diff --git a/src/frontend/src/flows/verifiableCredentials/allowCredentials.json b/src/frontend/src/flows/verifiableCredentials/allowCredentials.json new file mode 100644 index 0000000000..3abd794094 --- /dev/null +++ b/src/frontend/src/flows/verifiableCredentials/allowCredentials.json @@ -0,0 +1,9 @@ +{ + "en": { + "title": "Credential Access Request", + "allow_start": "Allow verifying credential", + "allow_sep_with": "with", + "cancel": "Cancel", + "allow": "Allow" + } +} diff --git a/src/frontend/src/flows/verifiableCredentials/allowCredentials.ts b/src/frontend/src/flows/verifiableCredentials/allowCredentials.ts new file mode 100644 index 0000000000..4a88d6f890 --- /dev/null +++ b/src/frontend/src/flows/verifiableCredentials/allowCredentials.ts @@ -0,0 +1,109 @@ +import { mkAnchorInput } from "$src/components/anchorInput"; +import { mainWindow } from "$src/components/mainWindow"; +import { I18n } from "$src/i18n"; +import { mount, renderPage } from "$src/utils/lit-html"; +import { TemplateResult, html } from "lit-html"; + +import copyJson from "./allowCredentials.json"; + +/* A screen prompting the user to allow (or cancel) issuing verified + * credentials */ + +const allowCredentialsTemplate = ({ + i18n, + relyingOrigin, + providerOrigin, + consentMessage, + userNumber, + onAllow, + onCancel, + scrollToTop = false, +}: { + i18n: I18n; + relyingOrigin: string; + providerOrigin: string; + consentMessage: string; + userNumber?: bigint; + onAllow: (userNumber: bigint) => void; + onCancel: () => void; + /* put the page into view */ + scrollToTop?: boolean; +}): TemplateResult => { + const copy = i18n.i18n(copyJson); + const anchorInput = mkAnchorInput({ + userNumber, + onSubmit: (userNumber) => onAllow(userNumber), + }); + + const slot = html` +
window.scrollTo(0, 0)) : undefined} + > +

${copy.title}

+
+ + ${anchorInput.template} + +

+ ${copy.allow_start} + ${providerOrigin} ${copy.allow_sep_with} + ${relyingOrigin}? +

+ +
+ +
+ +
+ + +
+ `; + + return mainWindow({ + showFooter: false, + showLogo: false, + slot, + }); +}; + +export const allowCredentialsPage = renderPage(allowCredentialsTemplate); + +// Prompt to allow verifying credentials +export const allowCredentials = ({ + relyingOrigin, + providerOrigin, + consentMessage, + userNumber, +}: { + relyingOrigin: string; + providerOrigin: string; + consentMessage: string; + userNumber?: bigint; +}): Promise<{ tag: "allowed"; userNumber: bigint } | { tag: "canceled" }> => { + return new Promise((resolve) => + allowCredentialsPage({ + i18n: new I18n(), + relyingOrigin, + providerOrigin, + consentMessage, + userNumber, + onAllow: (userNumber) => resolve({ tag: "allowed", userNumber }), + onCancel: () => resolve({ tag: "canceled" }), + scrollToTop: true, + }) + ); +}; diff --git a/src/showcase/src/pages/[page].astro b/src/showcase/src/pages/[page].astro index 6ccd26c815..473612fa13 100644 --- a/src/showcase/src/pages/[page].astro +++ b/src/showcase/src/pages/[page].astro @@ -54,6 +54,7 @@ export const iiPageNames = [ "showMessage", "showSpinner", "addDeviceSuccess", + "allowCredentials", ]; export function getStaticPaths() { diff --git a/src/showcase/src/showcase.ts b/src/showcase/src/showcase.ts index 9eafee9e13..7dcaf84dfe 100644 --- a/src/showcase/src/showcase.ts +++ b/src/showcase/src/showcase.ts @@ -58,6 +58,8 @@ import { NonEmptyArray } from "$src/utils/utils"; import { TemplateResult, html, render } from "lit-html"; import { asyncReplace } from "lit-html/directives/async-replace.js"; +import { allowCredentialsPage } from "$src/flows/verifiableCredentials/allowCredentials"; + const identityBackground = loadIdentityBackground(); const userNumber = BigInt(10000); @@ -630,6 +632,19 @@ export const iiPages: Record void> = { deviceAlias: chromeDevice.alias, onContinue: () => console.log("Continue"), }), + allowCredentials: () => + allowCredentialsPage({ + i18n, + relyingOrigin: "https://oc.app", + providerOrigin: "https://nns.ic0.app", + consentMessage: ` +# ACME Inc Employment Credential + +Credential that states that the holder is employed by the ACME Inc at the time of issuance. + `, + onAllow: () => toast.info(html`Allowed`), + onCancel: () => toast.info(html`Canceled`), + }), }; const showcase: TemplateResult = html`