From a140c40c7317428f2db4b8926ac2953b5974ca0a Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Mon, 4 Dec 2023 10:21:46 +0100 Subject: [PATCH 1/6] Add support for 2 index.js files --- src/canister_tests/src/framework.rs | 2 +- src/internet_identity/src/assets.rs | 24 ++++++++++++++++++------ src/internet_identity/src/http.rs | 7 ++++--- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/canister_tests/src/framework.rs b/src/canister_tests/src/framework.rs index ae6a30caa2..c7c141da4e 100644 --- a/src/canister_tests/src/framework.rs +++ b/src/canister_tests/src/framework.rs @@ -420,7 +420,7 @@ xr-spatial-tracking=()", "^default-src 'none';\ connect-src 'self' https://identity.internetcomputer.org https://icp-api.io https://\\*\\.icp0.io https://\\*\\.ic0.app;\ img-src 'self' data:;\ -script-src 'sha256-[a-zA-Z0-9/=+]+' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https:;\ +script-src 'sha256-[a-zA-Z0-9/=+]+' 'sha256-[a-zA-Z0-9/=+]+' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https:;\ base-uri 'none';\ form-action 'none';\ style-src 'self' 'unsafe-inline';\ diff --git a/src/internet_identity/src/assets.rs b/src/internet_identity/src/assets.rs index 67c95d010c..f0a59fec0d 100644 --- a/src/internet_identity/src/assets.rs +++ b/src/internet_identity/src/assets.rs @@ -19,23 +19,35 @@ pub fn init_assets() { } // The "#, - &format!(r#""#), + &format!(r#""#), + ); + + let setup_js2: String = JS_SETUP_SCRIPT2.to_string(); + html.replace( + r#""#, + &format!(r#""#), ) } lazy_static! { // The SRI sha256 hash of the script tag, used by the CSP policy. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src - pub static ref JS_SETUP_SCRIPT_SRI_HASH: String = { - let hash = &sha2::Sha256::digest(JS_SETUP_SCRIPT.as_bytes()); + pub static ref JS_SETUP_SCRIPT1_SRI_HASH: String = { + let hash = &sha2::Sha256::digest(JS_SETUP_SCRIPT1.as_bytes()); + let hash = BASE64.encode(hash); + format!("sha256-{hash}") + }; + pub static ref JS_SETUP_SCRIPT2_SRI_HASH: String = { + let hash = &sha2::Sha256::digest(JS_SETUP_SCRIPT2.as_bytes()); let hash = BASE64.encode(hash); format!("sha256-{hash}") }; diff --git a/src/internet_identity/src/http.rs b/src/internet_identity/src/http.rs index 94cd5c3afe..91913181fa 100644 --- a/src/internet_identity/src/http.rs +++ b/src/internet_identity/src/http.rs @@ -1,4 +1,4 @@ -use crate::assets::JS_SETUP_SCRIPT_SRI_HASH; +use crate::assets::{JS_SETUP_SCRIPT1_SRI_HASH, JS_SETUP_SCRIPT2_SRI_HASH}; use crate::http::metrics::metrics; use crate::state; use asset_util::{EXACT_MATCH_TERMINATOR, IC_CERTIFICATE_EXPRESSION}; @@ -195,12 +195,13 @@ pub fn security_headers() -> Vec { /// upgrade-insecure-requests is omitted when building in dev mode to allow loading II on localhost /// with Safari. pub fn content_security_policy_header() -> String { - let hash = JS_SETUP_SCRIPT_SRI_HASH.to_string(); + let hash1 = JS_SETUP_SCRIPT1_SRI_HASH.to_string(); + let hash2 = JS_SETUP_SCRIPT2_SRI_HASH.to_string(); let csp = format!( "default-src 'none';\ connect-src 'self' https://identity.internetcomputer.org https://icp-api.io https://*.icp0.io https://*.ic0.app;\ img-src 'self' data:;\ - script-src '{hash}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https:;\ + script-src '{hash1}' '{hash2}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https:;\ base-uri 'none';\ form-action 'none';\ style-src 'self' 'unsafe-inline';\ From e249395ea9423f3630c96cacad392aa120218959 Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Mon, 4 Dec 2023 10:23:35 +0100 Subject: [PATCH 2/6] Add verifiable credentials support in frontend --- package-lock.json | 14 + package.json | 5 +- src/frontend/generated/vc_issuer_idl.js | 103 +++++ src/frontend/generated/vc_issuer_types.d.ts | 84 ++++ .../abortedCredentials.json | 14 + .../abortedCredentials.ts | 84 ++++ .../src/flows/verifiableCredentials/index.ts | 415 ++++++++++++++++++ .../postMessageInterface.ts | 180 ++++++++ .../flows/verifiableCredentials/vcIssuer.ts | 109 +++++ src/frontend/src/styles/main.css | 6 + src/frontend/src/utils/iiConnection.ts | 80 ++++ src/frontend/src/vc-flow.ts | 4 + src/frontend/vc-flow/index.html | 16 + src/showcase/src/pages/[page].astro | 1 + src/showcase/src/showcase.ts | 7 + vite.config.ts | 12 +- vite.plugins.ts | 10 + 17 files changed, 1142 insertions(+), 2 deletions(-) create mode 100644 src/frontend/generated/vc_issuer_idl.js create mode 100644 src/frontend/generated/vc_issuer_types.d.ts create mode 100644 src/frontend/src/flows/verifiableCredentials/abortedCredentials.json create mode 100644 src/frontend/src/flows/verifiableCredentials/abortedCredentials.ts create mode 100644 src/frontend/src/flows/verifiableCredentials/index.ts create mode 100644 src/frontend/src/flows/verifiableCredentials/postMessageInterface.ts create mode 100644 src/frontend/src/flows/verifiableCredentials/vcIssuer.ts create mode 100644 src/frontend/src/vc-flow.ts create mode 100644 src/frontend/vc-flow/index.html diff --git a/package-lock.json b/package-lock.json index 8e9db1fbb9..7a1d0f7ac3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "bip39": "^3.0.4", "buffer": "^6.0.3", "idb-keyval": "^6.2.1", + "jose": "^5.1.3", "lit-html": "^2.7.2", "process": "^0.11.10", "qr-creator": "^1.0.0", @@ -8398,6 +8399,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jose": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.1.3.tgz", + "integrity": "sha512-GPExOkcMsCLBTi1YetY2LmkoY559fss0+0KVa6kOfb2YFe84nAM7Nm/XzuZozah4iHgmBGrCOHL5/cy670SBRw==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -21081,6 +21090,11 @@ } } }, + "jose": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.1.3.tgz", + "integrity": "sha512-GPExOkcMsCLBTi1YetY2LmkoY559fss0+0KVa6kOfb2YFe84nAM7Nm/XzuZozah4iHgmBGrCOHL5/cy670SBRw==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index 808c2cb57c..7646f925f3 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,11 @@ "watch:showcase": "astro check --root ./src/showcase --watch", "watch": "npm run check -- --watch", "opts": "NODE_OPTIONS='--loader ts-node/esm --experimental-specifier-resolution=node' \"$@\"", - "generate": "npm run generate:types && npm run generate:js", + "generate": "npm run generate:types && npm run generate:js && npm run generate:types-issuer && npm run generate:js-issuer", "generate:types": "didc bind ./src/internet_identity/internet_identity.did -t ts > src/frontend/generated/internet_identity_types.d.ts", "generate:js": "didc bind ./src/internet_identity/internet_identity.did -t js > src/frontend/generated/internet_identity_idl.js", + "generate:types-issuer": "didc bind ./demos/vc_issuer/vc_issuer.did -t ts > src/frontend/generated/vc_issuer_types.d.ts", + "generate:js-issuer": "didc bind ./demos/vc_issuer/vc_issuer.did -t js > src/frontend/generated/vc_issuer_idl.js", "build:showcase": "tsc --noEmit && astro check --root ./src/showcase && astro build --root ./src/showcase", "preview:showcase": "astro preview --root ./src/showcase", "screenshots": "npm run opts -- ./src/frontend/screenshots.ts", @@ -62,6 +64,7 @@ "bip39": "^3.0.4", "buffer": "^6.0.3", "idb-keyval": "^6.2.1", + "jose": "^5.1.3", "lit-html": "^2.7.2", "process": "^0.11.10", "qr-creator": "^1.0.0", diff --git a/src/frontend/generated/vc_issuer_idl.js b/src/frontend/generated/vc_issuer_idl.js new file mode 100644 index 0000000000..331e99ff64 --- /dev/null +++ b/src/frontend/generated/vc_issuer_idl.js @@ -0,0 +1,103 @@ +export const idlFactory = ({ IDL }) => { + const IssuerConfig = IDL.Record({ + 'idp_canister_ids' : IDL.Vec(IDL.Principal), + 'ic_root_key_der' : IDL.Vec(IDL.Nat8), + }); + const SignedIdAlias = IDL.Record({ 'credential_jws' : IDL.Text }); + const ArgumentValue = IDL.Variant({ 'Int' : IDL.Int32, 'String' : IDL.Text }); + const CredentialSpec = IDL.Record({ + 'arguments' : IDL.Opt(IDL.Vec(IDL.Tuple(IDL.Text, ArgumentValue))), + 'credential_type' : IDL.Text, + }); + const GetCredentialRequest = IDL.Record({ + 'signed_id_alias' : SignedIdAlias, + 'prepared_context' : IDL.Opt(IDL.Vec(IDL.Nat8)), + 'credential_spec' : CredentialSpec, + }); + const IssuedCredentialData = IDL.Record({ 'vc_jws' : IDL.Text }); + const IssueCredentialError = IDL.Variant({ + 'Internal' : IDL.Text, + 'SignatureNotFound' : IDL.Text, + 'InvalidIdAlias' : IDL.Text, + 'UnauthorizedSubject' : IDL.Text, + 'UnknownSubject' : IDL.Text, + 'UnsupportedCredentialSpec' : IDL.Text, + }); + const GetCredentialResponse = IDL.Variant({ + 'Ok' : IssuedCredentialData, + 'Err' : IssueCredentialError, + }); + const HeaderField = IDL.Tuple(IDL.Text, IDL.Text); + const HttpRequest = IDL.Record({ + 'url' : IDL.Text, + 'method' : IDL.Text, + 'body' : IDL.Vec(IDL.Nat8), + 'headers' : IDL.Vec(HeaderField), + }); + const HttpResponse = IDL.Record({ + 'body' : IDL.Vec(IDL.Nat8), + 'headers' : IDL.Vec(HeaderField), + 'status_code' : IDL.Nat16, + }); + const PrepareCredentialRequest = IDL.Record({ + 'signed_id_alias' : SignedIdAlias, + 'credential_spec' : CredentialSpec, + }); + const PreparedCredentialData = IDL.Record({ + 'prepared_context' : IDL.Opt(IDL.Vec(IDL.Nat8)), + }); + const PrepareCredentialResponse = IDL.Variant({ + 'Ok' : PreparedCredentialData, + 'Err' : IssueCredentialError, + }); + const Icrc21ConsentPreferences = IDL.Record({ 'language' : IDL.Text }); + const Icrc21VcConsentMessageRequest = IDL.Record({ + 'preferences' : Icrc21ConsentPreferences, + 'credential_spec' : CredentialSpec, + }); + const Icrc21ConsentInfo = IDL.Record({ + 'consent_message' : IDL.Text, + 'language' : IDL.Text, + }); + const Icrc21ErrorInfo = IDL.Record({ + 'description' : IDL.Text, + 'error_code' : IDL.Nat64, + }); + const Icrc21Error = IDL.Variant({ + 'GenericError' : Icrc21ErrorInfo, + 'UnsupportedCanisterCall' : Icrc21ErrorInfo, + 'ConsentMessageUnavailable' : Icrc21ErrorInfo, + }); + const Icrc21ConsentMessageResponse = IDL.Variant({ + 'Ok' : Icrc21ConsentInfo, + 'Err' : Icrc21Error, + }); + return IDL.Service({ + 'add_employee' : IDL.Func([IDL.Principal], [IDL.Text], []), + 'add_graduate' : IDL.Func([IDL.Principal], [IDL.Text], []), + 'configure' : IDL.Func([IssuerConfig], [], []), + 'get_credential' : IDL.Func( + [GetCredentialRequest], + [GetCredentialResponse], + ['query'], + ), + 'http_request' : IDL.Func([HttpRequest], [HttpResponse], ['query']), + 'prepare_credential' : IDL.Func( + [PrepareCredentialRequest], + [PrepareCredentialResponse], + [], + ), + 'vc_consent_message' : IDL.Func( + [Icrc21VcConsentMessageRequest], + [Icrc21ConsentMessageResponse], + [], + ), + }); +}; +export const init = ({ IDL }) => { + const IssuerConfig = IDL.Record({ + 'idp_canister_ids' : IDL.Vec(IDL.Principal), + 'ic_root_key_der' : IDL.Vec(IDL.Nat8), + }); + return [IDL.Opt(IssuerConfig)]; +}; diff --git a/src/frontend/generated/vc_issuer_types.d.ts b/src/frontend/generated/vc_issuer_types.d.ts new file mode 100644 index 0000000000..f25cdec05a --- /dev/null +++ b/src/frontend/generated/vc_issuer_types.d.ts @@ -0,0 +1,84 @@ +import type { Principal } from '@dfinity/principal'; +import type { ActorMethod } from '@dfinity/agent'; +import type { IDL } from '@dfinity/candid'; + +export type ArgumentValue = { 'Int' : number } | + { 'String' : string }; +export interface CredentialSpec { + 'arguments' : [] | [Array<[string, ArgumentValue]>], + 'credential_type' : string, +} +export interface GetCredentialRequest { + 'signed_id_alias' : SignedIdAlias, + 'prepared_context' : [] | [Uint8Array | number[]], + 'credential_spec' : CredentialSpec, +} +export type GetCredentialResponse = { 'Ok' : IssuedCredentialData } | + { 'Err' : IssueCredentialError }; +export type HeaderField = [string, string]; +export interface HttpRequest { + 'url' : string, + 'method' : string, + 'body' : Uint8Array | number[], + 'headers' : Array, +} +export interface HttpResponse { + 'body' : Uint8Array | number[], + 'headers' : Array, + 'status_code' : number, +} +export interface Icrc21ConsentInfo { + 'consent_message' : string, + 'language' : string, +} +export type Icrc21ConsentMessageResponse = { 'Ok' : Icrc21ConsentInfo } | + { 'Err' : Icrc21Error }; +export interface Icrc21ConsentPreferences { 'language' : string } +export type Icrc21Error = { 'GenericError' : Icrc21ErrorInfo } | + { 'UnsupportedCanisterCall' : Icrc21ErrorInfo } | + { 'ConsentMessageUnavailable' : Icrc21ErrorInfo }; +export interface Icrc21ErrorInfo { + 'description' : string, + 'error_code' : bigint, +} +export interface Icrc21VcConsentMessageRequest { + 'preferences' : Icrc21ConsentPreferences, + 'credential_spec' : CredentialSpec, +} +export type IssueCredentialError = { 'Internal' : string } | + { 'SignatureNotFound' : string } | + { 'InvalidIdAlias' : string } | + { 'UnauthorizedSubject' : string } | + { 'UnknownSubject' : string } | + { 'UnsupportedCredentialSpec' : string }; +export interface IssuedCredentialData { 'vc_jws' : string } +export interface IssuerConfig { + 'idp_canister_ids' : Array, + 'ic_root_key_der' : Uint8Array | number[], +} +export interface PrepareCredentialRequest { + 'signed_id_alias' : SignedIdAlias, + 'credential_spec' : CredentialSpec, +} +export type PrepareCredentialResponse = { 'Ok' : PreparedCredentialData } | + { 'Err' : IssueCredentialError }; +export interface PreparedCredentialData { + 'prepared_context' : [] | [Uint8Array | number[]], +} +export interface SignedIdAlias { 'credential_jws' : string } +export interface _SERVICE { + 'add_employee' : ActorMethod<[Principal], string>, + 'add_graduate' : ActorMethod<[Principal], string>, + 'configure' : ActorMethod<[IssuerConfig], undefined>, + 'get_credential' : ActorMethod<[GetCredentialRequest], GetCredentialResponse>, + 'http_request' : ActorMethod<[HttpRequest], HttpResponse>, + 'prepare_credential' : ActorMethod< + [PrepareCredentialRequest], + PrepareCredentialResponse + >, + 'vc_consent_message' : ActorMethod< + [Icrc21VcConsentMessageRequest], + Icrc21ConsentMessageResponse + >, +} +export declare const idlFactory: IDL.InterfaceFactory; diff --git a/src/frontend/src/flows/verifiableCredentials/abortedCredentials.json b/src/frontend/src/flows/verifiableCredentials/abortedCredentials.json new file mode 100644 index 0000000000..54590b7d40 --- /dev/null +++ b/src/frontend/src/flows/verifiableCredentials/abortedCredentials.json @@ -0,0 +1,14 @@ +{ + "en": { + "title": "Credential Sharing Aborted", + "ok": "Ok", + "aborted_internal_error": "There was an unexpected issue while verifying your credentials. Please retry, and if the problem persist contact support.", + "aborted_auth_failed_ii": "There was an error authenticating you with your Internet Identity. Aliases were not created.", + "aborted_auth_failed_issuer": "There was an error authenticating you with the issuer. Make sure you can authenticate with the issuer.", + "aborted_issuer_api_error": "There was an error requesting credentials with the issuer. The issuer returned an error.", + "aborted_bad_principal_rp": "The principal provided by the relying party does not match the data Internet Identity has.", + "aborted_no_canister_id": "Internet Identity could not find the canister for the issuer.", + "notice": "We will now let the relying party know there was an issue.", + "you_may_close": "You may now close this page." + } +} diff --git a/src/frontend/src/flows/verifiableCredentials/abortedCredentials.ts b/src/frontend/src/flows/verifiableCredentials/abortedCredentials.ts new file mode 100644 index 0000000000..30b2d178fa --- /dev/null +++ b/src/frontend/src/flows/verifiableCredentials/abortedCredentials.ts @@ -0,0 +1,84 @@ +import { mainWindow } from "$src/components/mainWindow"; +import { toast } from "$src/components/toast"; +import { I18n } from "$src/i18n"; +import { mount, renderPage } from "$src/utils/lit-html"; +import { Chan } from "$src/utils/utils"; +import { TemplateResult, html } from "lit-html"; +import { asyncReplace } from "lit-html/directives/async-replace.js"; + +import copyJson from "./abortedCredentials.json"; + +export type AbortReason = + | "internal_error" + | "auth_failed_ii" + | "auth_failed_issuer" + | "issuer_api_error" + | "bad_principal_rp" + | "no_canister_id"; + +/* A screen telling the user the flow was aborted and giving information + * on why it was aborted and what they can do about it. */ +const abortedCredentialsTemplate = ({ + i18n, + reason, + onAcknowledge, + scrollToTop = false, +}: { + i18n: I18n; + reason: AbortReason; + onAcknowledge: () => void; + /* put the page into view */ + scrollToTop?: boolean; +}): TemplateResult => { + const copy = i18n.i18n(copyJson); + + const didAck = new Chan(false); + const ack = () => { + didAck.send(true); + toast.info(html`${copy.you_may_close}`); + return onAcknowledge(); + }; + + const slot = html` +
window.scrollTo(0, 0)) : undefined} + > +

${copy.title}

+
+

${copy[`aborted_${reason}`]}

+ +

${copy.notice}

+ + + `; + + return mainWindow({ + showFooter: false, + showLogo: false, + slot, + }); +}; + +export const abortedCredentialsPage = renderPage(abortedCredentialsTemplate); +export const abortedCredentials = ({ + reason, +}: { + reason: AbortReason; +}): Promise<"aborted"> => { + return new Promise((resolve) => + abortedCredentialsPage({ + i18n: new I18n(), + reason, + onAcknowledge: () => resolve("aborted"), + scrollToTop: true, + }) + ); +}; diff --git a/src/frontend/src/flows/verifiableCredentials/index.ts b/src/frontend/src/flows/verifiableCredentials/index.ts new file mode 100644 index 0000000000..ceefaacf5b --- /dev/null +++ b/src/frontend/src/flows/verifiableCredentials/index.ts @@ -0,0 +1,415 @@ +import { SignedIdAlias } from "$generated/internet_identity_types"; +import { + CredentialSpec, + IssuedCredentialData, +} from "$generated/vc_issuer_types"; +import { handleLogin } from "$src/components/authenticateBox"; +import { withLoader } from "$src/components/loader"; +import { showMessage } from "$src/components/message"; +import { showSpinner } from "$src/components/spinner"; +import { fetchDelegation } from "$src/flows/authorize/fetchDelegation"; +import { AuthenticatedConnection, Connection } from "$src/utils/iiConnection"; +import { + Delegation, + DelegationChain, + DelegationIdentity, + ECDSAKeyIdentity, +} from "@dfinity/identity"; +import { isNullish } from "@dfinity/utils"; +import { base64url } from "jose"; +import { abortedCredentials } from "./abortedCredentials"; +import { allowCredentials } from "./allowCredentials"; +import { VcVerifiablePresentation, vcProtocol } from "./postMessageInterface"; +import { VcIssuer } from "./vcIssuer"; + +// The "verifiable credentials" approval flow +export const vcFlow = async ({ + connection, +}: { + connection: Connection; +}): Promise => { + const result = await vcProtocol({ + /* Show some spinners while we wait for more data or for an action to complete */ + onProgress: (x) => { + if (x === "waiting") { + return showSpinner({ + message: "Waiting for verification data", + }); + } + + if (x === "verifying") { + return showSpinner({ + message: "Checking verification data", + }); + } + x satisfies never; + }, + + /* How the credentials are actually verified */ + verifyCredentials: (args) => verifyCredentials({ connection, ...args }), + }); + + if (result === "orphan") { + await showMessage({ + message: "No credentials data provided! Wrong URL?", + }); + } + + return await new Promise((_) => { + /* halt forever */ + }); +}; + +type VerifyCredentials = Parameters[0]["verifyCredentials"]; +type VerifyCredentialsArgs = Parameters[0]; + +const verifyCredentials = async ({ + connection, + request: { + credentialSubject: givenP_RP, + issuer: { origin: issuerOrigin, canisterId: issuerCanisterId_ }, + credentialSpec, + }, + rpOrigin, +}: { connection: Connection } & VerifyCredentialsArgs) => { + // Use the issuer canister ID provided by the RP, or look it up + // from the issuer origin if no canister ID was provided. + // NOTE: we do _not_ check the origin's canister ID if a canister ID was provided explicitly. + let issuerCanisterId = issuerCanisterId_?.toText(); + + if (isNullish(issuerCanisterId)) { + const lookedUp = await withLoader(() => + lookupCanister({ origin: issuerOrigin }) + ); + if (lookedUp === "not_found") { + return abortedCredentials({ reason: "no_canister_id" }); + } + + issuerCanisterId = lookedUp.ok; + } + + const vcIssuer = new VcIssuer(issuerCanisterId); + // XXX: We don't check that the language matches the user's language. We need + // to figure what to do UX-wise first. + const consentInfo = await vcIssuer.getConsentMessage({ credentialSpec }); + + if (consentInfo === "error") { + return abortedCredentials({ reason: "auth_failed_issuer" }); + } + + // Ask user to confirm the verification of credentials + const allowed = await allowCredentials({ + relyingOrigin: rpOrigin, + providerOrigin: issuerOrigin, + consentMessage: consentInfo.consent_message, + userNumber: undefined, + }); + if (allowed.tag === "canceled") { + return "aborted"; + } + allowed.tag satisfies "allowed"; + + const userNumber = allowed.userNumber; + + // For the rest of the flow we need to be authenticated, so authenticate + // XXX: this simply breaks for PIN identities + const authResult = await withLoader(() => + handleLogin({ + login: () => connection.login(userNumber), + }) + ); + + if (authResult.tag !== "ok") { + return abortedCredentials({ reason: "auth_failed_ii" }); + } + const authenticatedConnection = authResult.connection; + + // Compute the user's principal on the RP and ensure it matches what the RP sent us + const computedP_RP = await withLoader(() => + authenticatedConnection.getPrincipal({ + origin: rpOrigin, + }) + ); + if (computedP_RP.compareTo(givenP_RP) !== "eq") { + console.error( + [ + "bad principals for user number/origin", + userNumber, + rpOrigin, + computedP_RP.toString(), + givenP_RP.toString(), + ].join(", ") + ); + return abortedCredentials({ reason: "bad_principal_rp" }); + } + + // Ask II to generate the aliases + + const pAliasPending = getAliasCredentials({ + rpOrigin, + issuerOrigin, + authenticatedConnection, + }); + + // Grab the credentials from the issuer + const credentials = await withLoader(async () => { + const pAliasRes = await pAliasPending; + + if ("err" in pAliasRes) { + return { err: pAliasRes.err }; + } + + const pAlias = pAliasRes.ok; + + const issuedCredential = await issueCredential({ + vcIssuer, + issuerOrigin, + issuerAliasCredential: pAlias.issuerAliasCredential, + credentialSpec, + authenticatedConnection, + }); + + if ("err" in issuedCredential) { + return { err: issuedCredential.err }; + } + return [issuedCredential.ok, pAlias] as const; + }); + + if ("err" in credentials) { + return abortedCredentials({ reason: credentials.err }); + } + + const [issuedCredential, pAlias] = credentials; + + // Create the presentation and return it to the RP + return createPresentation({ + issuerCanisterId, + rpAliasCredential: pAlias.rpAliasCredential, + issuedCredential, + }); +}; + +// Lookup the canister by performing a request to the origin and check +// if the server (probably BN) set a header to inform us of the canister ID +const lookupCanister = async ({ + origin, +}: { + origin: string; +}): Promise<{ ok: string } | "not_found"> => { + const response = await fetch( + origin, + // fail on redirects + { + redirect: "error", + method: "HEAD", + // do not send cookies or other credentials + credentials: "omit", + } + ); + + if (response.status !== 200) { + console.error("Bad response when looking for canister ID", response.status); + return "not_found"; + } + + const HEADER_NAME = "x-ic-canister-id"; + const canisterId = response.headers.get(HEADER_NAME); + + if (isNullish(canisterId)) { + console.error( + `Canister ID header '${HEADER_NAME}' was not set on origin ${origin}` + ); + + return "not_found"; + } + + return { ok: canisterId }; +}; + +// Prepare & get aliases +const getAliasCredentials = async ({ + authenticatedConnection, + issuerOrigin, + rpOrigin, +}: { + issuerOrigin: string; + rpOrigin: string; + authenticatedConnection: AuthenticatedConnection; +}): Promise< + | { + ok: { + rpAliasCredential: SignedIdAlias; + issuerAliasCredential: SignedIdAlias; + }; + } + | { err: "internal_error" | "auth_failed_ii" } +> => { + const preparedIdAlias = await authenticatedConnection.prepareIdAlias({ + issuerOrigin, + rpOrigin, + }); + + if ("error" in preparedIdAlias) { + if (preparedIdAlias.error === "internal_error") { + console.error("Could not prepare ID alias"); + return { err: "internal_error" }; + } + + preparedIdAlias.error satisfies "authentication_failed"; + console.error("Could not prepare ID alias: authentication failed"); + return { err: "auth_failed_ii" }; + } + + const result = await authenticatedConnection.getIdAlias({ + preparedIdAlias, + issuerOrigin, + rpOrigin, + }); + + if ("error" in result) { + if (result.error === "internal_error") { + console.error("Could not get ID alias"); + return { err: "internal_error" }; + } + + result.error satisfies "authentication_failed"; + console.error("Could not get ID alias: authentication failed"); + return { err: "auth_failed_ii" }; + } + + const { + rp_id_alias_credential: rpAliasCredential, + issuer_id_alias_credential: issuerAliasCredential, + } = result; + + return { ok: { rpAliasCredential, issuerAliasCredential } }; +}; + +// Contact the issuer to issue the credentials +const issueCredential = async ({ + vcIssuer, + issuerOrigin, + issuerAliasCredential, + credentialSpec, + authenticatedConnection, +}: { + vcIssuer: VcIssuer; + issuerOrigin: string; + issuerAliasCredential: SignedIdAlias; + credentialSpec: CredentialSpec; + authenticatedConnection: AuthenticatedConnection; +}): Promise< + | { ok: IssuedCredentialData } + | { err: "auth_failed_issuer" | "issuer_api_error" } +> => { + const issuerIdentityRes = await authenticateForIssuer({ + authenticatedConnection, + issuerOrigin, + }); + + if ("err" in issuerIdentityRes) { + return { err: issuerIdentityRes.err }; + } + + const issuerIdentity = issuerIdentityRes.ok; + + const args = { + signedIdAlias: issuerAliasCredential, + credentialSpec, + identity: issuerIdentity, + }; + + const preparedCredential = await vcIssuer.prepareCredential(args); + + if (preparedCredential === "error") { + return { err: "issuer_api_error" }; + } + + const issuedCredential = await vcIssuer.getCredential({ + ...args, + preparedCredential, + identity: issuerIdentity, + }); + + if (issuedCredential === "error") { + return { err: "issuer_api_error" }; + } + + return { ok: issuedCredential }; +}; + +// Perform an authentication (delegation, etc) of the user to the issuer +// so that we can contact the issuer authenticated as the user +const authenticateForIssuer = async ({ + authenticatedConnection, + issuerOrigin, +}: { + authenticatedConnection: AuthenticatedConnection; + issuerOrigin: string; +}): Promise<{ ok: DelegationIdentity } | { err: "auth_failed_issuer" }> => { + // This is basically a copy-paste of what we have in the authentication flow + + const tempIdentity: ECDSAKeyIdentity = await ECDSAKeyIdentity.generate({ + extractable: false, + }); + const delegation = await fetchDelegation({ + connection: authenticatedConnection, + derivationOrigin: issuerOrigin, + publicKey: new Uint8Array(tempIdentity.getPublicKey().toDer()), + maxTimeToLive: BigInt(5 * 60 * 1000_000_000) /* 5 minutes */, + }); + + if ("error" in delegation) { + console.error("Could not fetch delegation"); + return { err: "auth_failed_issuer" }; + } + + const [userKey, parsed_signed_delegation] = delegation; + const degs = { + delegation: new Delegation( + parsed_signed_delegation.delegation.pubkey, + parsed_signed_delegation.delegation.expiration, + parsed_signed_delegation.delegation.targets + ), + signature: parsed_signed_delegation.signature, + }; + const delegations = DelegationChain.fromDelegations( + [degs], + Uint8Array.from(userKey) + ); + return { ok: DelegationIdentity.fromDelegation(tempIdentity, delegations) }; +}; + +// Create the final presentation (to be then returned to the RP) +const createPresentation = ({ + issuerCanisterId, + rpAliasCredential, + issuedCredential, +}: { + issuerCanisterId: string; + rpAliasCredential: SignedIdAlias; + issuedCredential: IssuedCredentialData; +}): VcVerifiablePresentation => { + // The simplest JWT header, with no algorithm specified since we don't sign the payload + const headerObj = { typ: "JWT", alg: "none" }; + + const payloadObj = { + iss: `did:icp:${issuerCanisterId}` /* JWT Issuer is set to the issuer's canister ID as per spec */, + vp: { + "@context": "https://www.w3.org/2018/credentials/v1", + type: "VerifiablePresentation", + verifiableCredential: [ + rpAliasCredential.credential_jws satisfies string, + issuedCredential.vc_jws satisfies string, + ] /* spec dictates first the alias creds, then the VC */, + }, + }; + + const header = base64url.encode(JSON.stringify(headerObj)); + const payload = base64url.encode(JSON.stringify(payloadObj)); + + // NOTE: the JWT is not signed, as per the spec + const signature = ""; + + return { verifiablePresentation: [header, payload, signature].join(".") }; +}; diff --git a/src/frontend/src/flows/verifiableCredentials/postMessageInterface.ts b/src/frontend/src/flows/verifiableCredentials/postMessageInterface.ts new file mode 100644 index 0000000000..969c3240ba --- /dev/null +++ b/src/frontend/src/flows/verifiableCredentials/postMessageInterface.ts @@ -0,0 +1,180 @@ +import { ArgumentValue } from "$generated/vc_issuer_types"; +import { toast } from "$src/components/toast"; +import { Principal } from "@dfinity/principal"; +import { isNullish } from "@dfinity/utils"; +import { z } from "zod"; + +// The type of messages that kick start the flow (II -> RP) +export const VcFlowReady = { + jsonrpc: "2.0", + method: "vc-flow-ready", +}; + +const zodPrincipal = z.string().transform((val, ctx) => { + let principal; + try { + principal = Principal.fromText(val); + } catch { + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Not a principal " }); + return z.NEVER; + } + + return principal; +}); + +// Parse & validate a CredentialSpec +const zodCredentialSpec = z + /* The input object */ + .object({ + credentialType: z.string(), + arguments: z.optional( + z.record(z.string(), z.union([z.string(), z.number()])) + ), + }) + /* Transform to make the type easier to use: + * - transform the arguments to whatever the did spec expects + * - work around the JS type gen weirdness for optionals + * XXX: TS needs the type annotation or it gets slightly confused + */ + .transform<{ + credential_type: string; + arguments: [] | [Array<[string, ArgumentValue]>]; + }>(({ credentialType, arguments: args }) => ({ + credential_type: credentialType, + arguments: isNullish(args) ? [] : [fixupArgs(args)], + })); + +/* Convert the JSON map/record into what the did spec expects */ +const fixupArgs = ( + arg: Record +): Array<[string, ArgumentValue]> => { + return Object.entries(arg).map(([k, v]) => [ + k, + typeof v === "string" ? { String: v } : { Int: v }, + ]); +}; + +// The request (RP -> II) +// https://www.jsonrpc.org/specification +// https://github.com/dfinity/internet-identity/blob/vc-mvp/docs/vc-spec.md#identity-provider-api +export const VcFlowRequest = z.object({ + id: z.union([ + z.number(), + z.string(), + ]) /* Slightly lax; in principle jsonrpc does not allow fractional numbers as id */, + jsonrpc: z.literal("2.0"), + method: z.literal("request_credential"), + params: z.object({ + issuer: z.object({ + origin: z + .string() + .url() /* XXX: we limit to URLs, but in practice should even be an origin */, + canisterId: z.optional(zodPrincipal), + }), + credentialSpec: zodCredentialSpec, + credentialSubject: zodPrincipal, + }), +}); + +// The wire format of a VC flow request +export type VcFlowRequestWire = z.input; +export type VcFlowRequest = z.output; + +// The final response concluding the flow (II -> RP) +export type VcResponse = { + id: VcFlowRequest["id"]; + jsonrpc: "2.0"; +} & ( + | { result: VcVerifiablePresentation } + | { error: { version: "1"; code: "UNKNOWN" } } +); + +export type VcVerifiablePresentation = { + verifiablePresentation: string; +}; + +// The protocol, from a "postMessage" req/resp point of view +export const vcProtocol = async ({ + onProgress, + verifyCredentials, +}: { + onProgress: (state: "waiting" | "verifying") => void; + verifyCredentials: (args: { + request: VcFlowRequest["params"]; + rpOrigin: string; + }) => Promise; +}): Promise<"orphan" | "success"> => { + if (window.opener === null) { + // If there's no `window.opener` a user has manually navigated to "/vc-flow". + // Signal that there will never be an authentication request incoming. + return "orphan"; + } + + // Send a message to indicate we're ready. + // NOTE: Because `window.opener.origin` cannot be accessed, this message + // is sent with "*" as the target origin. This is safe as no sensitive + // information is being communicated here. + window.opener.postMessage(VcFlowReady, "*"); + + onProgress("waiting"); + + // Wait for the RP request + const { origin, request } = await waitForRequest(); + const reqId = request.id; + + onProgress("verifying"); + + // Verify the credentials + const result = await verifyCredentials({ + request: request.params, + rpOrigin: origin, + }); + + // Respond to the RP + const content = + result === "aborted" + ? ({ + error: { version: "1", code: "UNKNOWN" }, + } as const) + : { result }; + + window.opener.postMessage( + { + id: reqId, + jsonrpc: "2.0", + ...content, + } satisfies VcResponse, + origin + ); + + return "success"; +}; + +// Wait for a request to kickstart the flow +const waitForRequest = (): Promise<{ + request: VcFlowRequest; + origin: string; +}> => { + return new Promise((resolve) => { + const messageEventHandler = (evnt: MessageEvent) => { + const message: unknown = evnt.data; + const result = VcFlowRequest.safeParse(message); + + if (!result.success) { + const message = `Unexpected error: flow request ` + result.error; + console.error(message); + toast.error(message); + // XXX: here we just wait further assuming the opener might recover + // and send a correct request + return; + } + + window.removeEventListener("message", messageEventHandler); + + resolve({ request: result.data, origin: evnt.origin }); + }; + + // Set up an event listener for receiving messages from the client. + window.addEventListener("message", messageEventHandler); + }); +}; diff --git a/src/frontend/src/flows/verifiableCredentials/vcIssuer.ts b/src/frontend/src/flows/verifiableCredentials/vcIssuer.ts new file mode 100644 index 0000000000..4587d60d48 --- /dev/null +++ b/src/frontend/src/flows/verifiableCredentials/vcIssuer.ts @@ -0,0 +1,109 @@ +import { SignedIdAlias } from "$generated/internet_identity_types"; +import { idlFactory as vc_issuer_idl } from "$generated/vc_issuer_idl"; +import { + CredentialSpec, + Icrc21ConsentInfo, + IssuedCredentialData, + PreparedCredentialData, + _SERVICE, +} from "$generated/vc_issuer_types"; +import { features } from "$src/features"; +import { Actor, ActorSubclass, HttpAgent, Identity } from "@dfinity/agent"; + +import { inferHost } from "$src/utils/iiConnection"; + +// Boilerplate for contacting a canister implementing the Issuer API +export class VcIssuer { + public constructor(readonly canisterId: string) {} + + // Create an actor representing the backend + createActor = async ( + identity?: Identity + ): Promise> => { + const agent = new HttpAgent({ + host: inferHost(), + identity, + }); + + // Only fetch the root key when we're not in prod + if (features.FETCH_ROOT_KEY) { + await agent.fetchRootKey(); + } + const actor = Actor.createActor<_SERVICE>(vc_issuer_idl, { + agent, + canisterId: this.canisterId, + }); + return actor; + }; + + prepareCredential = async ({ + signedIdAlias, + credentialSpec, + identity, + }: { + signedIdAlias: SignedIdAlias; + credentialSpec: CredentialSpec; + identity: Identity; + }): Promise => { + const actor = await this.createActor(identity); + + const result = await actor.prepare_credential({ + signed_id_alias: signedIdAlias, + credential_spec: credentialSpec, + }); + + if ("Err" in result) { + console.error("Could not prepare credential", result.Err); + return "error"; + } + + return result.Ok; + }; + + getCredential = async ({ + signedIdAlias, + preparedCredential, + credentialSpec, + identity, + }: { + signedIdAlias: SignedIdAlias; + credentialSpec: CredentialSpec; + preparedCredential: PreparedCredentialData; + identity: Identity; + }): Promise => { + const actor = await this.createActor(identity); + + const result = await actor.get_credential({ + signed_id_alias: signedIdAlias, + prepared_context: preparedCredential.prepared_context, + credential_spec: credentialSpec, + }); + + if ("Err" in result) { + console.error("Could not get credential", result.Err); + return "error"; + } + + return result.Ok; + }; + + getConsentMessage = async ({ + credentialSpec, + }: { + credentialSpec: CredentialSpec; + }): Promise => { + const actor = await this.createActor(); + + const result = await actor.vc_consent_message({ + preferences: { language: "en-US" }, + credential_spec: credentialSpec, + }); + + if ("Err" in result) { + console.error("Could not get consent message", result.Err); + return "error"; + } + + return result.Ok; + }; +} diff --git a/src/frontend/src/styles/main.css b/src/frontend/src/styles/main.css index 8a5d6b65da..4aa31b9196 100644 --- a/src/frontend/src/styles/main.css +++ b/src/frontend/src/styles/main.css @@ -2774,6 +2774,12 @@ input[type="checkbox"] { image-rendering: pixelated; } +/* A consent message for verifiable credentials */ +.c-consent-message { + font-size: 0.7em; + font-family: monospace; +} + /* Marquee diff --git a/src/frontend/src/utils/iiConnection.ts b/src/frontend/src/utils/iiConnection.ts index c4dd4b55c9..9f87ba1ea0 100644 --- a/src/frontend/src/utils/iiConnection.ts +++ b/src/frontend/src/utils/iiConnection.ts @@ -12,8 +12,10 @@ import { DeviceKey, FrontendHostname, GetDelegationResponse, + IdAliasCredentials, IdentityAnchorInfo, KeyType, + PreparedIdAlias, PublicKey, Purpose, RegisterResponse, @@ -580,6 +582,84 @@ export class AuthenticatedConnection extends Connection { return { error: e }; } }; + + prepareIdAlias = async ({ + issuerOrigin: issuerOrigin_, + rpOrigin: rpOrigin_, + }: { + issuerOrigin: string; + rpOrigin: string; + }): Promise< + | PreparedIdAlias + | { error: "internal_error" } + | { error: "authentication_failed" } + > => { + const issuerOrigin = remapToLegacyDomain(issuerOrigin_); + const rpOrigin = remapToLegacyDomain(rpOrigin_); + const actor = await this.getActor(); + const userNumber = this.userNumber; + const [result] = await actor.prepare_id_alias({ + issuer: issuerOrigin, + relying_party: rpOrigin, + identity_number: userNumber, + }); + + if (isNullish(result)) { + console.error("Canister did not send a response"); + return { error: "internal_error" }; + } + + if ("authentication_failed" in result) { + console.error( + ["Authentication failed", result.authentication_failed].join(": ") + ); + return { error: "authentication_failed" }; + } + + return result.ok; + }; + + getIdAlias = async ({ + preparedIdAlias, + issuerOrigin: issuerOrigin_, + rpOrigin: rpOrigin_, + }: { + preparedIdAlias: PreparedIdAlias; + issuerOrigin: string; + rpOrigin: string; + }): Promise< + | IdAliasCredentials + | { error: "internal_error" } + | { error: "authentication_failed" } + > => { + const issuerOrigin = remapToLegacyDomain(issuerOrigin_); + const rpOrigin = remapToLegacyDomain(rpOrigin_); + const actor = await this.getActor(); + const userNumber = this.userNumber; + + const [result] = await actor.get_id_alias({ + issuer: issuerOrigin, + relying_party: rpOrigin, + identity_number: userNumber, + ...preparedIdAlias, + }); + + if (isNullish(result)) { + console.error("Canister did not send a response"); + return { error: "internal_error" }; + } + + if ("no_such_credentials" in result) { + console.error(["No credentials", result.no_such_credentials].join(": ")); + return { error: "internal_error" }; + } + + if ("authentication_failed" in result) { + return { error: "authentication_failed" }; + } + + return result.ok; + }; } // Reads the "origin" used to infer what domain a FIDO device is available on. diff --git a/src/frontend/src/vc-flow.ts b/src/frontend/src/vc-flow.ts new file mode 100644 index 0000000000..2358ba3388 --- /dev/null +++ b/src/frontend/src/vc-flow.ts @@ -0,0 +1,4 @@ +import { vcFlow } from "./flows/verifiableCredentials"; +import { createSpa } from "./spa"; + +void createSpa((connection) => vcFlow({ connection })); diff --git a/src/frontend/vc-flow/index.html b/src/frontend/vc-flow/index.html new file mode 100644 index 0000000000..7278cc2e4b --- /dev/null +++ b/src/frontend/vc-flow/index.html @@ -0,0 +1,16 @@ + + + + + + + Internet Identity + + + + + +
+
+ + diff --git a/src/showcase/src/pages/[page].astro b/src/showcase/src/pages/[page].astro index 473612fa13..455f3f4ef2 100644 --- a/src/showcase/src/pages/[page].astro +++ b/src/showcase/src/pages/[page].astro @@ -55,6 +55,7 @@ export const iiPageNames = [ "showSpinner", "addDeviceSuccess", "allowCredentials", + "abortedCredentialsInternalError", ]; export function getStaticPaths() { diff --git a/src/showcase/src/showcase.ts b/src/showcase/src/showcase.ts index 7dcaf84dfe..802b902225 100644 --- a/src/showcase/src/showcase.ts +++ b/src/showcase/src/showcase.ts @@ -58,6 +58,7 @@ import { NonEmptyArray } from "$src/utils/utils"; import { TemplateResult, html, render } from "lit-html"; import { asyncReplace } from "lit-html/directives/async-replace.js"; +import { abortedCredentialsPage } from "$src/flows/verifiableCredentials/abortedCredentials"; import { allowCredentialsPage } from "$src/flows/verifiableCredentials/allowCredentials"; const identityBackground = loadIdentityBackground(); @@ -645,6 +646,12 @@ Credential that states that the holder is employed by the ACME Inc at the time o onAllow: () => toast.info(html`Allowed`), onCancel: () => toast.info(html`Canceled`), }), + abortedCredentialsInternalError: () => + abortedCredentialsPage({ + i18n, + reason: "internal_error", + onAcknowledge: () => toast.info(html`Acked`), + }), }; const showcase: TemplateResult = html` diff --git a/vite.config.ts b/vite.config.ts index 4670fc3ca9..bcd0b38af6 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -45,7 +45,11 @@ export default defineConfig(({ mode }: UserConfig): UserConfig => { rollupOptions: { // Bundle only english words in bip39. external: /.*\/wordlists\/(?!english).*\.json/, - input: ["src/frontend/index.html", "src/frontend/faq.html"], + input: [ + "src/frontend/index.html", + "src/frontend/faq.html", + "src/frontend/vc-flow/index.html", + ], output: { entryFileNames: `[name].js`, // II canister only supports resources that contains a single dot in their filenames. qr-creator.js.gz = ok. qr-creator.min.js.gz not ok. qr-creator.es6.min.js.gz no ok. @@ -70,6 +74,12 @@ export default defineConfig(({ mode }: UserConfig): UserConfig => { hosts: ["nice-name.com"], canisterName: "test_app", }, + { + /* nice for deploying locally without having + * to look up & type the canister ID */ + hosts: ["issuer.localhost:5173"], + canisterName: "issuer", + }, ...(process.env.NO_HOT_RELOAD === "1" ? [ { diff --git a/vite.plugins.ts b/vite.plugins.ts index 0516b6ef13..59ab13172d 100644 --- a/vite.plugins.ts +++ b/vite.plugins.ts @@ -110,6 +110,16 @@ export const replicaForwardPlugin = ({ res.statusCode = 500; res.end("Replica forwarding failed: " + err.message); }); + + /* Add a 'x-ic-canister-id' header like the BNs do */ + proxy.on("proxyRes", (res) => { + res.headers["x-ic-canister-id"] = canisterId; + + // Ensure the browser accepts the response + res.headers["access-control-allow-origin"] = "*"; + res.headers["access-control-expose-headers"] = "*"; + res.headers["access-control-allow-headers"] = "*"; + }); }; const matchingRule = forwardRules.find((rule) => From f4c8c475acc4a877dd86178c6f5b2473c5dd6a04 Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Mon, 4 Dec 2023 10:23:47 +0100 Subject: [PATCH 3/6] Add verifiable credentials support in test-app --- demos/test-app/package-lock.json | 1441 +++++++++++++++++++- demos/test-app/package.json | 8 +- demos/test-app/src/index.html | 24 +- demos/test-app/src/{index.ts => index.tsx} | 183 +++ demos/test-app/src/main.css | 8 + 5 files changed, 1648 insertions(+), 16 deletions(-) rename demos/test-app/src/{index.ts => index.tsx} (68%) diff --git a/demos/test-app/package-lock.json b/demos/test-app/package-lock.json index 8923345080..9ff60c51d4 100644 --- a/demos/test-app/package-lock.json +++ b/demos/test-app/package-lock.json @@ -12,14 +12,360 @@ "@dfinity/candid": "^0.19.3", "@dfinity/identity": "^0.19.3", "@dfinity/principal": "^0.19.3", - "buffer": "^6.0.3" + "buffer": "^6.0.3", + "jose": "^5.1.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": { "@types/node": "^20.10.1", + "@types/react": "^18.2.38", + "@types/react-dom": "^18.2.17", + "@vitejs/plugin-react": "^4.2.0", "typescript": "5.2.2", "vite": "^4.3.9" } }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", + "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.5", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@dfinity/agent": { "version": "0.19.3", "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-0.19.3.tgz", @@ -431,6 +777,54 @@ "node": ">=12" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@noble/hashes": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", @@ -481,6 +875,47 @@ "node": ">=10.12.0" } }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, "node_modules/@types/node": { "version": "20.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.1.tgz", @@ -490,6 +925,69 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/prop-types": { + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.2.39", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz", + "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.17", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz", + "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "dev": true + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz", + "integrity": "sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.3", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.4", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/asn1js": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", @@ -579,6 +1077,38 @@ "ieee754": "^1.1.13" } }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -602,16 +1132,100 @@ "ieee754": "^1.2.1" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001565", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", + "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/delimit-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", "integrity": "sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs=" }, + "node_modules/electron-to-chromium": { + "version": "1.4.597", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.597.tgz", + "integrity": "sha512-0XOQNqHhg2YgRVRUrS4M4vWjFCFIP2ETXcXe/0KIQBjXE9Cpy+tgzzYfuq6HGai3hWq0YywtG+5XK8fyG08EjA==", + "dev": true + }, "node_modules/esbuild": { "version": "0.17.18", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz", @@ -649,6 +1263,24 @@ "@esbuild/win32-x64": "0.17.18" } }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -663,6 +1295,33 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/idb": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", @@ -700,6 +1359,31 @@ "node": ">=10" } }, + "node_modules/jose": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.1.2.tgz", + "integrity": "sha512-X7TOC/d8KPvx4wPUuLHVgTSdoWw0UW5TQOUwhvCvj+ZPfsf9vUPhhksYPjNBWVGPQ/6yd/JrL1gQxBnIDwYdFg==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/json-text-sequence": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", @@ -708,6 +1392,44 @@ "delimit-stream": "0.1.0" } }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/nanoid": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", @@ -726,6 +1448,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -775,7 +1503,39 @@ "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", "peer": true, "engines": { - "node": ">=6.0.0" + "node": ">=6.0.0" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/readable-stream": { @@ -826,6 +1586,23 @@ } ] }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/simple-cbor": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", @@ -848,6 +1625,27 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -878,6 +1676,36 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -943,9 +1771,264 @@ "pvtsutils": "^1.3.2", "tslib": "^2.4.0" } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true } }, "dependencies": { + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true + }, + "@babel/core": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", + "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.5", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + } + }, + "@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "dev": true, + "requires": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" + } + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "dev": true + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, "@dfinity/agent": { "version": "0.19.3", "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-0.19.3.tgz", @@ -1143,6 +2226,45 @@ "dev": true, "optional": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "@noble/hashes": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", @@ -1181,6 +2303,47 @@ "webcrypto-core": "^1.7.7" } }, + "@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, "@types/node": { "version": "20.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.1.tgz", @@ -1190,6 +2353,60 @@ "undici-types": "~5.26.4" } }, + "@types/prop-types": { + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", + "dev": true + }, + "@types/react": { + "version": "18.2.39", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz", + "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.2.17", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz", + "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "dev": true + }, + "@vitejs/plugin-react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz", + "integrity": "sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==", + "dev": true, + "requires": { + "@babel/core": "^7.23.3", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.4", + "react-refresh": "^0.14.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "asn1js": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", @@ -1241,6 +2458,18 @@ } } }, + "browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + } + }, "buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -1250,16 +2479,75 @@ "ieee754": "^1.2.1" } }, + "caniuse-lite": { + "version": "1.0.30001565", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", + "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, "delimit-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", "integrity": "sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs=" }, + "electron-to-chromium": { + "version": "1.4.597", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.597.tgz", + "integrity": "sha512-0XOQNqHhg2YgRVRUrS4M4vWjFCFIP2ETXcXe/0KIQBjXE9Cpy+tgzzYfuq6HGai3hWq0YywtG+5XK8fyG08EjA==", + "dev": true + }, "esbuild": { "version": "0.17.18", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz", @@ -1290,6 +2578,18 @@ "@esbuild/win32-x64": "0.17.18" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, "fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -1297,6 +2597,24 @@ "dev": true, "optional": true }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, "idb": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", @@ -1317,6 +2635,22 @@ "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==" }, + "jose": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.1.2.tgz", + "integrity": "sha512-X7TOC/d8KPvx4wPUuLHVgTSdoWw0UW5TQOUwhvCvj+ZPfsf9vUPhhksYPjNBWVGPQ/6yd/JrL1gQxBnIDwYdFg==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-text-sequence": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", @@ -1325,12 +2659,47 @@ "delimit-stream": "0.1.0" } }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "nanoid": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -1363,6 +2732,29 @@ "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", "peer": true }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -1387,6 +2779,20 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, "simple-cbor": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", @@ -1406,6 +2812,21 @@ "safe-buffer": "~5.2.0" } }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, "tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -1429,6 +2850,16 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1458,6 +2889,12 @@ "pvtsutils": "^1.3.2", "tslib": "^2.4.0" } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true } } } diff --git a/demos/test-app/package.json b/demos/test-app/package.json index faba077435..2b9390b8d2 100644 --- a/demos/test-app/package.json +++ b/demos/test-app/package.json @@ -7,7 +7,10 @@ "@dfinity/candid": "^0.19.3", "@dfinity/identity": "^0.19.3", "@dfinity/principal": "^0.19.3", - "buffer": "^6.0.3" + "buffer": "^6.0.3", + "jose": "^5.1.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "scripts": { "dev": "vite --config ./vite.config.ts", @@ -17,6 +20,9 @@ }, "devDependencies": { "@types/node": "^20.10.1", + "@types/react": "^18.2.38", + "@types/react-dom": "^18.2.17", + "@vitejs/plugin-react": "^4.2.0", "typescript": "5.2.2", "vite": "^4.3.9" } diff --git a/demos/test-app/src/index.html b/demos/test-app/src/index.html index 104f724d5a..64222b835f 100644 --- a/demos/test-app/src/index.html +++ b/demos/test-app/src/index.html @@ -1,6 +1,6 @@ - +