client-index.ts
| 1 | async function encrypt(content: Uint8Array, password: string): Promise<ArrayBuffer> { |
| 2 | const iv = crypto.getRandomValues(new Uint8Array(16)) |
| 3 | const salt = crypto.getRandomValues(new Uint8Array(16)) |
| 4 | const keyMaterial = await crypto.subtle.importKey( |
| 5 | "raw", |
| 6 | new TextEncoder().encode(password), |
| 7 | { name: "PBKDF2" }, |
| 8 | false, |
| 9 | ["deriveBits", "deriveKey"] |
| 10 | ) |
| 11 | const key = await crypto.subtle.deriveKey( |
| 12 | { |
| 13 | name: "PBKDF2", |
| 14 | salt: salt, |
| 15 | iterations: 100000, |
| 16 | hash: "SHA-512" |
| 17 | }, |
| 18 | keyMaterial, |
| 19 | { name: "AES-CBC", length: 256 }, |
| 20 | false, |
| 21 | ["encrypt"] |
| 22 | ) |
| 23 | const encryptedContent = await crypto.subtle.encrypt( |
| 24 | { name: "AES-CBC", iv: iv }, |
| 25 | key, |
| 26 | content |
| 27 | ) |
| 28 | return new Uint8Array([...salt, ...iv, ...new Uint8Array(encryptedContent)]).buffer |
| 29 | } |
| 30 | |
| 31 | async function uploadFile() { |
| 32 | (document.getElementById("upload-dialog") as HTMLDialogElement | null)?.showModal() |
| 33 | const passwordInput = document.getElementById("password") as HTMLInputElement | null |
| 34 | const fileInput = document.getElementById("file") as HTMLInputElement | null |
| 35 | const filenameInput = document.getElementById("filename") as HTMLInputElement | null |
| 36 | const encryptedInput = document.getElementById("encrypted") as HTMLInputElement | null |
| 37 | const form = document.getElementById("uploadForm") as HTMLFormElement | null |
| 38 | |
| 39 | if (!passwordInput || !fileInput || !filenameInput || !encryptedInput || !form) { |
| 40 | console.error("Missing required elements.") |
| 41 | console.error(passwordInput, fileInput, filenameInput, encryptedInput, form) |
| 42 | return |
| 43 | } |
| 44 | |
| 45 | const password = passwordInput.value; |
| 46 | if (!password) { |
| 47 | form.submit() |
| 48 | return |
| 49 | } |
| 50 | |
| 51 | const file = fileInput.files?.[0]; |
| 52 | if (!file) { |
| 53 | return |
| 54 | } |
| 55 | |
| 56 | const content = await file.arrayBuffer() |
| 57 | const encryptedContent = await encrypt(new Uint8Array(content), password) |
| 58 | |
| 59 | const myFile = new File([encryptedContent], file.name) |
| 60 | const dataTransfer = new DataTransfer() |
| 61 | dataTransfer.items.add(myFile) |
| 62 | |
| 63 | fileInput.files = dataTransfer.files |
| 64 | encryptedInput.checked = true |
| 65 | console.log("encryption done") |
| 66 | form.submit() |
| 67 | } |
| 68 | |
| 69 | const jsguards = document.getElementsByClassName("jsguard") |
| 70 | for (let i = 0; i < jsguards.length; i++) { |
| 71 | jsguards[i].remove() |
| 72 | } |
| 73 | |
| 74 | (document.getElementById("uploadForm") as HTMLFormElement | null)?.reset(); |
| 75 | window.uploadFile = uploadFile |
| 76 | //disable bfcache, otherwise dialog will stay open when navigating back |
| 77 | window.addEventListener('unload', function () { }); |
| 78 | window.addEventListener('beforeunload', function () { }); |