diff --git a/src/frontend/src/flows/verifiableCredentials/index.ts b/src/frontend/src/flows/verifiableCredentials/index.ts index a1c2ea24d3..210932632e 100644 --- a/src/frontend/src/flows/verifiableCredentials/index.ts +++ b/src/frontend/src/flows/verifiableCredentials/index.ts @@ -15,16 +15,19 @@ import { VcIssuer } from "./vcIssuer"; const dapps = getDapps(); +// XXX the VC flow currently only supports the happy path const giveUp = async (message?: string): Promise => { - console.error("Nope " + message); - toast.error("Nope " + message); + console.error(message); + toast.error("Error was encountered, giving up: " + message); return await new Promise((_) => { - /* halt */ + /* halt forever */ }); }; +// The "verifiable credentials" approval flow export const vcFlow = async ({ connection }: { connection: Connection }) => { await vcProtocol({ + /* Show some spinners while we wait for more data or for an action to complete */ onProgress: (x) => { if (x === "waiting") { return showSpinner({ @@ -40,7 +43,14 @@ export const vcFlow = async ({ connection }: { connection: Connection }) => { x satisfies never; }, - verifyCredentials: async ({ request, rpOrigin }) => { + /* How the credentials are actually verified */ + verifyCredentials: async ({ + request: { + credentialSubject: givenP_RP, + issuer: { issuerOrigin, credentialId }, + }, + rpOrigin, + }) => { // Go through the login flow, potentially creating an anchor. const { connection: authenticatedConnection } = await authenticateBox({ connection, @@ -48,8 +58,7 @@ export const vcFlow = async ({ connection }: { connection: Connection }) => { templates: authnTemplateManage({ dapps }), }); - const { issuerOrigin } = request.issuer; - + // Compute the user's principal on the RP and ensure it matches what the RP sent us const computedP_RP = await authenticatedConnection.getPrincipal({ origin: rpOrigin, }); @@ -59,8 +68,6 @@ export const vcFlow = async ({ connection }: { connection: Connection }) => { issuerOrigin, authenticatedConnection, }); - - const givenP_RP = request.credentialSubject; if (computedP_RP.compareTo(givenP_RP) !== "eq") { return giveUp( [ @@ -71,6 +78,7 @@ export const vcFlow = async ({ connection }: { connection: Connection }) => { ); } + // Ask user to confirm the verification of credentials const allowed = await allow({ relyingOrigin: rpOrigin, providerOrigin: issuerOrigin, @@ -80,6 +88,7 @@ export const vcFlow = async ({ connection }: { connection: Connection }) => { } allowed satisfies "allowed"; + // Grab the credentials from the issuer const [issuedCredential, pAlias] = await withLoader(async () => { const issuerCanisterId = lookupCanister({ origin: issuerOrigin }); const pAlias = await pAliasPending; @@ -87,11 +96,12 @@ export const vcFlow = async ({ connection }: { connection: Connection }) => { const issuedCredential = await issueCredential({ issuerCanisterId, issuerAliasCredential: pAlias.issuerAliasCredential, - credentialId: request.issuer.credentialId, + credentialId, }); return [issuedCredential, pAlias]; }); + // Create the presentation and return it to the RP return createPresentation({ rpAliasCredential: pAlias.rpAliasCredential, issuedCredential, @@ -100,9 +110,11 @@ export const vcFlow = async ({ connection }: { connection: Connection }) => { }); }; +const issuerCanisterId: string = "bw4dl-smaaa-aaaaa-qaacq-cai"; + const lookupCanister = ({ origin: _origin }: { origin: string }): string => { // XXX: my locally installed issuer - return "bw4dl-smaaa-aaaaa-qaacq-cai"; + return issuerCanisterId; }; const getAliasCredentials = async ({ @@ -184,20 +196,18 @@ const createPresentation = ({ rpAliasCredential: SignedIdAlias; issuedCredential: IssuedCredentialData; }): VcVerifiablePresentation["result"] => { - // TODO: figure out if this is all that's needed + // The simplest JWT header, with no algorithm specified since we don't sign the payload const headerObj = { typ: "JWT", alg: "none" }; - // TODO: figure out who's the issue - // TODO: does the order of credentials matter? const payloadObj = { - iss: "did:icp:bephe-imsta-66z5n-f555b-qqtmh-uom5q-gnr44-ukpid-6oaoe-b5muo-jae", + 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 */, }, };