From 0358d2ed9a64df9bf4d8e0b563e1fea27d73a335 Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Tue, 13 Feb 2024 14:17:07 +0100 Subject: [PATCH 1/4] wip Remve sig-verifier-js --- demos/web2-auth/index.html | 21 +++ demos/web2-auth/package.json | 18 +++ demos/web2-auth/src/auth.ts | 127 +++++++++++++++++ demos/web2-auth/src/index.ts | 28 ++++ demos/web2-auth/tsconfig.json | 7 + demos/web2-auth/vite.config.ts | 54 +++++++ package-lock.json | 253 ++++++++++++++++++++++++++++++++- package.json | 5 +- tsconfig.all.json | 1 + 9 files changed, 508 insertions(+), 6 deletions(-) create mode 100644 demos/web2-auth/index.html create mode 100644 demos/web2-auth/package.json create mode 100644 demos/web2-auth/src/auth.ts create mode 100644 demos/web2-auth/src/index.ts create mode 100644 demos/web2-auth/tsconfig.json create mode 100644 demos/web2-auth/vite.config.ts diff --git a/demos/web2-auth/index.html b/demos/web2-auth/index.html new file mode 100644 index 0000000000..fb7029e457 --- /dev/null +++ b/demos/web2-auth/index.html @@ -0,0 +1,21 @@ + + + + + + + Internet Identity + + + + +
+ +
+ + diff --git a/demos/web2-auth/package.json b/demos/web2-auth/package.json new file mode 100644 index 0000000000..8a33daeb97 --- /dev/null +++ b/demos/web2-auth/package.json @@ -0,0 +1,18 @@ +{ + "name": "web2-auth", + "version": "1.0.0", + "description": "", + "type": "module", + "dependencies": { + "@dfinity/sig-verifier-js": "*" + }, + "devDependencies": { + "vite": "*" + }, + "scripts": { + "check": "tsc --noEmit", + "vite": "NODE_OPTIONS='--experimental-wasm-modules' vite --config ./vite.config.ts" + }, + "author": "", + "license": "ISC" +} diff --git a/demos/web2-auth/src/auth.ts b/demos/web2-auth/src/auth.ts new file mode 100644 index 0000000000..68d056822f --- /dev/null +++ b/demos/web2-auth/src/auth.ts @@ -0,0 +1,127 @@ +// TODO: deduplicate + +import type { SignIdentity, Signature } from "@dfinity/agent"; +import { + Delegation, + DelegationChain, + DelegationIdentity, + SignedDelegation, +} from "@dfinity/identity"; +import { Principal } from "@dfinity/principal"; + +// The type of response from II as per the spec +interface AuthResponseSuccess { + kind: "authorize-client-success"; + delegations: { + delegation: { + pubkey: Uint8Array; + expiration: bigint; + targets?: Principal[]; + }; + signature: Uint8Array; + }[]; + userPublicKey: Uint8Array; +} + +// Perform a sign in to II using parameters set in this app +export const authWithII = async ({ + url: url_, + maxTimeToLive, + derivationOrigin, + sessionPublicKey, +}: { + url: string; + maxTimeToLive?: bigint; + derivationOrigin?: string; + sessionPublicKey: Uint8Array; +}): Promise => { + // Figure out the II URL to use + const iiUrl = new URL(url_); + iiUrl.hash = "#authorize"; + + // Open an II window and kickstart the flow + const win = window.open(iiUrl, "ii-window"); + if (win === null) { + throw new Error(`Could not open window for '${iiUrl}'`); + } + + // Wait for II to say it's ready + const evnt = await new Promise((resolve) => { + const readyHandler = (e: MessageEvent) => { + window.removeEventListener("message", readyHandler); + resolve(e); + }; + window.addEventListener("message", readyHandler); + }); + + if (evnt.data.kind !== "authorize-ready") { + throw new Error("Bad message from II window: " + JSON.stringify(evnt)); + } + + // Send the request to II + const request = { + kind: "authorize-client", + sessionPublicKey, + maxTimeToLive, + derivationOrigin, + }; + + win.postMessage(request, iiUrl.origin); + + // Wait for the II response and update the local state + const response = await new Promise((resolve) => { + const responseHandler = (e: MessageEvent) => { + window.removeEventListener("message", responseHandler); + win.close(); + resolve(e); + }; + window.addEventListener("message", responseHandler); + }); + + const message = response.data; + if (message.kind !== "authorize-client-success") { + throw new Error("Bad reply: " + JSON.stringify(message)); + } + + return message; +}; + +// Read delegations the delegations from the response +const identityFromResponse = ({ + sessionIdentity, + response, +}: { + sessionIdentity: SignIdentity; + response: AuthResponseSuccess; +}): DelegationIdentity => { + const delegations = response.delegations.map(extractDelegation); + + const delegationChain = DelegationChain.fromDelegations( + delegations, + response.userPublicKey.buffer + ); + + const identity = DelegationIdentity.fromDelegation( + sessionIdentity, + delegationChain + ); + + return identity; +}; + +// Infer the type of an array's elements +type ElementOf = Arr extends readonly (infer ElementOf)[] + ? ElementOf + : "argument is not an array"; + +export const extractDelegation = ( + signedDelegation: ElementOf +): SignedDelegation => ({ + delegation: new Delegation( + signedDelegation.delegation.pubkey, + signedDelegation.delegation.expiration, + signedDelegation.delegation.targets + ), + signature: signedDelegation.signature + .buffer as Signature /* brand type for agent-js */, +}); diff --git a/demos/web2-auth/src/index.ts b/demos/web2-auth/src/index.ts new file mode 100644 index 0000000000..ab2675cb4a --- /dev/null +++ b/demos/web2-auth/src/index.ts @@ -0,0 +1,28 @@ +import { authWithII } from "./auth"; + +const button = document.querySelector( + "[data-button-id=authenticate]" +)! as HTMLButtonElement; +const isAuthed = document.querySelector( + "[data-output-id=is-authed]" +)! as HTMLOutputElement; + +button.addEventListener("click", async () => { + const resp = await fetch("/challenge"); + const obj = await resp.json(); + const challenge = obj.challenge; + const delegationIdentity = await authWithII({ + url: "http://internet_identity.localhost:5173", + sessionPublicKey: Uint8Array.from(atob(challenge), (c) => c.charCodeAt(0)), + }); + console.log(delegationIdentity); + const data = { challenge, delegationIdentity }; + await fetch("/verify", { + method: "POST", + body: JSON.stringify(data, (_, v) => + typeof v === "bigint" ? v.toString() : v + ), + }); +}); + +button.disabled = false; diff --git a/demos/web2-auth/tsconfig.json b/demos/web2-auth/tsconfig.json new file mode 100644 index 0000000000..03ea203bfc --- /dev/null +++ b/demos/web2-auth/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "include": ["vite.config.ts", "./src"], + "compilerOptions": { + "composite": true + } +} diff --git a/demos/web2-auth/vite.config.ts b/demos/web2-auth/vite.config.ts new file mode 100644 index 0000000000..1aea78df28 --- /dev/null +++ b/demos/web2-auth/vite.config.ts @@ -0,0 +1,54 @@ +import { verifyIcSignature } from "@dfinity/sig-verifier-js/sig_verifier_js"; +import type { IncomingMessage, ServerResponse } from "http"; +import type { Plugin, ViteDevServer } from "vite"; +import { defineConfig } from "vite"; + +export async function createChallenge(): Promise { + // TODO: generate random challenge, store & add expiry + return "YSBjaGFsbGVuZ2UsIGkuZS4gYSBzdHJpbmcgb2YgYXQgbGVhc3QgMzIgYnl0ZXM="; +} + +export async function verifyChallenge() { + const res = await verifyIcSignature( + // TODO: use delegation + new Uint8Array(), + new Uint8Array(), + new Uint8Array(), + new Uint8Array() + ); + + // TODO: check result +} + +const handleChallenge = async (req: IncomingMessage, res: ServerResponse) => { + const challenge = await createChallenge(); + res.statusCode = 200; + res.end(JSON.stringify({ challenge })); +}; + +const handleVerify = async (req: IncomingMessage, res: ServerResponse) => { + res.statusCode = 200; + // TODO: verify challenge & add cookie here on success + res.end(JSON.stringify({ status: "ok" })); +}; + +const backendPlugin = (): Plugin => ({ + name: "backend-plugin", + configureServer(server: ViteDevServer) { + server.middlewares.use(async (req, res, next) => { + if (req.url === "/challenge") { + return handleChallenge(req, res); + } + if (req.url === "/verify") { + return handleVerify(req, res); + } + + return next(); + }); + }, +}); + +export default defineConfig({ + plugins: [backendPlugin()], + server: { port: 5178 }, +}); diff --git a/package-lock.json b/package-lock.json index dcd6872abd..4df5afd635 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,11 +10,12 @@ "license": "SEE LICENSE IN LICENSE.md", "workspaces": [ "src/vc-api", + "demos/web2-auth", "demos/test-app", "demos/vc_issuer", "src/vite-plugins", - "src/vc_util_js", - "src/sig-verifier-js" + "src/sig-verifier-js", + "src/vc_util_js" ], "dependencies": { "@dfinity/agent": "^1.1.1", @@ -63,6 +64,12 @@ "npm": ">=10.0.0 <11.0.0" } }, + "demos/sig-verifier-js": { + "version": "1.0.0", + "extraneous": true, + "license": "ISC", + "devDependencies": {} + }, "demos/test-app": { "name": "@dfinity/internet-identity-test-app", "dependencies": { @@ -107,6 +114,16 @@ "vite": "^4.5.3" } }, + "demos/web2-auth": { + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@dfinity/sig-verifier-js": "*" + }, + "devDependencies": { + "vite": "*" + } + }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "dev": true, @@ -1886,6 +1903,232 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@swc/core": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.1.tgz", + "integrity": "sha512-3y+Y8js+e7BbM16iND+6Rcs3jdiL28q3iVtYsCviYSSpP2uUVKkp5sJnCY4pg8AaVvyN7CGQHO7gLEZQ5ByozQ==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "@swc/counter": "^0.1.2", + "@swc/types": "^0.1.5" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.4.1", + "@swc/core-darwin-x64": "1.4.1", + "@swc/core-linux-arm-gnueabihf": "1.4.1", + "@swc/core-linux-arm64-gnu": "1.4.1", + "@swc/core-linux-arm64-musl": "1.4.1", + "@swc/core-linux-x64-gnu": "1.4.1", + "@swc/core-linux-x64-musl": "1.4.1", + "@swc/core-win32-arm64-msvc": "1.4.1", + "@swc/core-win32-ia32-msvc": "1.4.1", + "@swc/core-win32-x64-msvc": "1.4.1" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.1.tgz", + "integrity": "sha512-ePyfx0348UbR4DOAW24TedeJbafnzha8liXFGuQ4bdXtEVXhLfPngprrxKrAddCuv42F9aTxydlF6+adD3FBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.1.tgz", + "integrity": "sha512-eLf4JSe6VkCMdDowjM8XNC5rO+BrgfbluEzAVtKR8L2HacNYukieumN7EzpYCi0uF1BYwu1ku6tLyG2r0VcGxA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.1.tgz", + "integrity": "sha512-K8VtTLWMw+rkN/jDC9o/Q9SMmzdiHwYo2CfgkwVT29NsGccwmNhCQx6XoYiPKyKGIFKt4tdQnJHKUFzxUqQVtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.1.tgz", + "integrity": "sha512-0e8p4g0Bfkt8lkiWgcdiENH3RzkcqKtpRXIVNGOmVc0OBkvc2tpm2WTx/eoCnes2HpTT4CTtR3Zljj4knQ4Fvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.1.tgz", + "integrity": "sha512-b/vWGQo2n7lZVUnSQ7NBq3Qrj85GrAPPiRbpqaIGwOytiFSk8VULFihbEUwDe0rXgY4LDm8z8wkgADZcLnmdUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.1.tgz", + "integrity": "sha512-AFMQlvkKEdNi1Vk2GFTxxJzbICttBsOQaXa98kFTeWTnFFIyiIj2w7Sk8XRTEJ/AjF8ia8JPKb1zddBWr9+bEQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.1.tgz", + "integrity": "sha512-QX2MxIECX1gfvUVZY+jk528/oFkS9MAl76e3ZRvG2KC/aKlCQL0KSzcTSm13mOxkDKS30EaGRDRQWNukGpMeRg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.1.tgz", + "integrity": "sha512-OklkJYXXI/tntD2zaY8i3iZldpyDw5q+NAP3k9OlQ7wXXf37djRsHLV0NW4+ZNHBjE9xp2RsXJ0jlOJhfgGoFA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.1.tgz", + "integrity": "sha512-MBuc3/QfKX9FnLOU7iGN+6yHRTQaPQ9WskiC8s8JFiKQ+7I2p25tay2RplR9dIEEGgVAu6L7auv96LbNTh+FaA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.1.tgz", + "integrity": "sha512-lu4h4wFBb/bOK6N2MuZwg7TrEpwYXgpQf5R7ObNSXL65BwZ9BG8XRzD+dLJmALu8l5N08rP/TrpoKRoGT4WSxw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/@szmarczak/http-timer": { "version": "5.0.1", "dev": true, @@ -13770,6 +14013,10 @@ "node": ">= 8" } }, + "node_modules/web2-auth": { + "resolved": "demos/web2-auth", + "link": true + }, "node_modules/webcrypto-core": { "version": "1.7.7", "license": "MIT", @@ -14659,7 +14906,6 @@ }, "src/sig-verifier-js": { "name": "@dfinity/sig-verifier-js", - "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE.md", "devDependencies": { "@dfinity/internet-identity-vite-plugins": "*", @@ -14671,7 +14917,6 @@ }, "src/vc_util_js": { "name": "@dfinity/vc_util_js", - "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE.md", "devDependencies": { "@dfinity/internet-identity-vite-plugins": "*", diff --git a/package.json b/package.json index 137f25cb6c..bda50a7617 100644 --- a/package.json +++ b/package.json @@ -81,10 +81,11 @@ }, "workspaces": [ "src/vc-api", + "demos/web2-auth", "demos/test-app", "demos/vc_issuer", "src/vite-plugins", - "src/vc_util_js", - "src/sig-verifier-js" + "src/sig-verifier-js", + "src/vc_util_js" ] } diff --git a/tsconfig.all.json b/tsconfig.all.json index d39d7af8e7..17a9bf0bc2 100644 --- a/tsconfig.all.json +++ b/tsconfig.all.json @@ -5,6 +5,7 @@ "references": [ { "path": "./src/vc-api" }, { "path": "./src/sig-verifier-js" }, + { "path": "./demos/web2-auth" }, { "path": "./demos/test-app" }, { "path": "./demos/vc_issuer" }, { "path": "./src/vite-plugins" } From 470c9fd0f103d8cfcdd2d93f536c70610924e150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lloren=C3=A7?= Date: Wed, 28 Feb 2024 11:35:18 +0100 Subject: [PATCH 2/4] LM: Changes package-lock --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index 4df5afd635..39685f4919 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14906,6 +14906,7 @@ }, "src/sig-verifier-js": { "name": "@dfinity/sig-verifier-js", + "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE.md", "devDependencies": { "@dfinity/internet-identity-vite-plugins": "*", From 3c82dfbd705c147efa60f5fcd7402e46c46d833b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lloren=C3=A7?= Date: Wed, 28 Feb 2024 14:45:35 +0100 Subject: [PATCH 3/4] LM: Verifying signature successfully --- demos/web2-auth/src/index.ts | 36 ++++++++--- demos/web2-auth/vite.config.ts | 105 ++++++++++++++++++++++++++++----- 2 files changed, 120 insertions(+), 21 deletions(-) diff --git a/demos/web2-auth/src/index.ts b/demos/web2-auth/src/index.ts index ab2675cb4a..75074010cc 100644 --- a/demos/web2-auth/src/index.ts +++ b/demos/web2-auth/src/index.ts @@ -7,21 +7,43 @@ const isAuthed = document.querySelector( "[data-output-id=is-authed]" )! as HTMLOutputElement; +export const uint8ArrayToHexString = (bytes: Uint8Array | number[]) => { + if (!(bytes instanceof Uint8Array)) { + bytes = Uint8Array.from(bytes); + } + return bytes.reduce( + (str, byte) => str + byte.toString(16).padStart(2, "0"), + "" + ); +}; + button.addEventListener("click", async () => { const resp = await fetch("/challenge"); - const obj = await resp.json(); + const obj: { challenge: string } = await resp.json(); const challenge = obj.challenge; const delegationIdentity = await authWithII({ - url: "http://internet_identity.localhost:5173", - sessionPublicKey: Uint8Array.from(atob(challenge), (c) => c.charCodeAt(0)), + // The url needs to be aligned with the root key in the backend + // url: "http://internet_identity.localhost:5173", + url: "https://jqajs-xiaaa-aaaad-aab5q-cai.ic0.app/", + sessionPublicKey: new Uint8Array(Buffer.from(challenge, "base64")), }); - console.log(delegationIdentity); const data = { challenge, delegationIdentity }; await fetch("/verify", { method: "POST", - body: JSON.stringify(data, (_, v) => - typeof v === "bigint" ? v.toString() : v - ), + body: JSON.stringify(data, (_, v) => { + if (typeof v === "bigint") { + // We need to expiration date to be hex string. + return v.toString(16); + } + if (v instanceof Uint8Array) { + // We need the keys to be hex strings. + return uint8ArrayToHexString(v); + } + return v; + }), + headers: new Headers({ + "Content-Type": "application/json", + }), }); }); diff --git a/demos/web2-auth/vite.config.ts b/demos/web2-auth/vite.config.ts index 1aea78df28..9dc5f06a28 100644 --- a/demos/web2-auth/vite.config.ts +++ b/demos/web2-auth/vite.config.ts @@ -1,5 +1,5 @@ -import { verifyIcSignature } from "@dfinity/sig-verifier-js/sig_verifier_js"; -import type { IncomingMessage, ServerResponse } from "http"; +import { validateDelegationAndGetPrincipal } from "@dfinity/sig-verifier-js/sig_verifier_js"; +import { IncomingMessage, ServerResponse } from "http"; import type { Plugin, ViteDevServer } from "vite"; import { defineConfig } from "vite"; @@ -8,16 +8,55 @@ export async function createChallenge(): Promise { return "YSBjaGFsbGVuZ2UsIGkuZS4gYSBzdHJpbmcgb2YgYXQgbGVhc3QgMzIgYnl0ZXM="; } -export async function verifyChallenge() { - const res = await verifyIcSignature( - // TODO: use delegation - new Uint8Array(), - new Uint8Array(), - new Uint8Array(), - new Uint8Array() - ); +type Delegation = { + delegation: { + pubkey: string; + expiration: string; + }; + signature: string; +}; + +type VerifyData = { + challenge: string; + authMethod: string; + delegationIdentity: { + kind: string; + delegations: Delegation[]; + userPublicKey: string; + }; +}; - // TODO: check result +const ROOT_PUBLIC_KEY_RAW = new Uint8Array([ + 0x81, 0x4c, 0x0e, 0x6e, 0xc7, 0x1f, 0xab, 0x58, 0x3b, 0x08, 0xbd, 0x81, 0x37, + 0x3c, 0x25, 0x5c, 0x3c, 0x37, 0x1b, 0x2e, 0x84, 0x86, 0x3c, 0x98, 0xa4, 0xf1, + 0xe0, 0x8b, 0x74, 0x23, 0x5d, 0x14, 0xfb, 0x5d, 0x9c, 0x0c, 0xd5, 0x46, 0xd9, + 0x68, 0x5f, 0x91, 0x3a, 0x0c, 0x0b, 0x2c, 0xc5, 0x34, 0x15, 0x83, 0xbf, 0x4b, + 0x43, 0x92, 0xe4, 0x67, 0xdb, 0x96, 0xd6, 0x5b, 0x9b, 0xb4, 0xcb, 0x71, 0x71, + 0x12, 0xf8, 0x47, 0x2e, 0x0d, 0x5a, 0x4d, 0x14, 0x50, 0x5f, 0xfd, 0x74, 0x84, + 0xb0, 0x12, 0x91, 0x09, 0x1c, 0x5f, 0x87, 0xb9, 0x88, 0x83, 0x46, 0x3f, 0x98, + 0x09, 0x1a, 0x0b, 0xaa, 0xae, +]); + +export function verifyChallenge(data: VerifyData): string | undefined { + try { + const delegationChain = { + delegations: data.delegationIdentity.delegations, + publicKey: data.delegationIdentity.userPublicKey, + }; + const currentTimeNanoSeconds = process.hrtime.bigint(); + const res = validateDelegationAndGetPrincipal( + Uint8Array.from(Buffer.from(data.challenge, "base64")), + JSON.stringify(delegationChain), + currentTimeNanoSeconds, + "jqajs-xiaaa-aaaad-aab5q-cai", + ROOT_PUBLIC_KEY_RAW + ); + + return res; + } catch (e) { + console.error(e); + return undefined; + } } const handleChallenge = async (req: IncomingMessage, res: ServerResponse) => { @@ -26,12 +65,50 @@ const handleChallenge = async (req: IncomingMessage, res: ServerResponse) => { res.end(JSON.stringify({ challenge })); }; -const handleVerify = async (req: IncomingMessage, res: ServerResponse) => { +const handleVerify = async (req: RequestWithBody, res: ServerResponse) => { res.statusCode = 200; - // TODO: verify challenge & add cookie here on success + const principal = verifyChallenge(req.body); + console.log("principal", principal); + // TODO: add cookie here on success res.end(JSON.stringify({ status: "ok" })); }; +// Extend IncomingMessage to include body +interface RequestWithBody extends IncomingMessage { + body?: any; +} + +const bodyParserPlugin = (): Plugin => ({ + name: "body-parser", + configureServer(server) { + server.middlewares.use( + async (req: RequestWithBody, res: ServerResponse, next) => { + // Only parse JSON bodies and only for POST requests + if ( + req.method === "POST" && + req.headers["content-type"] === "application/json" + ) { + let body = ""; + req.on("data", (chunk) => { + body += chunk.toString(); // convert Buffer to string + }); + req.on("end", () => { + try { + req.body = JSON.parse(body); + } catch (e: unknown) { + res.statusCode = 400; + return res.end("Error parsing JSON body"); + } + next(); + }); + } else { + next(); + } + } + ); + }, +}); + const backendPlugin = (): Plugin => ({ name: "backend-plugin", configureServer(server: ViteDevServer) { @@ -49,6 +126,6 @@ const backendPlugin = (): Plugin => ({ }); export default defineConfig({ - plugins: [backendPlugin()], + plugins: [bodyParserPlugin(), backendPlugin()], server: { port: 5178 }, }); From 6afc925b55ffb1aad53a6eb3f5ec0e9df95241eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lloren=C3=A7?= Date: Tue, 23 Apr 2024 17:19:25 +0200 Subject: [PATCH 4/4] Revert workspace order change --- package-lock.json | 5 ++--- package.json | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 39685f4919..fe078578d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,8 +14,8 @@ "demos/test-app", "demos/vc_issuer", "src/vite-plugins", - "src/sig-verifier-js", - "src/vc_util_js" + "src/vc_util_js", + "src/sig-verifier-js" ], "dependencies": { "@dfinity/agent": "^1.1.1", @@ -14906,7 +14906,6 @@ }, "src/sig-verifier-js": { "name": "@dfinity/sig-verifier-js", - "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE.md", "devDependencies": { "@dfinity/internet-identity-vite-plugins": "*", diff --git a/package.json b/package.json index bda50a7617..0855589da7 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "demos/test-app", "demos/vc_issuer", "src/vite-plugins", - "src/sig-verifier-js", - "src/vc_util_js" + "src/vc_util_js", + "src/sig-verifier-js" ] }