From 6fa0d49ce166a5ecd8c48e527649e08df8373205 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Fri, 21 Jul 2023 10:33:44 -0400 Subject: [PATCH] refactor: port over the encrypted key exchange and set key from extension --- npm-shrinkwrap.json | 9 +++ package.json | 1 + src/index.ts | 3 + src/messages.ts | 76 +++++++++++++++++++++++ src/messages/exchangeCommunicationKeys.ts | 12 ++++ src/messages/setLoginKey.ts | 26 ++++++++ 6 files changed, 127 insertions(+) create mode 100644 src/messages.ts create mode 100644 src/messages/exchangeCommunicationKeys.ts create mode 100644 src/messages/setLoginKey.ts diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 2bda66e..4196662 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -9,6 +9,7 @@ "version": "0.1.0-develop.1", "dependencies": { "@lumeweb/libweb": "0.2.0-develop.27", + "@noble/ciphers": "^0.1.4", "binconv": "^0.2.0" }, "devDependencies": { @@ -1731,6 +1732,14 @@ "vite-plugin-optimizer": "^1.4.2" } }, + "node_modules/@noble/ciphers": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.1.4.tgz", + "integrity": "sha512-d3ZR8vGSpy3v/nllS+bD/OMN5UZqusWiQqkyj7AwzTnhXFH72pF5oB4Ach6DQ50g5kXxC28LdaYBEpsyv9KOUQ==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@noble/curves": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", diff --git a/package.json b/package.json index 4f6e06b..95b4795 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@lumeweb/libweb": "0.2.0-develop.27", + "@noble/ciphers": "^0.1.4", "binconv": "^0.2.0" } } diff --git a/src/index.ts b/src/index.ts index 27a9e4a..8d05a21 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import { boot } from "./kernel.js"; +import { handleIncomingMessage } from "./messages.js"; document.title = "Hosted Lume Kernel"; let header = document.createElement("h1"); @@ -6,4 +7,6 @@ header.textContent = "Something went wrong! You should not be visiting this page, this page should only be accessed via an invisible iframe."; document.body.appendChild(header); +window.addEventListener("message", handleIncomingMessage); + boot(); diff --git a/src/messages.ts b/src/messages.ts new file mode 100644 index 0000000..a91edc7 --- /dev/null +++ b/src/messages.ts @@ -0,0 +1,76 @@ +import exchangeCommunicationKeys from "./messages/exchangeCommunicationKeys.js"; +import setLoginKey from "./messages/setLoginKey.js"; + +const kernelMessageHandlers = { + exchangeCommunicationKeys, + setLoginKey, +}; + +export async function handleIncomingMessage(event: MessageEvent) { + if (event.source === null) { + return; + } + if (event.source === window) { + return; + } + + if (!("nonce" in event.data)) { + (event.source as WindowProxy).postMessage( + { + nonce: "N/A", + method: "response", + err: "message sent to kernel with no nonce", + }, + event.origin, + ); + return; + } + + if (!("method" in event.data)) { + (event.source as WindowProxy).postMessage( + { + nonce: event.data.nonce, + method: "response", + err: "message sent to kernel with no method", + }, + event.origin, + ); + return; + } + + if (event.data.method in kernelMessageHandlers) { + let response; + + try { + response = await kernelMessageHandlers[event.data.method]( + event.data.data, + ); + } catch (e: any) { + response = { err: (e as Error).message }; + } + + (event.source as WindowProxy).postMessage( + { + nonce: event.data.nonce, + data: response, + }, + event.origin, + ); + return; + } + + if (["moduleCall", "response"].includes(event.data.method)) { + return; + } + + (event.source as WindowProxy).postMessage( + { + nonce: event.data.nonce, + method: "response", + err: + "unrecognized method (user may need to log in): " + event.data.method, + }, + event.origin, + ); + return; +} diff --git a/src/messages/exchangeCommunicationKeys.ts b/src/messages/exchangeCommunicationKeys.ts new file mode 100644 index 0000000..ad914ae --- /dev/null +++ b/src/messages/exchangeCommunicationKeys.ts @@ -0,0 +1,12 @@ +import { bytesToHex, hexToBytes } from "@lumeweb/libweb"; +import { + getCommunicationPubKey, + setFrontendCommunicationPubkey, +} from "../vars.js"; +import { log } from "../util.js"; + +export default function (data: any) { + setFrontendCommunicationPubkey(hexToBytes(data)); + + return bytesToHex(getCommunicationPubKey()); +} diff --git a/src/messages/setLoginKey.ts b/src/messages/setLoginKey.ts new file mode 100644 index 0000000..d66bcef --- /dev/null +++ b/src/messages/setLoginKey.ts @@ -0,0 +1,26 @@ +import { secretbox } from "@noble/ciphers/salsa"; +import { x25519 } from "@noble/curves/ed25519"; +import { + getCommunicationKey, + getFrontendCommunicationPubkey, + setLoginComplete, +} from "../vars.js"; +import { saveUserKey } from "../storage.js"; +import { hexToBytes } from "@lumeweb/libweb"; + +export default function (data: any) { + const box = secretbox( + x25519.getSharedSecret( + getCommunicationKey(), + getFrontendCommunicationPubkey(), + ), + hexToBytes(data.nonce), + ); + const decryptedData = box.open(hexToBytes(data.data)); + + setLoginComplete(false); + + saveUserKey(decryptedData); + + return true; +}