diff options
author | Cirakg <cirakg@cirakg.xyz> | 2025-04-13 17:47:44 +0200 |
---|---|---|
committer | Cirakg <cirakg@cirakg.xyz> | 2025-04-13 17:47:44 +0200 |
commit | 2c9a02ab93d4d3c7011ed9ea90c136b8fdad1531 (patch) | |
tree | 2f6d12695a61ead4cf732a252d01e4b1d3cbf5c8 /index.html | |
parent | f2b7cd2a2c3bb598ba474ab8322f7d55434ac766 (diff) |
feat: Allowed paste upload.
Diffstat (limited to 'index.html')
-rw-r--r-- | index.html | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/index.html b/index.html new file mode 100644 index 0000000..f4fe7a3 --- /dev/null +++ b/index.html @@ -0,0 +1,194 @@ +<!DOCTYPE html> +<html lang="en" data-theme="dark"> + +<head> + <meta charset="UTF-8"> + <meta name="description" content="AES-256 Encryption Example"> + <title>Secure Paste</title> + <link rel="icon" href="./favicon.svg" type="image/svg+xml"> + <link rel="stylesheet" href="./pico.min.css"> +</head> + +<body> + <main class="container"> + <h1>paste-cgi</h1> + + <form id="cryptoForm"> + <label for="title">Title</label> + <input type="text" id="title" placeholder="Enter a title" required /> + + <label for="plaintext">Paste</label> + <textarea id="plaintext" rows="5" placeholder="Enter your paste" required></textarea> + + <label for="pasteType">Type</label> + <select id="pasteType" onchange="togglePasteType()"> + <option value="plain">Plain</option> + <option value="password">Password</option> + </select> + + <div id="passwordField" style="display: none;"> + <label for="password">Password</label> + <input type="password" id="password" placeholder="Enter your password" /> + </div> + + <label for="expiration">Expiration</label> + <select id="expiration"> + <option value="never">Never</option> + <option value="burn_after_read">Burn after read</option> + <option value="10_minutes">10 minutes</option> + <option value="1_hour">1 hour</option> + <option value="1_day">1 Day</option> + <option value="1_week">1 Week</option> + <option value="2_weeks">2 Weeks</option> + <option value="1_month">1 Month</option> + <option value="6_months">6 Months</option> + <option value="1_year">1 Year</option> + </select> + + <button type="button" id="encryptBtn" onclick="handlePaste()">Paste</button> + </form> + + <div id="pasteUrlSection" style="display: none;"> + <h3>Paste Url:</h3> + <input id="pasteUrl" readonly></textarea> + <button type="button" onclick="copyPaste()">Copy</button> + </div> + </main> + + <script> + const pasteTypeConstant = "pasteType"; + const passwordFieldConstant = "passwordField"; + const passwordTypeConstant = "password"; + const plainTypeConstant = "plain"; + const titleConstant = "title"; + const expirationConstant = "expiration"; + const plaintextConstant = "plaintext"; + const pasteUrlConstant = "pasteUrl" + const pasteUrlSectionConstant = "pasteUrlSection" + + function copyPaste(){ + var copyText = document.getElementById(pasteUrlConstant); + + copyText.select(); + copyText.setSelectionRange(0, 99999); + + navigator.clipboard.writeText(copyText.value); + } + + function togglePasteType() { + const passwordType = document.getElementById(pasteTypeConstant).value; + const passwordField = document.getElementById(passwordFieldConstant); + if (passwordType === passwordTypeConstant) { + passwordField.style.display = 'block'; + } else { + passwordField.style.display = 'none'; + } + } + + async function deriveKey(password, salt) { + let encodedPassword = new TextEncoder().encode(password); + let baseKey = await window.crypto.subtle.importKey( + "raw", + encodedPassword, + { name: "PBKDF2" }, + false, + ["deriveKey"], + ); + + let derivedKey = await window.crypto.subtle.deriveKey( + { + name: "PBKDF2", + salt: salt, + iterations: 600000, + hash: "SHA-256", + }, + baseKey, + { name: "AES-GCM", length: 256 }, + true, + ["encrypt", "decrypt"], + ); + + return derivedKey; + } + + async function encryptData(data, password) { + let salt = window.crypto.getRandomValues(new Uint8Array(16)); + let iv = window.crypto.getRandomValues(new Uint8Array(12)); + let key = await deriveKey(password, salt); + let encodedData = new TextEncoder().encode(data); + + let encryptedContent = await window.crypto.subtle.encrypt( + { + name: "AES-GCM", + iv: iv, + tagLength: 128, + }, + key, + encodedData, + ); + + let ciphertext = encryptedContent.slice( + 0, + encryptedContent.byteLength - 16, + ); + let authTag = encryptedContent.slice(encryptedContent.byteLength - 16); + + return { + ciphertext: new Uint8Array(ciphertext), + iv: iv, + authTag: new Uint8Array(authTag), + salt: salt, + }; + } + + async function handlePaste() { + let type = document.getElementById(pasteTypeConstant).value; + let title = document.getElementById(titleConstant).value; + let expiration = document.getElementById(expirationConstant).value; + let plaintext = document.getElementById(plaintextConstant).value; + let password = document.getElementById(passwordTypeConstant).value; + + let pasted_text = "" + if (type == plainTypeConstant) { + if (!plaintext || !title) return alert("Enter title and paste."); + + pasted_text = plaintext + } + else { + if (!plaintext || !password || !title) return alert("Enter title, paste and password."); + + let encrypted = await encryptData(plaintext, password); + pasted_text = btoa(JSON.stringify(encrypted)) + } + + let currentPath = window.location.origin; + + try { + let response = await fetch(currentPath + "/submit", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + type: type, + title: title, + expiration: expiration, + pasted_text: pasted_text + }), + }); + + if (response.ok) { + let jsonResponse = await response.json(); + document.getElementById(pasteUrlConstant).value = currentPath + "/get?id=" + jsonResponse.id; + document.getElementById(pasteUrlSectionConstant).style.display = 'block'; + } else { + console.error("Failed to submit data. Status:", response.status); + } + } catch (error) { + console.error("Error making the POST request:", error); + } + } + </script> +</body> + +</html>
\ No newline at end of file |