diff --git a/src/frontend/src/lib/stores/authorization.store.ts b/src/frontend/src/lib/stores/authorization.store.ts index 0a29398e52..2b70ea6d19 100644 --- a/src/frontend/src/lib/stores/authorization.store.ts +++ b/src/frontend/src/lib/stores/authorization.store.ts @@ -5,7 +5,7 @@ export type AuthorizationContext = { }; export type Authorized = { - accountNumber: bigint | undefined; + accountNumberPromise: Promise; }; const contextInternal = writable(); @@ -16,9 +16,11 @@ export const authorizationStore = { setContext: (effectiveOrigin: string): void => { contextInternal.set({ effectiveOrigin }); }, - /** Called by the UI when the user authorizes with a specific account. */ - authorize: (accountNumber: bigint | undefined): void => { - authorizedInternal.set({ accountNumber }); + /** Called by the UI when the user authorizes with a specific account. + * Accepts a promise so the animation can start immediately while the + * account number resolves asynchronously. */ + authorize: (accountNumberPromise: Promise): void => { + authorizedInternal.set({ accountNumberPromise: accountNumberPromise }); }, subscribe: contextInternal.subscribe, }; diff --git a/src/frontend/src/lib/stores/channelHandlers/attributes.ts b/src/frontend/src/lib/stores/channelHandlers/attributes.ts index 2d938d32e8..79cdcaf2b3 100644 --- a/src/frontend/src/lib/stores/channelHandlers/attributes.ts +++ b/src/frontend/src/lib/stores/channelHandlers/attributes.ts @@ -189,7 +189,7 @@ export const handleIcrc3Attributes = } // Wait for the user to authorize before serving attributes. - await waitForStore(authorizedStore); + const { accountNumberPromise } = await waitForStore(authorizedStore); const authenticated = await waitForStore(authenticationStore); // Validate the derivation origin if provided, same as delegation handler. @@ -230,10 +230,11 @@ export const handleIcrc3Attributes = const attributeKeys = implicitKeys.filter((key) => availableKeys.has(key)); try { + const accountNumber = await accountNumberPromise; const { message } = await authenticated.actor .prepare_icrc3_attributes({ origin, - account_number: [], + account_number: accountNumber !== undefined ? [accountNumber] : [], identity_number: authenticated.identityNumber, attributes: attributeKeys.map((key) => ({ key, @@ -248,7 +249,7 @@ export const handleIcrc3Attributes = authenticated.actor .get_icrc3_attributes({ origin, - account_number: [], + account_number: accountNumber !== undefined ? [accountNumber] : [], identity_number: authenticated.identityNumber, message, }) diff --git a/src/frontend/src/lib/stores/channelHandlers/delegation.ts b/src/frontend/src/lib/stores/channelHandlers/delegation.ts index 0471b150a1..52946671b7 100644 --- a/src/frontend/src/lib/stores/channelHandlers/delegation.ts +++ b/src/frontend/src/lib/stores/channelHandlers/delegation.ts @@ -70,11 +70,14 @@ export const handleDelegationRequest = // Authorization is the commit point — the user may switch identities // freely before this. Once authorized, the UI is no longer needed. - const { accountNumber } = await waitForStore(authorizedStore); + const authorized = await waitForStore(authorizedStore); // Read the identity *after* authorization so we capture whichever // identity the user settled on (they may have switched mid-flow). - const { identityNumber, actor } = await waitForStore(authenticationStore); + const [accountNumber, { identityNumber, actor }] = await Promise.all([ + authorized.accountNumberPromise, + waitForStore(authenticationStore), + ]); const sessionPublicKey = new Uint8Array(params.publicKey.toDer()); diff --git a/src/frontend/src/lib/utils/reroute.ts b/src/frontend/src/lib/utils/reroute.ts index 9d3d893828..c9eb901ee0 100644 --- a/src/frontend/src/lib/utils/reroute.ts +++ b/src/frontend/src/lib/utils/reroute.ts @@ -15,10 +15,6 @@ export const reroute: Reroute = ({ url }) => { if (url.hash === "#authorize") { return get(DISCOVERABLE_PASSKEY_FLOW) ? "/authorize" : "/legacy/authorize"; } - // Load direct authorization page instead if openid param is present - if (url.pathname === "/authorize" && url.searchParams.has("openid")) { - return `/init-openid-authorize`; - } if (url.pathname === "/") { return get(DISCOVERABLE_PASSKEY_FLOW) || building ? "/" : "/legacy"; } diff --git a/src/frontend/src/routes/(new-styling)/(channel)/+layout.svelte b/src/frontend/src/routes/(new-styling)/(channel)/+layout.svelte deleted file mode 100644 index f0943aa50e..0000000000 --- a/src/frontend/src/routes/(new-styling)/(channel)/+layout.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - -{#if $channelErrorStore !== undefined && $channelErrorStore !== "unsupported-browser"} - -{:else if $authorizationStore !== undefined} - {@render children()} -{/if} diff --git a/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+layout.svelte b/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+layout.svelte deleted file mode 100644 index 37102509e8..0000000000 --- a/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+layout.svelte +++ /dev/null @@ -1,149 +0,0 @@ - - -{#snippet upgradePanel()} -
-
- -

- {#if dapp?.name !== undefined} - {@const application = dapp.name} - {$t`${application} has moved to the new Internet Identity`} - {:else} - {$t`This app has moved to the new Internet Identity`} - {/if} -

-

- Still using an identity number? -

- - -
-
- - -
-
- {#if isUpgrading} - (isUpgrading = false)}> - { - handleError(error); - isUpgrading = false; - }} - /> - - {/if} -{/snippet} - -
-
- {#if $GUIDED_UPGRADE || $MIN_GUIDED_UPGRADE} - {@render upgradePanel()} - {/if} - - {@render children()} - -
-
diff --git a/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+page.ts b/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+page.ts deleted file mode 100644 index 94d8b5c3de..0000000000 --- a/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+page.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { get } from "svelte/store"; -import { lastUsedIdentitiesStore } from "$lib/stores/last-used-identities.store"; -import { redirect } from "@sveltejs/kit"; -import { PageLoad } from "./$types"; - -let firstVisit = true; - -export const load: PageLoad = ({ url }) => { - const lastUsedIdentityAvailable = - get(lastUsedIdentitiesStore).selected !== undefined; - - if (firstVisit) { - firstVisit = false; - - if (lastUsedIdentityAvailable) { - // Copy and modify URL path to retain other data e.g. search params - const next = new URL(url); - next.pathname = "/authorize/continue"; - throw redirect(307, next); - } - } -}; diff --git a/src/frontend/src/routes/(new-styling)/(channel)/authorize/+layout.svelte b/src/frontend/src/routes/(new-styling)/(channel)/authorize/+layout.svelte deleted file mode 100644 index e36e90c2a6..0000000000 --- a/src/frontend/src/routes/(new-styling)/(channel)/authorize/+layout.svelte +++ /dev/null @@ -1,283 +0,0 @@ - - -
-
-
- {#if selectedIdentity !== undefined} - - {#if isIdentityPopoverOpen} - { - if (isAuthenticating) { - return; - } - isIdentityPopoverOpen = false; - }} - direction="down" - align="end" - distance="0.75rem" - class="!bg-bg-primary" - > - { - await handleSignIn(identityNumber); - await authorizeDefault(); - }} - onUseAnotherIdentity={() => { - isIdentityPopoverOpen = false; - isAuthDialogOpen = true; - }} - onManageIdentity={async () => { - isIdentityPopoverOpen = false; - window.open("/manage", "_blank"); - }} - onManageIdentities={() => { - isIdentityPopoverOpen = false; - isManageIdentitiesDialogOpen = true; - }} - onError={(error) => { - isIdentityPopoverOpen = false; - handleError(error); - }} - onClose={() => (isIdentityPopoverOpen = false)} - /> - - {/if} - {#if isAuthDialogOpen} - { - if (isAuthenticating) { - return; - } - isAuthDialogOpen = false; - }} - > - { - isAuthDialogOpen = false; - handleError(error); - }} - withinDialog - > -

- {$t`Sign in`} -

-

- {$t`Choose method to continue`} -

-
-
- {/if} - {/if} -
-
- {#if $authorizedStore !== undefined} - {#await waitFor(10000)} -
- -

- {$t`Redirecting to the app`} -

-
- {:then _} - - - - -

- {$t`Authentication successful`} -

-

- {$t`You may close this page.`} -

- -
- {/await} - {:else} - {@render children()} - {/if} -
-
-
-
- -{#if isManageIdentitiesDialogOpen} - (isManageIdentitiesDialogOpen = false)}> - - -{/if} diff --git a/src/frontend/src/routes/(new-styling)/(channel)/authorize/upgrade-success/+layout.ts b/src/frontend/src/routes/(new-styling)/(channel)/authorize/upgrade-success/+layout.ts deleted file mode 100644 index 0f8a733b0e..0000000000 --- a/src/frontend/src/routes/(new-styling)/(channel)/authorize/upgrade-success/+layout.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { LayoutLoad } from "./$types"; -import { redirect } from "@sveltejs/kit"; -import { get } from "svelte/store"; -import { isAuthenticatedStore } from "$lib/stores/authentication.store"; - -export const load: LayoutLoad = () => { - // Go back to /authorize if not authenticated - if (!get(isAuthenticatedStore)) { - throw redirect(307, "/authorize"); - } -}; diff --git a/src/frontend/src/routes/(new-styling)/(pending-channel)/+layout.svelte b/src/frontend/src/routes/(new-styling)/(pending-channel)/+layout.svelte deleted file mode 100644 index 408e996e20..0000000000 --- a/src/frontend/src/routes/(new-styling)/(pending-channel)/+layout.svelte +++ /dev/null @@ -1,21 +0,0 @@ - - -{#if $channelErrorStore !== undefined && $channelErrorStore !== "unsupported-browser"} - -{:else if $channelStore !== undefined} - {@render children()} -{/if} diff --git a/src/frontend/src/routes/(new-styling)/(pending-channel)/init-openid-authorize/+page.svelte b/src/frontend/src/routes/(new-styling)/(pending-channel)/init-openid-authorize/+page.svelte deleted file mode 100644 index 61a95ce675..0000000000 --- a/src/frontend/src/routes/(new-styling)/(pending-channel)/init-openid-authorize/+page.svelte +++ /dev/null @@ -1,40 +0,0 @@ - diff --git a/src/frontend/src/routes/(new-styling)/(pending-channel)/init-openid-authorize/+page.ts b/src/frontend/src/routes/(new-styling)/(pending-channel)/init-openid-authorize/+page.ts deleted file mode 100644 index e4964d252b..0000000000 --- a/src/frontend/src/routes/(new-styling)/(pending-channel)/init-openid-authorize/+page.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { redirect } from "@sveltejs/kit"; -import { backendCanisterConfig } from "$lib/globals"; -import { PageLoad } from "./$types"; - -export const load: PageLoad = ({ url }) => { - const issuer = url.searchParams.get("openid"); - const config = backendCanisterConfig.openid_configs[0]?.find( - (config) => issuer !== undefined && config.issuer === issuer, - ); - if (config === undefined) { - // If OpenID config can't be found, fallback to ICRC-29 authorization flow - throw redirect(307, "/authorize"); - } - return { config }; -}; diff --git a/src/frontend/src/routes/(new-styling)/(resuming-channel)/+layout.svelte b/src/frontend/src/routes/(new-styling)/(resuming-channel)/+layout.svelte deleted file mode 100644 index 4b0ccefdb7..0000000000 --- a/src/frontend/src/routes/(new-styling)/(resuming-channel)/+layout.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - -{#if $channelStore !== undefined} - {@render children()} -{:else if $channelErrorStore !== undefined || pendingChannelOrigin === null} - -{/if} diff --git a/src/frontend/src/routes/(new-styling)/(resuming-channel)/resume-openid-authorize/+page.svelte b/src/frontend/src/routes/(new-styling)/(resuming-channel)/resume-openid-authorize/+page.svelte deleted file mode 100644 index 073978bb15..0000000000 --- a/src/frontend/src/routes/(new-styling)/(resuming-channel)/resume-openid-authorize/+page.svelte +++ /dev/null @@ -1,159 +0,0 @@ - - -
- {#if animateTransitions} -
- {#if dapp?.logoSrc !== undefined} -
- - - - - - - {$t`${dapp.name} -
- {:else} - - - - - - - {/if} -

- {$t`Signing in securely`} -

- - {$t`Powered by`} - - {window.location.hostname} - -
- {/if} -
diff --git a/src/frontend/src/routes/(new-styling)/authorize/+layout.svelte b/src/frontend/src/routes/(new-styling)/authorize/+layout.svelte new file mode 100644 index 0000000000..d0e96122b4 --- /dev/null +++ b/src/frontend/src/routes/(new-styling)/authorize/+layout.svelte @@ -0,0 +1,321 @@ + + +{#if hasError} + +{:else if isReady} +
+ {#if showHeaderFooter} +
+
+ {#if selectedIdentity !== undefined} + + {#if isIdentityPopoverOpen} + { + if (isAuthenticating) { + return; + } + isIdentityPopoverOpen = false; + }} + direction="down" + align="end" + distance="0.75rem" + class="!bg-bg-primary" + > + { + await handleSignIn(identityNumber); + await authorizeDefault(); + }} + onUseAnotherIdentity={() => { + isIdentityPopoverOpen = false; + isAuthDialogOpen = true; + }} + onManageIdentity={async () => { + isIdentityPopoverOpen = false; + window.open("/manage", "_blank"); + }} + onManageIdentities={() => { + isIdentityPopoverOpen = false; + isManageIdentitiesDialogOpen = true; + }} + onError={(error) => { + isIdentityPopoverOpen = false; + handleError(error); + }} + onClose={() => (isIdentityPopoverOpen = false)} + /> + + {/if} + {#if isAuthDialogOpen} + { + if (isAuthenticating) { + return; + } + isAuthDialogOpen = false; + }} + > + { + isAuthDialogOpen = false; + handleError(error); + }} + withinDialog + > +

+ {$t`Sign in`} +

+

+ {$t`Choose method to continue`} +

+
+
+ {/if} + {/if} +
+ {/if} +
+ {@render children()} +
+ {#if showHeaderFooter} +
+
+ {/if} +
+ + {#if isManageIdentitiesDialogOpen} + (isManageIdentitiesDialogOpen = false)}> + + + {/if} +{/if} diff --git a/src/frontend/src/routes/(new-styling)/authorize/+page.svelte b/src/frontend/src/routes/(new-styling)/authorize/+page.svelte new file mode 100644 index 0000000000..b5c6e3595e --- /dev/null +++ b/src/frontend/src/routes/(new-styling)/authorize/+page.svelte @@ -0,0 +1,329 @@ + + +{#snippet upgradePanel()} +
+
+ +

+ {#if dapp?.name !== undefined} + {@const application = dapp.name} + {$t`${application} has moved to the new Internet Identity`} + {:else} + {$t`This app has moved to the new Internet Identity`} + {/if} +

+

+ Still using an identity number? +

+ + +
+
+ + +
+
+ {#if isUpgrading} + (isUpgrading = false)}> + { + handleError(error); + isUpgrading = false; + }} + /> + + {/if} +{/snippet} + +{#snippet panelWrapper(content: Snippet)} +
+
+ {#if $GUIDED_UPGRADE || $MIN_GUIDED_UPGRADE} + {@render upgradePanel()} + {/if} +
+ {@render content()} +
+
+
+{/snippet} + +{#if data.flow === "openid-init"} + +{:else if $authorizedStore !== undefined} + + +{:else if data.flow === "openid-resume" && openIdResumeProcessing} + + +{:else if upgradeSuccess && $isAuthenticatedStore} + + {@render panelWrapper(upgradeSuccessContent)} +{:else if selectedIdentity !== undefined} + + {@render panelWrapper(continueContent)} +{:else} + + {@render panelWrapper(authWizardContent)} +{/if} + +{#snippet upgradeSuccessContent()} + +{/snippet} + +{#snippet continueContent()} + +{/snippet} + +{#snippet authWizardContent()} + +{/snippet} diff --git a/src/frontend/src/routes/(new-styling)/authorize/+page.ts b/src/frontend/src/routes/(new-styling)/authorize/+page.ts new file mode 100644 index 0000000000..fac1fa6612 --- /dev/null +++ b/src/frontend/src/routes/(new-styling)/authorize/+page.ts @@ -0,0 +1,24 @@ +import { redirect } from "@sveltejs/kit"; +import { backendCanisterConfig } from "$lib/globals"; +import type { PageLoad } from "./$types"; + +export const load: PageLoad = ({ url }) => { + const issuer = url.searchParams.get("openid"); + if (issuer !== null) { + const config = backendCanisterConfig.openid_configs[0]?.find( + (config) => config.issuer === issuer, + ); + if (config === undefined) { + // If OpenID config can't be found, fallback to ICRC-29 authorization flow + throw redirect(307, "/authorize"); + } + return { flow: "openid-init" as const, config }; + } + + const flow = url.searchParams.get("flow"); + if (flow === "openid-resume") { + return { flow: "openid-resume" as const }; + } + + return { flow: "normal" as const }; +}; diff --git a/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+page.svelte b/src/frontend/src/routes/(new-styling)/authorize/views/AuthWizardView.svelte similarity index 52% rename from src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+page.svelte rename to src/frontend/src/routes/(new-styling)/authorize/views/AuthWizardView.svelte index 5959771634..6991fefe88 100644 --- a/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/+page.svelte +++ b/src/frontend/src/routes/(new-styling)/authorize/views/AuthWizardView.svelte @@ -1,43 +1,27 @@ - +

{$t`Choose method`} diff --git a/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/continue/+page.svelte b/src/frontend/src/routes/(new-styling)/authorize/views/ContinueView.svelte similarity index 92% rename from src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/continue/+page.svelte rename to src/frontend/src/routes/(new-styling)/authorize/views/ContinueView.svelte index 36253ea945..bd833a9cb6 100644 --- a/src/frontend/src/routes/(new-styling)/(channel)/authorize/(panel)/continue/+page.svelte +++ b/src/frontend/src/routes/(new-styling)/authorize/views/ContinueView.svelte @@ -1,9 +1,5 @@ + +
+
+ {#if dapp?.logoSrc !== undefined} +
+ + + + + + + {$t`${dapp.name} +
+ {:else} + + + + + + + {/if} +

+ {$t`Signing in securely`} +

+ + {$t`Powered by`} + + {window.location.hostname} + +
+ {#await waitFor(10000) then _} + + + + +

+ {$t`Authentication successful`} +

+

+ {$t`You may close this page.`} +

+ +
+ {/await} +
+ + diff --git a/src/frontend/src/routes/(new-styling)/(channel)/authorize/upgrade-success/+page.svelte b/src/frontend/src/routes/(new-styling)/authorize/views/UpgradeSuccessView.svelte similarity index 86% rename from src/frontend/src/routes/(new-styling)/(channel)/authorize/upgrade-success/+page.svelte rename to src/frontend/src/routes/(new-styling)/authorize/views/UpgradeSuccessView.svelte index 4ea374b161..0fe8029bfe 100644 --- a/src/frontend/src/routes/(new-styling)/(channel)/authorize/upgrade-success/+page.svelte +++ b/src/frontend/src/routes/(new-styling)/authorize/views/UpgradeSuccessView.svelte @@ -1,11 +1,17 @@