diff --git a/docs/.astro/types.d.ts b/docs/.astro/types.d.ts index 83eef58..c268a41 100644 --- a/docs/.astro/types.d.ts +++ b/docs/.astro/types.d.ts @@ -141,217 +141,224 @@ declare module 'astro:content' { slug: "architecture"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "clients/android/answer.mdx": { id: "clients/android/answer.mdx"; slug: "clients/android/answer"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "clients/android/authentication.mdx": { id: "clients/android/authentication.mdx"; slug: "clients/android/authentication"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "clients/android/introduction.mdx": { id: "clients/android/introduction.mdx"; slug: "clients/android/introduction"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "clients/android/offer.mdx": { id: "clients/android/offer.mdx"; slug: "clients/android/offer"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; -"clients/android/provider-service/create-passkey.md": { - id: "clients/android/provider-service/create-passkey.md"; - slug: "clients/android/provider-service/create-passkey"; +"clients/android/provider-service/authenticate.md": { + id: "clients/android/provider-service/authenticate.md"; + slug: "clients/android/provider-service/authenticate"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> -} & { render(): Render[".md"] }; -"clients/android/provider-service/get-passkey.md": { - id: "clients/android/provider-service/get-passkey.md"; - slug: "clients/android/provider-service/get-passkey"; - body: string; - collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "clients/android/provider-service/introduction.mdx": { id: "clients/android/provider-service/introduction.mdx"; slug: "clients/android/provider-service/introduction"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; +"clients/android/provider-service/register.md": { + id: "clients/android/provider-service/register.md"; + slug: "clients/android/provider-service/register"; + body: string; + collection: "docs"; + data: any +} & { render(): Render[".md"] }; "clients/android/registration.mdx": { id: "clients/android/registration.mdx"; slug: "clients/android/registration"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "clients/browser/answer.mdx": { id: "clients/browser/answer.mdx"; slug: "clients/browser/answer"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "clients/browser/authentication.md": { id: "clients/browser/authentication.md"; slug: "clients/browser/authentication"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "clients/browser/example.md": { id: "clients/browser/example.md"; slug: "clients/browser/example"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "clients/browser/introduction.mdx": { id: "clients/browser/introduction.mdx"; slug: "clients/browser/introduction"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "clients/browser/offer.mdx": { id: "clients/browser/offer.mdx"; slug: "clients/browser/offer"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "clients/browser/registration.mdx": { id: "clients/browser/registration.mdx"; slug: "clients/browser/registration"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "guides/Passkey/authentication.mdx": { id: "guides/Passkey/authentication.mdx"; slug: "guides/passkey/authentication"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any +} & { render(): Render[".mdx"] }; +"guides/Passkey/extension.mdx": { + id: "guides/Passkey/extension.mdx"; + slug: "guides/passkey/extension"; + body: string; + collection: "docs"; + data: any } & { render(): Render[".mdx"] }; "guides/Passkey/registration.mdx": { id: "guides/Passkey/registration.mdx"; slug: "guides/passkey/registration"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "guides/Peer to Peer/answer.mdx": { id: "guides/Peer to Peer/answer.mdx"; slug: "guides/peer-to-peer/answer"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "guides/Peer to Peer/exchange.mdx": { id: "guides/Peer to Peer/exchange.mdx"; slug: "guides/peer-to-peer/exchange"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "guides/Peer to Peer/offer.mdx": { id: "guides/Peer to Peer/offer.mdx"; slug: "guides/peer-to-peer/offer"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "guides/components.mdx": { id: "guides/components.mdx"; slug: "guides/components"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; -"guides/concepts.md": { - id: "guides/concepts.md"; +"guides/concepts.mdx": { + id: "guides/concepts.mdx"; slug: "guides/concepts"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> -} & { render(): Render[".md"] }; + data: any +} & { render(): Render[".mdx"] }; "guides/getting-started.mdx": { id: "guides/getting-started.mdx"; slug: "guides/getting-started"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; -"guides/qr-code.md": { - id: "guides/qr-code.md"; - slug: "guides/qr-code"; +"guides/linking.mdx": { + id: "guides/linking.mdx"; + slug: "guides/linking"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> -} & { render(): Render[".md"] }; + data: any +} & { render(): Render[".mdx"] }; "introduction.md": { id: "introduction.md"; slug: "introduction"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "server/environment-variables.md": { id: "server/environment-variables.md"; slug: "server/environment-variables"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "server/integrations.md": { id: "server/integrations.md"; slug: "server/integrations"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "server/introduction.md": { id: "server/introduction.md"; slug: "server/introduction"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "server/running-locally.md": { id: "server/running-locally.md"; slug: "server/running-locally"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "server/tmp.md": { id: "server/tmp.md"; slug: "server/tmp"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "server/tmp2.md": { id: "server/tmp2.md"; slug: "server/tmp2"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; }; @@ -363,5 +370,5 @@ declare module 'astro:content' { type AnyEntryMap = ContentEntryMap & DataEntryMap; - export type ContentConfig = typeof import("../src/content/config.js"); + export type ContentConfig = never; } diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 9c593d0..389d998 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -7,8 +7,15 @@ import starlightOpenAPI, { openAPISidebarGroups } from "starlight-openapi"; import react from "@astrojs/react"; import mdx from "@astrojs/mdx"; +import basicSsl from '@vitejs/plugin-basic-ssl' // https://astro.build/config export default defineConfig({ + vite: { + plugins: [basicSsl()], + server: { + https: true, + }, + }, site: 'https://liquidauth.com', markdown: { rehypePlugins: [rehypeMermaid] @@ -22,6 +29,17 @@ export default defineConfig({ logo: { src: "./public/logo.svg" }, + head:[ + { + tag: 'script', + attrs: { + // Tweaks to the script URL or attributes can be made here. + src: 'https://unpkg.com/htmx.org@1.9.6', + integrity: "sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni", + crossorigin: "anonymous", + }, + }, + ], editLink: { baseUrl: 'https://github.com/algorandfoundation/liquid-auth/edit/develop/docs/', }, diff --git a/docs/package-lock.json b/docs/package-lock.json index 5ee10ef..08561c0 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -8,15 +8,17 @@ "name": "test-starlight", "version": "0.0.1", "dependencies": { + "@algorandfoundation/liquid-client": "github:algorandfoundation/liquid-auth-js", "@astrojs/check": "^0.5.10", "@astrojs/mdx": "^3.1.2", - "@astrojs/react": "^3.6.0", + "@astrojs/react": "^3.6.2", "@astrojs/starlight": "^0.24.2", "@astrojs/tailwind": "^5.1.0", "@fontsource/poppins": "^5.0.13", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "astro": "^4.3.5", + "qr-code-styling": "github:awesome-algorand/qr-code-styling", "react": "^18.3.1", "react-dom": "^18.3.1", "rehype-mermaid": "^2.1.0", @@ -29,10 +31,37 @@ "typescript": "^5.4.5" }, "devDependencies": { + "@vitejs/plugin-basic-ssl": "^1.1.0", "socket.io-client": "^4.7.5", "tweetnacl": "^1.0.3" } }, + "node_modules/@algorandfoundation/liquid-client": { + "version": "0.0.1", + "resolved": "git+ssh://git@github.com/algorandfoundation/liquid-auth-js.git#b787150ff490f7a4c2e28864821c2be76e31d294", + "hasInstallScript": true, + "license": "AGPL-3.0", + "dependencies": { + "canvas": "^2.11.2", + "eventemitter3": "^5.0.1", + "qr-code-styling": "*", + "socket.io-client": "^4.7.5", + "tweetnacl": "^1.0.3", + "uuid": "^10.0.0" + } + }, + "node_modules/@algorandfoundation/liquid-client/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -358,9 +387,9 @@ } }, "node_modules/@astrojs/react": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-3.6.0.tgz", - "integrity": "sha512-YGLxy5jCU9xKG/HAvYsWMcvrQVIhqVe0Sda3Z5UtP32rfXeG6B9J1xQvnx+kRSFTpIrj+7AwPSDSehLbCHJ56w==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-3.6.2.tgz", + "integrity": "sha512-fK29lYI7zK/KG4ZBy956x4dmauZcZ18osFkuyGa8r3gmmCQa2NZ9XNu9WaVYEUm0j89f4Gii4tbxLoyM8nk2MA==", "dependencies": { "@vitejs/plugin-react": "^4.3.1", "ultrahtml": "^1.5.3" @@ -1823,6 +1852,25 @@ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, "node_modules/@mdx-js/mdx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz", @@ -2282,8 +2330,7 @@ "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "dev": true + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" }, "node_modules/@types/acorn": { "version": "4.0.6", @@ -2466,6 +2513,18 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "dev": true, + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/@vitejs/plugin-react": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", @@ -2584,6 +2643,11 @@ "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.16.tgz", "integrity": "sha512-JT5CvrIYYCrmB+dCana8sUqJEcGB1ZDXNLMQ2+42bW995WmNoenijWMUdZfwmuQUTQcEVVIa2OecZzTYWUW9Cg==" }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "node_modules/acorn": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", @@ -2603,6 +2667,17 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", @@ -2715,6 +2790,24 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -3197,6 +3290,52 @@ } ] }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/canvas/node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/canvas/node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/canvas/node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -3488,6 +3627,14 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/color/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3526,6 +3673,16 @@ "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==" }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -4095,6 +4252,11 @@ "robust-predicates": "^3.0.2" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -4229,7 +4391,6 @@ "version": "6.5.4", "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", - "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", @@ -4242,7 +4403,6 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", - "dev": true, "engines": { "node": ">=10.0.0" } @@ -4569,6 +4729,38 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4590,6 +4782,68 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -4730,6 +4984,11 @@ "node": ">=4" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -5124,6 +5383,18 @@ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -5171,6 +5442,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -5733,6 +6014,28 @@ "@jridgewell/sourcemap-codec": "^1.4.15" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/markdown-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", @@ -7395,6 +7698,45 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -7436,6 +7778,11 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==" + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -7486,6 +7833,25 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -7496,6 +7862,20 @@ "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -7542,6 +7922,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -7794,6 +8186,14 @@ "node": ">=8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -8249,6 +8649,19 @@ "node": ">=6" } }, + "node_modules/qr-code-styling": { + "version": "1.5.1", + "resolved": "git+ssh://git@github.com/awesome-algorand/qr-code-styling.git#f279d28f55e300270e31a034d6ade67f5a373598", + "license": "MIT", + "dependencies": { + "qrcode-generator": "^1.4.3" + } + }, + "node_modules/qrcode-generator": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-1.4.4.tgz", + "integrity": "sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9023,6 +9436,61 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", @@ -9179,6 +9647,11 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "node_modules/sharp": { "version": "0.32.6", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", @@ -9323,7 +9796,6 @@ "version": "4.7.5", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", - "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", @@ -9338,7 +9810,6 @@ "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -9694,6 +10165,22 @@ "node": ">=10" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tar-fs": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", @@ -9717,6 +10204,27 @@ "streamx": "^2.15.0" } }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -9755,6 +10263,11 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -9825,8 +10338,7 @@ "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" }, "node_modules/type-fest": { "version": "2.19.0", @@ -10452,6 +10964,20 @@ "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.3.0.tgz", "integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==" }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -10486,6 +11012,51 @@ "node": ">=4" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", @@ -10662,7 +11233,6 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, "engines": { "node": ">=10.0.0" }, @@ -10683,7 +11253,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", - "dev": true, "engines": { "node": ">=0.4.0" } diff --git a/docs/package.json b/docs/package.json index 4c8701e..44b5fe4 100644 --- a/docs/package.json +++ b/docs/package.json @@ -10,15 +10,17 @@ "astro": "astro" }, "dependencies": { + "@algorandfoundation/liquid-client": "github:algorandfoundation/liquid-auth-js", "@astrojs/check": "^0.5.10", "@astrojs/mdx": "^3.1.2", - "@astrojs/react": "^3.6.0", + "@astrojs/react": "^3.6.2", "@astrojs/starlight": "^0.24.2", "@astrojs/tailwind": "^5.1.0", "@fontsource/poppins": "^5.0.13", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "astro": "^4.3.5", + "qr-code-styling": "github:awesome-algorand/qr-code-styling", "react": "^18.3.1", "react-dom": "^18.3.1", "rehype-mermaid": "^2.1.0", @@ -31,6 +33,7 @@ "typescript": "^5.4.5" }, "devDependencies": { + "@vitejs/plugin-basic-ssl": "^1.1.0", "socket.io-client": "^4.7.5", "tweetnacl": "^1.0.3" } diff --git a/docs/public/logo.png b/docs/public/logo.png new file mode 100644 index 0000000..7e7d46f Binary files /dev/null and b/docs/public/logo.png differ diff --git a/docs/src/components/QrCodeDemo.tsx b/docs/src/components/QrCodeDemo.tsx new file mode 100644 index 0000000..47638a8 --- /dev/null +++ b/docs/src/components/QrCodeDemo.tsx @@ -0,0 +1,58 @@ +import {SignalClient} from "@algorandfoundation/liquid-client"; +import { useEffect, useState } from "react"; + +const url = "liquid-auth.onrender.com" + +const INITIAL = "Initializing ๐Ÿš€" +const PEER_CONNECTED = "Peer connected ๐ŸŽ‰" +const LINK_REQUEST = "Link Requested ๐Ÿšš" +const WAITING = "Waiting for Link โŒ›" +const LINKED = "Linked ๐Ÿ”—" +const CLOSED = "Closed ๐Ÿšช" + +export function QrCodeDemo(){ + const [client] = useState(new SignalClient(url)); + const [requestId, setRequestId] = useState(SignalClient.generateRequestId()); + const [qrCodeUrl, setQrCodeUrl] = useState(""); + const [status, setStatus] = useState(INITIAL); + + // @ts-expect-error, ignoring the private field + client.qrCodeOptions.image = "/logo.png" + + useEffect(() => { + setStatus(LINK_REQUEST) + client.on("link-message", () => { + setStatus(LINKED) + }) + client.peer(requestId, "offer").then(() => { + setStatus(PEER_CONNECTED) + }) + client.qrCode().then((url) => { + setQrCodeUrl(url); + setStatus(WAITING) + }) + return ()=>{ + client.close() + setStatus(CLOSED) + } + }, [requestId]); + + return
+
{status}
+ {qrCodeUrl && PEER_CONNECTED && +
+ QR Code for Liquid Auth + Algorand QRCode +
+ } + {status === PEER_CONNECTED && } + +
+} diff --git a/docs/src/content/docs/clients/android/authentication.mdx b/docs/src/content/docs/clients/android/authentication.mdx index 2ff5b15..14d04f3 100644 --- a/docs/src/content/docs/clients/android/authentication.mdx +++ b/docs/src/content/docs/clients/android/authentication.mdx @@ -14,7 +14,7 @@ val httpClient = OkHttpClient.Builder() val assertionApi = AssertionApi(httpClient) ``` -## User Agent +## ๐Ÿ‘ค User Agent The User-Agent string is used to authenticate the device. @@ -24,7 +24,7 @@ val userAgent = "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} " + "(Android ${Build.VERSION.RELEASE}; ${Build.MODEL}; ${Build.BRAND})" ``` -## Options +## ๐Ÿงฎ Options Fetch assertion options from the service. ```kotlin @@ -35,7 +35,7 @@ val response = assertionApi.postAssertionOptions( ).await() ``` -## Retrieving +## ๐ŸŽ‰ Retrieving There are several ways to handle the retrieval of an existing Passkey. We recommend @@ -105,14 +105,28 @@ using the [FIDO2ApiClient](https://developers.google.com/identity/fido/android/n -## Response +## ๐Ÿ” Liquid Extension + +The liquid extension is optional for authentication requests. + +This is useful when you already have a passkey +and want to peer with a device that is not signed in. ```kotlin -// MainActivity.kt val liquidExtJSON = JSONObject() +// Optionally authenticate a remote peer liquidExtJSON.put("requestId", requestId) +``` + + +## ๐Ÿšš Response + +```kotlin +// MainActivity.kt + + val response = assertionApi.postAssertionResponse( origin, // Origin Server userAgent, // Required for checking the authenticator fingerprint diff --git a/docs/src/content/docs/clients/android/introduction.mdx b/docs/src/content/docs/clients/android/introduction.mdx index f47df2a..8ac15cb 100644 --- a/docs/src/content/docs/clients/android/introduction.mdx +++ b/docs/src/content/docs/clients/android/introduction.mdx @@ -42,7 +42,7 @@ using the SHA256 fingerprint and application name in the [environment configurat Add jitpack as a repository - ```kotlin + ```kotlin add={6} add={7} add={8} dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { @@ -56,7 +56,7 @@ Add jitpack as a repository ``` - ```groovy + ```groovy add={6} dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { diff --git a/docs/src/content/docs/clients/android/provider-service/get-passkey.md b/docs/src/content/docs/clients/android/provider-service/authenticate.md similarity index 69% rename from docs/src/content/docs/clients/android/provider-service/get-passkey.md rename to docs/src/content/docs/clients/android/provider-service/authenticate.md index fca6c4f..a9f70d7 100644 --- a/docs/src/content/docs/clients/android/provider-service/get-passkey.md +++ b/docs/src/content/docs/clients/android/provider-service/authenticate.md @@ -1,5 +1,5 @@ --- -title: "Android: Get Service Passkey" +title: "Android 14: Authenticate" --- ```kotlin @@ -8,6 +8,6 @@ val request = PendingIntentHandler.retrieveProviderCreateCredentialRequest(inten if (request.callingRequest is CreatePublicKeyCredentialRequest) { val result = viewModel.processCreatePasskey(this@CreatePasskeyActivity, request) } else { - binding.createPasskeyMessage.text = resources.getString(R.string.get_passkey_error) + val text = resources.getString(R.string.get_passkey_error) } ``` diff --git a/docs/src/content/docs/clients/android/provider-service/create-passkey.md b/docs/src/content/docs/clients/android/provider-service/register.md similarity index 75% rename from docs/src/content/docs/clients/android/provider-service/create-passkey.md rename to docs/src/content/docs/clients/android/provider-service/register.md index 9175cbc..ffe295b 100644 --- a/docs/src/content/docs/clients/android/provider-service/create-passkey.md +++ b/docs/src/content/docs/clients/android/provider-service/register.md @@ -1,5 +1,5 @@ --- -title: "Android: Create Service Passkey" +title: "Android 14: Register" --- @@ -13,6 +13,6 @@ if (request != null) { finish() } } else { - binding.getPasskeyMessage.text = resources.getString(R.string.get_passkey_error) + val text = resources.getString(R.string.get_passkey_error) } ``` diff --git a/docs/src/content/docs/clients/android/registration.mdx b/docs/src/content/docs/clients/android/registration.mdx index 82b09b3..4cad405 100644 --- a/docs/src/content/docs/clients/android/registration.mdx +++ b/docs/src/content/docs/clients/android/registration.mdx @@ -6,6 +6,8 @@ import {Aside, Tabs, TabItem } from "@astrojs/starlight/components"; Register a [Passkey](../../guides/concepts#passkeys) with the [Service](../../server/introduction) and attest the knowledge of a KeyPair. +This is done by creating a new Passkey with the [liquid extension](/guides/passkey/extension) enabled. +The extension is used to sign the challenge with an additional KeyPair as well as authenticate a remote peer. Get started by initializing the AttestationApi with an OkHttpClient and CookieJar. ```kotlin @@ -15,7 +17,7 @@ val httpClient = OkHttpClient.Builder() val attestationApi = AttestationApi(httpClient) ``` -## User Agent +## ๐Ÿ‘ค User Agent The User-Agent string is used to authenticate the device. @@ -25,9 +27,10 @@ val userAgent = "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} " + "(Android ${Build.VERSION.RELEASE}; ${Build.MODEL}; ${Build.BRAND})" ``` -## Options +## ๐Ÿงฎ Options Fetch attestation options from the service. +The remote client should present a [Deep Link](/guides/linking/#deep-link) which contains the Origin. ```kotlin // Create Options for FIDO2 Server val options = JSONObject() @@ -47,7 +50,7 @@ val response = attestationApi.postAttestationOptions( ) ``` -## Creating +## โœจ Creating There are several ways to handle the creation of a new Passkey. We recommend @@ -124,17 +127,29 @@ attestationIntentLauncher.launch( -## Response +## ๐Ÿ” Liquid Extension + +Sign the challenge with an additional KeyPair and optionally authenticate a remote peer. ```kotlin // Create the Liquid Extension JSON val liquidExtJSON = JSONObject() +// The type of signature and public key, this is also used +// to determine the type of encoding for the user.id liquidExtJSON.put("type", "algorand") -liquidExtJSON.put("requestId", msg.requestId) +// The address of the account liquidExtJSON.put("address", account.address.toString()) -liquidExtJSON.put("signature", Base64.encodeBase64URLSafeString(signature!!)) +// The signature of the challenge, signed by the account +liquidExtJSON.put("signature", Base64.encodeBase64URLSafeString(signature)) +// Optionally authenticate a remote peer +liquidExtJSON.put("requestId", "") +// Optional device name liquidExtJSON.put("device", Build.MODEL) +``` +## ๐Ÿšš Response + +```kotlin val response = attestationApi.postAttestationResponse( origin, // Origin Server "User-Agent-String", // Required for checking the authenticator fingerprint diff --git a/docs/src/content/docs/clients/browser/authentication.md b/docs/src/content/docs/clients/browser/authentication.md index 563aeb0..47e87b8 100644 --- a/docs/src/content/docs/clients/browser/authentication.md +++ b/docs/src/content/docs/clients/browser/authentication.md @@ -1,8 +1,12 @@ --- title: 'Browser: Authentication' +sidebar: + badge: + text: "TODO" + variant: danger --- -Authenticate an existing [Passkey](../../guides/concepts#passkeys) with the [Service](../../server/introduction). +Authenticate an existing [Passkey](/guides/concepts/#passkeys) with the [Service](/guides/server/introduction). ### Who is this for? @@ -33,3 +37,71 @@ await assertion( {requestId: 12345} // Optional requestId to link ) ``` + +## Manual + +If you want to manually handle the process of creating a passkey, you can use the following methods and preforming +the three steps of the process. + +### ๐Ÿงฎ Options + +Manually fetching the `Options` from the service. + +```typescript +import {fetchAssertionRequestOptions} from '@algorandfoundation/liquid-client/assertion' + +const encodedOptions = await fetchAssertionRequestOptions("https://my-liquid-service.com", "") +``` + +### ๐ŸŽ‰ Retrieving + +Decode the options and fetch the Passkey. + +```typescript +import {fromBase64Url} from "@algorandfoundation/liquid-client/encoding"; +const options = { ...encodedOptions }; +// Challenge from the service +options.challenge = fromBase64Url(options.challenge); +// Decode any known credentials +if (options.allowCredentials) { + for (const cred of options.allowCredentials) { + cred.id = fromBase64Url(cred.id); + } +} +const credential = navigator.credentials.get({ + publicKey: options +}) +``` + +### ๐Ÿ” Liquid Extension + +Optionally, Authenticate a remote user with the Liquid Extension. + +```typescript +credential.clientExtensionResults = { + // Optionally authenticate a remote peer + requestId: "" +} +``` + +### ๐Ÿšš Response + +Encode and submit the passkey to the service. + +```typescript +import {fetchAssertionResponse} from '@algorandfoundation/liquid-client/assertion' +import {toBase64URL} from '@algorandfoundation/liquid-client/encoding' + +const result = await fetchAssertionResponse("https://my-liquid-service.com", { + id: credential.id, + type: credential.type, + rawId: toBase64URL(credential.rawId), + clientExtensionResults: credential.clientExtensionResults, + response: Object.keys(AuthenticatorAssertionResponse.prototype).reduce((prev, curr) => { + prev[curr] = toBase64URL(credential.response[curr]); + return prev; + }, { + clientDataJSON: toBase64URL(credential.response.clientDataJSON), + }), +}) +``` diff --git a/docs/src/content/docs/clients/browser/registration.mdx b/docs/src/content/docs/clients/browser/registration.mdx index be2a8f1..55ba822 100644 --- a/docs/src/content/docs/clients/browser/registration.mdx +++ b/docs/src/content/docs/clients/browser/registration.mdx @@ -12,7 +12,10 @@ Register a [Passkey](../../guides/concepts#passkeys) with the [Service](../../se ## Client -Creating a passkey and registering it with the service using an instance of the `SignalClient` +Creating a passkey and registering it with the service using an instance of the `SignalClient`. + +`attestation` is a convenience method that handles the entire process of creating a passkey and registering it with the service. +The caller must provide a callback that will be called when a challenge is received from the service. ```typescript // browser.client.ts @@ -26,11 +29,11 @@ await client.attestation( // The type of signature and public key type: 'algorand', // The address of the account - address: account.addr, + address: address, // The signature of the challenge, signed by the account - signature: toBase64URL(nacl.sign.detached(challenge, account.sk)), + signature: toBase64URL(nacl.sign.detached(challenge, seceretKey)), // Optionally authenticate a remote peer - requestId: 12345, + requestId: "", // Optional device name device: 'Demo Web Wallet' }) @@ -40,11 +43,13 @@ await client.attestation( ## Stateless -Creating a passkey without using the `SignalClient` +Using the `attestation` method to create a passkey without using the `SignalClient` ```typescript +import * as nacl from 'tweetnacl' import {attestation} from '@algorandfoundation/liquid-client/attestation' import {toBase64URL} from '@algorandfoundation/liquid-client/encoding' + await attestation( "https://my-liquid-service.com", // Callback when a challenge is received, return a signed challenge @@ -52,9 +57,9 @@ await attestation( // The type of signature and public key type: 'algorand', // The address of the account - address: account.addr, + address: address, // The signature of the challenge, signed by the account - signature: toBase64URL(nacl.sign.detached(challenge, account.sk)), + signature: toBase64URL(nacl.sign.detached(challenge, seceretKey)), // Optionally authenticate a remote peer requestId: 12345, // Optional device name @@ -62,3 +67,89 @@ await attestation( }) ) ``` + +## Manual + +If you want to manually handle the process of creating a passkey, you can use the following methods and preforming +the three steps of the process. + +### ๐Ÿงฎ Options + +Manually fetching the PublicKeyCredentialCreationOptions from the service. + +```typescript +import {fetchAttestationRequest} from '@algorandfoundation/liquid-client/attestation' + +const encodedOptions = await fetchAttestationRequest("https://my-liquid-service.com") +``` + +### โœจ Creating + +Decode the options and create a new passkey. + +```typescript +import {decodeAddress, fromBase64Url} from "@algorandfoundation/liquid-client/encoding"; +const options = { ...encodedOptions }; + // Uint8Array of the user's id, is set as the encoded address for this type of key + options.user.id = decodeAddress(address); + // Must be string that is equal to the id bytes using the appropriate encoding + options.user.name = address; + // Friendly name to display for the user + options.user.displayName = "Hello World"; + // Challenge from the service + options.challenge = fromBase64Url(options.challenge); + + // Decode any known credentials + if (options.excludeCredentials) { + for (const cred of options.excludeCredentials) { + cred.id = fromBase64Url(cred.id); + } +} +const credential = navigator.credentials.create({ + publicKey: options +}) + +``` + +### ๐Ÿ” Liquid Extension + +Sign the challenge with an additional KeyPair. + +```typescript +import * as nacl from 'tweetnacl' +import {toBase64URL} from '@algorandfoundation/liquid-client/encoding' + +credential.clientExtensionResults = { + // The type of signature and public key, this is also used + // to determine the type of encoding for the user.id + type: 'algorand', + // The address of the account + address: address, + // The signature of the challenge, signed by the account + signature: toBase64URL(nacl.sign.detached(options.challenge, seceretKey)), + // Optionally authenticate a remote peer + requestId: "", + // Optional device name + device: 'Demo Web Wallet' +} +``` + +### ๐Ÿšš Response + +Encode and submit the passkey to the service. + +```typescript +import {fetchAttestationResponse} from '@algorandfoundation/liquid-client/attestation' +import {toBase64URL} from '@algorandfoundation/liquid-client/encoding' + +const result = await fetchAttestationResponse("https://my-liquid-service.com", { + id: credential.id, + rawId: toBase64URL(credential.rawId), + type: credential.type, + response: { + clientDataJSON: toBase64URL(response.clientDataJSON), + attestationObject: toBase64URL(response.attestationObject), + }, + clientExtensionResults: credential.clientExtensionResults + }) +``` diff --git a/docs/src/content/docs/guides/Passkey/authentication.mdx b/docs/src/content/docs/guides/Passkey/authentication.mdx index 13ba917..b822f75 100644 --- a/docs/src/content/docs/guides/Passkey/authentication.mdx +++ b/docs/src/content/docs/guides/Passkey/authentication.mdx @@ -1,11 +1,8 @@ --- -title: Authentication Guide +title: "Passkey: Authentication Guide" sidebar: order: 11 label: Authentication - badge: - text: "WIP" - variant: caution tags: - Passkey - Registration @@ -13,7 +10,7 @@ tags: - Browser - Server --- -import { Tabs, TabItem, Steps, Aside} from '@astrojs/starlight/components'; +import { Steps, LinkCard, CardGrid, Aside } from "@astrojs/starlight/components"; Authenticating with a previously created [Passkey](../../concepts#passkeys) is a three-step process. @@ -23,101 +20,74 @@ Authenticating with a previously created [Passkey](../../concepts#passkeys) is a 3. Post the **Assertion Response** from an authenticator to the [Server](../../../server/introduction). -## โš™๏ธ Options +### Who is this for? -[PublicKeyCredentialRequestOptions](https://www.w3.org/TR/webauthn-2/#dictionary-assertion-options) are used +- **Wallets/Credential Managers** that want to adopt Liquid Auth. +- **Ecosystems** that want to leverage `Liquid Auth` for their networks. + +## ๐Ÿงฎ Options + + + + +PublicKeyCredentialRequestOptions are used to retrieve existing Passkey and are generated by the service. The URI for this request is [/assertion/request/:credId](../../../server/api/operations/assertioncontroller_request) using the `POST` method. - - - ```bash - export CRED_ID="AWwK7bcWvbQ4plHok9mOIzuMdDKmLTKog2mgqhe2X48C40ISsvt7xK9CJmjjWbWF7EnNVGxDPb51WHGfN1ac1_w" - curl -X POST \ - --header "Content-Type: application/json" \ - https://my-liquid-auth-service.com/attestation/request/$CRED_ID - ``` - - - ```typescript - //app.js - // TODO - ``` - See the [Browser](../../../clients/browser/registration) registration guide for more details. - - - ```kotlin - //app.kt - import foundation.algorand.auth.fido2.* - // TODO - ``` - See the [Android](../../../clients/android/registration) registration guide for more details. - - + + + + ## ๐ŸŽ‰ Retrieving Getting the existing Passkey from an authenticator can vary depending on the platform. Most platforms will accept the **Request Options** -and return an [AuthenticatorAssertionResponse](https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAssertionResponse). - - - - - ```typescript - //app.ts - const response: AuthenticatorAssertionResponse = await navigator.credentials.get({ - publicKey: options - }) - ``` - See the [Browser](../../../clients/browser/authentication) authentication guide for more details. - - - ```kotlin - //app.kt - // Retrieve the PublicKeyCredential from the - // FIDO2Client or CredentialManager - val credential = PublicKeyCredential() - ``` - See the [Android](../../../clients/android/authentication) authentication guide for more details. - - +and return an AuthenticatorAssertionResponse. + + + + + + ## ๐Ÿšš Response + + Registering a new Passkey with the service. Prove the authenticity of the Passkey by sending the **Attestation Response** to the service. The URI for this request is [/assertion/response](../../../server/api/operations/assertioncontroller_response) using the `POST` method. - - - ```bash - # TODO - curl -X POST \ - --header "Content-Type: application/json" \ - --data '{"clientDataJSON": "", "extension"}' \ - https://my-liquid-auth-service.com/attestation/response - ``` - - - ```typescript - //app.ts - // TODO - ``` - See the [Browser](../../../clients/browser/authentication) authentication guide for more details. - - - ```kotlin - //app.kt - val response = attestationApi.postAssertionResponse( - origin, // Origin Server - "User-Agent-String", // Required for checking the authenticator fingerprint - credential // PublicKeyCredential - liquidExtension // Liquid Extension - ) - ``` - See the [Android](../../../clients/android/authentication) authentication guide for more details. - - + + + + + diff --git a/docs/src/content/docs/guides/Passkey/extension.mdx b/docs/src/content/docs/guides/Passkey/extension.mdx new file mode 100644 index 0000000..6bdb3b1 --- /dev/null +++ b/docs/src/content/docs/guides/Passkey/extension.mdx @@ -0,0 +1,105 @@ +--- +title: "Passkey: Liquid Extension Guide" +sidebar: + label: "Extension" +--- + +import { Aside, LinkCard } from "@astrojs/starlight/components"; + + +This is a [WebAuthn extension](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API/WebAuthn_extensions) that allows the service to verify the authenticity of a `KeyPair` using a `Passkey`. +The extension is used during the [Registration](/guides/passkey/registration) and [Authentication](/guides/passkey/authentication) of Passkeys. + +It is the heart of operations for the `Liquid` service and is required for registration and peer-to-peer connections. + +### Who is this for? + +- **Wallets/Credential Managers** that want to adopt Liquid Auth. +- **Ecosystems** that want to leverage the `Liquid Extension` for their networks. + + + +## ๐Ÿงฎ Options + +The service will expect the following options to be passed with the `PublicKeyCredentialCreationOptions` and `PublicKeyCredentialRequestOptions`: + +```javascript +const body = { + //...options + "extensions": { + "liquid": true + } + } +``` + +This tells the service that the request is using the Liquid extension and expects to receive a `Passkey` with additional information. + + +## ๐Ÿงช Handling Passkey + +As of this writing, currently no Authenticators support the `liquid` extension natively. The extension must be handled by the integrators + +If you are developing an Authenticator, you will need to handle the `liquid` extension in the `PublicKeyCredentialCreationOptions` and `PublicKeyCredentialRequestOptions`. + +Feel free to edit this document if you have an Authenticator that supports the `liquid` extension. + + +## ๐Ÿšš Response + +The response message should include the extension results in the `liquid` key if it was enabled in the `Options`. +It is mandatory to include the extension when registering new credentials with the Service. + + +### โœจ Registration + + + +The reference implementation of the extension currently only supports the `algorand` type. +It allows associating an Algorand address with the Passkey. + +```javascript +const response = { + //...response from authenticator + "clientExtensionResults": { + "liquid": { + // Required for the extension + "type": "algorand", + // The address of the account in Algorand Encoding + "address": "2SPDE6XLJNXFTOO7OIGNRNKSEDOHJWVD3HBSEAPHONZQ4IQEYOGYTP6LXA", + // Signature of the challenge that was produced by the Service + "signature": "QY31mdH8AwpJ9p4pCXBO2iA5WdU-BjG52xEtJNuSJNHJIaJ10uzqk3FdR0fvYVfb_rzXTuWn4k1PFFeg-vpEDw", + // Optional RequestId to authenticate a remote peer + "requestId": "019097ff-bb8c-7514-a0c6-5209d2405a4a", + // Optional name for the device + "device": "Pixel 8 Pro" + } + } +} +``` + + + +### ๐ŸŽ‰ Authentication + +When using a previously registered Passkey, the client does not require the liquid extension. +The service has attested to the additional keypair which represents an account and can rely on the WebAuthn standard for authentication. + + +Although the extension is not required, it is useful for establishing a Peer-to-Peer connection. + + +```javascript +const response = { + //...response from authenticator + "clientExtensionResults": { + "liquid": { + // Optional RequestId to authenticate a remote peer + "requestId": "019097ff-bb8c-7514-a0c6-5209d2405a4a" + } + } +} +``` diff --git a/docs/src/content/docs/guides/Passkey/registration.mdx b/docs/src/content/docs/guides/Passkey/registration.mdx index 05705cf..a8a610a 100644 --- a/docs/src/content/docs/guides/Passkey/registration.mdx +++ b/docs/src/content/docs/guides/Passkey/registration.mdx @@ -1,10 +1,7 @@ --- -title: Registration Guide +title: "Passkey: Registration Guide" sidebar: order: 10 - badge: - text: "WIP" - variant: caution label: Registration tags: - Passkey @@ -14,117 +11,79 @@ tags: - Browser - Server --- -import { Tabs, TabItem, Steps, Aside} from '@astrojs/starlight/components'; +import { Steps, Aside, CardGrid, LinkCard} from '@astrojs/starlight/components'; Registering a [Passkey](../../concepts#passkeys) is a three-step process. 1. Fetch the **Creation Options** from the [Server](../../../server/introduction). - 2. Create a new [Passkey](../../concepts#passkeys)() using the **Creation Options**. + 2. Create a new [Passkey](../../concepts#passkeys) using the **Creation Options**. 3. Post the **Attestation Response** from an authenticator to the [Server](../../../server/introduction). -## โš™๏ธ Options +### Who is this for? + +- **Wallets/Credential Managers** that want to adopt Liquid Auth. +- **Ecosystems** that want to leverage `Liquid Auth` for their networks. + +## ๐Ÿงฎ Options -[PublicKeyCredentialCreationOptions](https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredentialCreationOptions) are used to create a new Passkey and are generated by the service. +PublicKeyCredentialCreationOptions are used to create a new Passkey and are generated by the service. This allows the service to define what options are required for registration. The URI for this request is [/attestation/request](../../../server/api/operations/attestationcontroller_request) using the `POST` method. - - - ```bash - curl -X POST \ - --header "Content-Type: application/json" \ - --data '{"extensions": {"liquid": true}}' \ - https://my-liquid-auth-service.com/attestation/request - ``` - - - ```typescript - //app.js - import { fetchAttestationRequest } from '@algorandfoundation/liquid-client/attestation' - const options = await fetchAttestationRequest("https://my-liquid-auth-service.com") - ``` - See the [Browser](../../../clients/browser/registration) registration guide for more details. - - - ```kotlin - //app.kt - import foundation.algorand.auth.fido2.* - // TODO - ``` - See the [Android](../../../clients/android/registration) registration guide for more details. - - + + + + + ## โœจ Creating Generating a new Passkey from an authenticator can vary depending on the platform. -Most platforms will accept the **Creation Options** and return an [AuthenticatorAttestationResponse](https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAttestationResponse). - - - - - ```typescript - //app.ts - const response: AuthenticatorAttestationResponse = await navigator.credentials.create({ - publicKey: options - }) - ``` - See the [Browser](../../../clients/browser/registration) registration guide for more details. - - - ```kotlin - //app.kt - // Create a new PublicKeyCredential using - // FIDO2Client or CredentialManager - val credential = PublicKeyCredential() - ``` - See the [Android](../../../clients/android/registration) registration guide for more details. - - +Most platforms will accept the **Creation Options** and return an AuthenticatorAttestationResponse. + + + + + ## ๐Ÿšš Response - + Registering a new Passkey with the service. Prove the authenticity of the Passkey by sending the **Attestation Response** to the service. The URI for this request is [/attestation/response](../../../server/api/operations/attestationcontroller_response) using the `POST` method. - - - ```bash - # TODO - curl -X POST \ - --header "Content-Type: application/json" \ - --data '{"attestationResponse": "", "clientDataJSON": "", "extension"}' \ - https://my-liquid-auth-service.com/attestation/response - ``` - - - ```typescript - //app.ts - import { fetchAttestationResponse } from '@algorandfoundation/liquid-client/attestation' - // TODO - ``` - See the [Browser](../../../clients/browser/registration) registration guide for more details. - - - ```kotlin - //app.kt - val response = attestationApi.postAttestationResponse( - origin, // Origin Server - "User-Agent-String", // Required for checking the authenticator fingerprint - credential // PublicKeyCredential - liquidExtension // Liquid Extension - ) - ``` - See the [Android](../../../clients/android/registration) registration guide for more details. - - + + + + + diff --git a/docs/src/content/docs/guides/Peer to Peer/answer.mdx b/docs/src/content/docs/guides/Peer to Peer/answer.mdx index 2e03694..520cfba 100644 --- a/docs/src/content/docs/guides/Peer to Peer/answer.mdx +++ b/docs/src/content/docs/guides/Peer to Peer/answer.mdx @@ -1,5 +1,5 @@ --- -title: "Answer Guide" +title: "Peer: Answer Guide" sidebar: order: 21 label: "Answer" @@ -9,9 +9,15 @@ import { LinkCard, CardGrid } from "@astrojs/starlight/components"; An **Answer** is a type of session that is initiated by a client and is used to respond to an **Offer** from another client. +The Answer client is responsible for presenting the [Deep Link](/guides/linking/#deep-link) to the Offer client and waiting for the response. -This is usually a dApp that wants to peer with a wallet client with an Offer. -The Answer client is responsible for presenting the QRCode to the Offer client. +### Who is this for? + +- **dApps/Wallets** that want to peer with Wallets in the ecosystem. +- **Wallets** that want to integrate deeply into `Liquid Auth` and tailor the experience. + + +### Additional Links >A: Present QR Code B->>A: Scan QR Code A-->>B: Receive Origin and RequestId - B->>C: Offer to Origin - C->>A: Offer to Client - A->>C: Answer to Origin - C->>B: Answer to Client + B->>C: Authenticate/Register + C->>C: Validate Signatures + C->>C: Join Clients to Room + C-->>B: Ok Response + B->>C: Emit Offer to Origin + C-->>A: Emit Offer to Client + A->>C: Emit Answer to Origin + C-->>B: Emit Answer to Client +``` + +## ICE Candidates + +The clients exchange ICE candidates to establish a connection. +The ICE candidates are used to determine the best path for the data to travel between the clients. +The clients exchange ICE candidates over the signaling server via WebSockets. + +```mermaid +sequenceDiagram + participant A as Answer Client + participant C as Liquid Service + participant B as Offer Client + A->>A: Gather ICE Candidates + A->>C: Send ICE Candidates + C->>B: Send ICE Candidates + B->>B: Gather ICE Candidates + B->>C: Send ICE Candidates + C->>A: Send ICE Candidates +``` + +### Candidate Discovery + +STUN and TURN servers are used as a fallback when a local connection cannot be established on the LAN. +The STUN server is used to discover the client's public IP address, +while the TURN server is used to relay data if a direct connection to public IP cannot be established. + +The following diagram shows the exchange of STUN/TURN candidates with a client. + +```mermaid +sequenceDiagram + participant A as Peer A + participant B as STUN Service + participant C as TURN Service + A->>A: Get Local Candidates + A->>B: Get STUN Candidates + B-->>A: Send STUN Candidates + A->>C: Get TURN Relay Candidates + C-->>A: Send TURN Relay Candidates ``` diff --git a/docs/src/content/docs/guides/Peer to Peer/offer.mdx b/docs/src/content/docs/guides/Peer to Peer/offer.mdx index 66fb91c..4aa819d 100644 --- a/docs/src/content/docs/guides/Peer to Peer/offer.mdx +++ b/docs/src/content/docs/guides/Peer to Peer/offer.mdx @@ -1,5 +1,5 @@ --- -title: "Offer Guide" +title: "Peer: Offer Guide" sidebar: order: 20 label: "Offer" @@ -11,7 +11,11 @@ import {Aside, CardGrid, LinkCard} from '@astrojs/starlight/components'; An **Offer** is a type of session that is initiated by a client and is used to create a P2P connection with an **Answer** client. -This is usually a wallet that wants to peer with a dApp client that can produce an Answer. +### Who is this for? + +- **Wallets/Credential Managers** that want to peer with dApps clients. + +### Additional Links You can find more information in the Server guide The responsibilities of the service are limited to authentication and brokering connections between peers. -Authentication is handled using [Passkeys](../concepts#passkeys) with a custom `Liquid Extension` +Authentication is handled using [Passkeys](../concepts#-passkeys) with a custom `Liquid Extension` which attests an additional KeyPair (ie Algorand Account). -Once a client is authenticated, the service can be used to broker a [Peer to Peer](../concepts#peer-to-peer) connection. +Once a client is authenticated, the service can be used to broker a [Peer to Peer](../concepts#-peer-to-peer) connection. #### Who should use this service? @@ -29,9 +29,9 @@ Not only is this generally more secure and decentralized, it also reduces the lo -### Clients +### ๐Ÿ’ป Clients - + The **Liquid Auth Clients** are libraries that provide a simple way to interact with the service and other peers. Clients use the service to authenticate and broker a connection between peers. diff --git a/docs/src/content/docs/guides/concepts.md b/docs/src/content/docs/guides/concepts.md deleted file mode 100644 index 07a7523..0000000 --- a/docs/src/content/docs/guides/concepts.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Key Concepts -sidebar: - order: 1 - badge: - text: "WIP" - variant: caution ---- - -There are a few key concepts that are important to understand when working with Liquid Auth. -The main concepts are `Linking`, `Passkeys`, and `Peer-to-Peer`. -See the full details in the [Architecture Reference](../../architecture). - -## Linking - -A link will authorize a remote client to access the service. This is done by generating a `RequestId` by the remote device and waiting -for a device to attest a Passkey. We recommend displaying a QR code with a [liquid deep-link]() to the user to scan with their device. - -See how to implement Linking in the [Android]() and [Browser]() client documentation - -## Passkeys - -Passkeys are also known as FIDO2/WebAuthn [PublicKeyCredential](https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential). -This KeyPair is used to register or authenticate a user and is generated by an authenticator device. -Passkeys/Authenticators must also support the `Liquid Extension` which is used to attest a `KeyPair` not controlled by the authenticator. - -## Peer-to-Peer - -[WebRTC](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API) is used for establishing a peer-to-peer connection between two clients. - -#### Offer - -Session Description Protocol (SDP) message sent from the client to the server. The offer contains information about the client's media capabilities and information about the datachannel. - -#### Answer - -Session Description Protocol (SDP) message sent back to a client who created the Offer. -An Answer client can then use this information to generate an answer, which is sent back to the offer client. - -#### Candidate - -ICE Candidate is a network address that can be used to communicate with the peer. diff --git a/docs/src/content/docs/guides/concepts.mdx b/docs/src/content/docs/guides/concepts.mdx new file mode 100644 index 0000000..f4b3078 --- /dev/null +++ b/docs/src/content/docs/guides/concepts.mdx @@ -0,0 +1,85 @@ +--- +title: Key Concepts +sidebar: + order: 1 +--- + +import {LinkCard, CardGrid} from '@astrojs/starlight/components'; + +There are a few key concepts that are important to understand when working with Liquid Auth. +The main concepts are `Linking`, `Passkeys`, and `Peer-to-Peer`. +See the full details in the [Architecture Reference](../../architecture). + +## ๐Ÿ”— Linking + +A link will authorize a remote client to access the service. +This is done by generating a `RequestId` and waiting for a device to attest a Passkey. + + + +## ๐Ÿ”’ Passkeys + +Passkeys are also known as FIDO2/WebAuthn [PublicKeyCredential](https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential). +This KeyPair is used to register or authenticate a user and is generated by an authenticator device. + + + + + + + +### FIDO2 Extension + +Authenticators must also support the `Liquid Extension` which is used to attest a `KeyPair` not controlled by the authenticator. + +This extension attaches an additional signature to the credential to associate the `KeyPair` with the `Passkey`. +The extension also includes an optional `requestId` which is used to link the `KeyPair` to a specific session. +When two clients are linked, they can establish a peer-to-peer connection. + + + + +## ๐Ÿ”„ Peer-to-Peer + +[WebRTC](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API) is used for establishing a peer-to-peer connection between two clients. + +#### Offer + +Session Description Protocol (SDP) message sent from the client to the server. The offer contains information about the client's media capabilities and information about the datachannel. + + + +#### Answer + +Session Description Protocol (SDP) message sent back to a client who created the Offer. +An Answer client can then use this information to generate an answer, which is sent back to the offer client. + + + +#### Candidate + +ICE Candidate is a network address that can be used to communicate with the peer. diff --git a/docs/src/content/docs/guides/getting-started.mdx b/docs/src/content/docs/guides/getting-started.mdx index 9b24322..9b795f1 100644 --- a/docs/src/content/docs/guides/getting-started.mdx +++ b/docs/src/content/docs/guides/getting-started.mdx @@ -4,12 +4,24 @@ sidebar: order: 0 pagefind: false --- -import { LinkCard, CardGrid, Aside } from '@astrojs/starlight/components'; +import { LinkCard, CardGrid } from '@astrojs/starlight/components'; Liquid Auth is composed of two main components, the **Liquid Auth Server** and the **Liquid Auth Clients**. They are used together to provide authentication and signaling services for decentralized applications (dApps). -## Quick Links + +## ๐Ÿš€ Use Case + +The service should be provided by the **dApp** and the **Wallets** should act as clients. +The **Wallet** will receive the `Origin` and `RequestId` from the `dApp` and will use it +to authenticate with the service provided as the `Origin`. + +#### ๐Ÿ“ Requirements + +- **Wallets** should implement the **Offer** `SignalClient` and `WebAuthn Extension` to establish a peer-to-peer connection with the **dApp**. +- **dApps** should implement the **Answer** `SignalClient` and host the Service. + +## ๐Ÿ”— Quick Links + We recommend following the Peer-to-Peer guides to understand how to establish a connection between clients + + +A link will authorize a remote client to access the service. +This is done by generating a `requestId` and waiting for a device to attest a [Passkey](/guides/concepts/#-passkeys). + +A link event can only be acknowledged by the service when the remote client has successfully authenticated. +The linking processs is backed by a [Deep Link](#deep-link) and a [QR Code](#qr-code). +The `SignalClient` is responsible for generating the deep link and presenting to another client. + +The remote client will handle the `Deep Link` by submitting a `Passkey` with the [Liquid Extension](/guides/passkey/extension) to the origin service. +Once the service has validated the linking request, the client will be able to communicate with the service and establish a peer-to-peer connection. + + +### Who is this for? + +- **dApps/Wallets** that want to integrate deeply into `Liquid Auth`. + + +## Deep Link + +Liquid uses a custom deep link to handle linking between devices. + +The format is as follows: + +``` +liquid:///?requestId= +``` + +This link will be used to generate a QR code for the user to scan with their device. + +#### Origin + +The origin is the server that will handle the linking request. + + +#### Request ID + +The request ID is a UUID generated by a client to identify the linking request. + +## QR Code + +We recommend displaying the deep link as a QR code for the user to scan with their device. +Try it out by downloading the [demo Android](https://github.com/algorandfoundation/liquid-auth-android/releases) application and scanning the QRCode below. + +
Loading
+ + +### Diagram + +This diagram illustrates the linking process between a website and a wallet. + +```mermaid +sequenceDiagram + participant Website as Answer Client + participant Server + participant Wallet as Offer Client + Website->>Server: Subscribe to 'wss:link' + Website-->>Website: Display QR Connect Request ID + Wallet->>Website: Scan QR Code + Server-->>Wallet: Get Challenge/Options + Wallet->>Server: Register/Authenticate + Server-->>Server: Validate Signatures + Server-->>Website: HTTPOnly Session + Server->>Wallet: Ok Response + HTTPOnly Session + Server->>Website: Emit to `wss:link` client +``` diff --git a/docs/src/content/docs/guides/qr-code.md b/docs/src/content/docs/guides/qr-code.md deleted file mode 100644 index f4f1c57..0000000 --- a/docs/src/content/docs/guides/qr-code.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "QR Code Guide" -sidebar: - label: "QR Code" - badge: - text: "TODO" - variant: danger -next: false ---- - diff --git a/docs/src/pages/demo.astro b/docs/src/pages/demo.astro new file mode 100644 index 0000000..8faadcf --- /dev/null +++ b/docs/src/pages/demo.astro @@ -0,0 +1,7 @@ +--- +import {QrCodeDemo} from '../components/QrCodeDemo'; +export const partial = true; +--- + + + diff --git a/docs/tsconfig.json b/docs/tsconfig.json index 69b4fc1..b984f06 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -3,6 +3,7 @@ "exclude": ["./clients/**/*"], "compilerOptions": { "jsx": "react-jsx", - "jsxImportSource": "react" + "jsxImportSource": "react", + "allowSyntheticDefaultImports": true } }