sure/src/routes/send.ts

112 lines
3.2 KiB
TypeScript

import {
deriveSharedSecret,
encrypt,
retrieveOrGenerateKeyPair,
} from "../utils/crypto";
const ENCRYPTED_URL_INPUT_ID = "encrypted-url";
const MESSAGE_INPUT_ID = "message";
const ENCRYPT_BUTTON_ID = "encrypt";
const REQUEST_PUBLIC_KEY = "requestPublicKey";
const TEMPLATE = `
<details open>
<summary>How To Use:</summary>
<ol>
<li>Enter the information you want to send back to the original requester into the text input below.</li>
<li>Click on 'Generate Response'. This will create a new URL that contains your encrypted message.</li>
<li>Send the newly generated URL back to the original requester. Only their browser will be able to decrypt the message.</li>
</ol>
</details>
<form>
<input
type="text"
name="message"
id="${MESSAGE_INPUT_ID}"
placeholder="Enter your message here..."
aria-label="Message to Encrypt"
required
/>
<input
id="${ENCRYPT_BUTTON_ID}"
type="submit"
value="Generate Response"
aria-label="Generate Response"
/>
<input
type="text"
name="encrypted-url"
id="${ENCRYPTED_URL_INPUT_ID}"
placeholder="URL with your encrypted response will appear here..."
aria-label="Encrypted URL"
/>
</form>
`;
export async function setupSendPage(element: HTMLElement, key: string) {
element.innerHTML = TEMPLATE;
localStorage.setItem(REQUEST_PUBLIC_KEY, key);
// Add an event listener to the "Encrypt" button
const encryptButton = document.getElementById(
ENCRYPT_BUTTON_ID
) as HTMLButtonElement;
encryptButton.addEventListener("click", encryptData);
}
async function encryptData(event: Event) {
event.preventDefault();
const key = localStorage.getItem(REQUEST_PUBLIC_KEY)!;
// Parse the 'p' parameter to get publicA
const publicAJwk = JSON.parse(atob(key));
// Import publicA as a CryptoKey
const publicA = await window.crypto.subtle.importKey(
"jwk",
publicAJwk,
{
name: "ECDH",
namedCurve: "P-256",
},
false,
[]
);
const keyPairB = await retrieveOrGenerateKeyPair();
// Retrieve the message input
const messageInput = document.getElementById(
MESSAGE_INPUT_ID
) as HTMLInputElement;
// Derive the AES key from your private key and the recipient's public key
const aesKey = await deriveSharedSecret(keyPairB.privateKey, publicA);
// Encrypt the message input value using the AES key
const { encryptedData, iv } = await encrypt(aesKey, messageInput.value);
// Update the encrypted URL input with the encrypted message
const encryptedUrlInput = document.getElementById(
ENCRYPTED_URL_INPUT_ID
) as HTMLInputElement;
const ecdhPublicJwk = await window.crypto.subtle.exportKey(
"jwk",
keyPairB.publicKey
);
const url = new URL(window.location.toString());
url.search = "";
url.hash = `p=${encodeURIComponent(
btoa(JSON.stringify(ecdhPublicJwk))
)}&iv=${encodeURIComponent(
btoa(String.fromCharCode.apply(null, Array.from(iv)))
)}&m=${encodeURIComponent(
btoa(
String.fromCharCode.apply(null, Array.from(new Uint8Array(encryptedData)))
)
)}`;
encryptedUrlInput.value = url.toString();
}