From 592f0f9abc3a3b88257634f34d273a2dcff2329b Mon Sep 17 00:00:00 2001 From: Frederik Rothenberger Date: Fri, 22 Mar 2024 10:55:29 +0100 Subject: [PATCH] Refactor add device success screen to be shown consistently This PR refactors the add device success screen to be shown consistently (regardless from where the flow is started) by making it part of the tentative device flow rather than having that logic in the top-level `index.ts` file. Given the screen is part of both sides of the flow (the new device _and_ the existing one) I moved the corresponding files out of the `manage` folder). --- src/frontend/src/components/authenticateBox.ts | 4 ++-- .../{manage => }/addDeviceSuccess.json | 0 .../{manage => }/addDeviceSuccess.test.ts | 0 .../addDevice/{manage => }/addDeviceSuccess.ts | 0 .../src/flows/addDevice/manage/addDevice.ts | 2 +- .../src/flows/addDevice/manage/addFIDODevice.ts | 2 +- .../welcomeView/registerTentativeDevice.ts | 17 ++++++++++++++--- src/frontend/src/index.ts | 5 ----- src/frontend/src/test-e2e/addDevice.test.ts | 4 ++++ src/showcase/src/pages/addDeviceSuccess.astro | 2 +- 10 files changed, 23 insertions(+), 13 deletions(-) rename src/frontend/src/flows/addDevice/{manage => }/addDeviceSuccess.json (100%) rename src/frontend/src/flows/addDevice/{manage => }/addDeviceSuccess.test.ts (100%) rename src/frontend/src/flows/addDevice/{manage => }/addDeviceSuccess.ts (100%) diff --git a/src/frontend/src/components/authenticateBox.ts b/src/frontend/src/components/authenticateBox.ts index 17f20c4ee0..5a749a3592 100644 --- a/src/frontend/src/components/authenticateBox.ts +++ b/src/frontend/src/components/authenticateBox.ts @@ -160,7 +160,7 @@ export const authenticateBoxFlow = async ({ templates: AuthnTemplates; addDevice: ( userNumber?: bigint - ) => Promise<{ tag: "deviceAdded"; alias: string } | { tag: "canceled" }>; + ) => Promise<{ tag: "deviceAdded" } | { tag: "canceled" }>; loginPasskey: ( userNumber: bigint ) => Promise< @@ -652,7 +652,7 @@ const loginPinIdentityMaterial = ({ const asNewDevice = async ( connection: Connection, prefilledUserNumber?: bigint -): Promise<{ tag: "deviceAdded"; alias: string } | { tag: "canceled" }> => { +): Promise<{ tag: "deviceAdded" } | { tag: "canceled" }> => { // Prompt the user for an anchor and provide additional information about the flow. // If the user number is already known, it is prefilled in the screen. const userNumberResult = await promptUserNumber({ diff --git a/src/frontend/src/flows/addDevice/manage/addDeviceSuccess.json b/src/frontend/src/flows/addDevice/addDeviceSuccess.json similarity index 100% rename from src/frontend/src/flows/addDevice/manage/addDeviceSuccess.json rename to src/frontend/src/flows/addDevice/addDeviceSuccess.json diff --git a/src/frontend/src/flows/addDevice/manage/addDeviceSuccess.test.ts b/src/frontend/src/flows/addDevice/addDeviceSuccess.test.ts similarity index 100% rename from src/frontend/src/flows/addDevice/manage/addDeviceSuccess.test.ts rename to src/frontend/src/flows/addDevice/addDeviceSuccess.test.ts diff --git a/src/frontend/src/flows/addDevice/manage/addDeviceSuccess.ts b/src/frontend/src/flows/addDevice/addDeviceSuccess.ts similarity index 100% rename from src/frontend/src/flows/addDevice/manage/addDeviceSuccess.ts rename to src/frontend/src/flows/addDevice/addDeviceSuccess.ts diff --git a/src/frontend/src/flows/addDevice/manage/addDevice.ts b/src/frontend/src/flows/addDevice/manage/addDevice.ts index e01ce28589..8159dc1d6d 100644 --- a/src/frontend/src/flows/addDevice/manage/addDevice.ts +++ b/src/frontend/src/flows/addDevice/manage/addDevice.ts @@ -6,7 +6,7 @@ import { displayError } from "$src/components/displayError"; import { withLoader } from "$src/components/loader"; import { AuthenticatedConnection } from "$src/utils/iiConnection"; import { isNullish } from "@dfinity/utils"; -import { addDeviceSuccess } from "./addDeviceSuccess"; +import { addDeviceSuccess } from "../addDeviceSuccess"; import { addFIDODevice } from "./addFIDODevice"; import { pollForTentativeDevice } from "./pollForTentativeDevice"; import { verifyTentativeDevice } from "./verifyTentativeDevice"; diff --git a/src/frontend/src/flows/addDevice/manage/addFIDODevice.ts b/src/frontend/src/flows/addDevice/manage/addFIDODevice.ts index 69cf3bb2bf..cfa0445fc8 100644 --- a/src/frontend/src/flows/addDevice/manage/addFIDODevice.ts +++ b/src/frontend/src/flows/addDevice/manage/addFIDODevice.ts @@ -15,7 +15,7 @@ import { isWebAuthnDuplicateDevice, } from "$src/utils/webAuthnErrorUtils"; import { WebAuthnIdentity } from "@dfinity/identity"; -import { addDeviceSuccess } from "./addDeviceSuccess"; +import { addDeviceSuccess } from "../addDeviceSuccess"; const displayFailedToAddDevice = (error: Error) => displayError({ diff --git a/src/frontend/src/flows/addDevice/welcomeView/registerTentativeDevice.ts b/src/frontend/src/flows/addDevice/welcomeView/registerTentativeDevice.ts index f66140c3a4..62eb55317e 100644 --- a/src/frontend/src/flows/addDevice/welcomeView/registerTentativeDevice.ts +++ b/src/frontend/src/flows/addDevice/welcomeView/registerTentativeDevice.ts @@ -5,6 +5,7 @@ import { } from "$generated/internet_identity_types"; import { displayError } from "$src/components/displayError"; import { withLoader } from "$src/components/loader"; +import { addDeviceSuccess } from "$src/flows/addDevice/addDeviceSuccess"; import { inferPasskeyAlias, loadUAParser } from "$src/flows/register"; import { setAnchorUsed } from "$src/storage"; import { authenticatorAttachmentToKeyType } from "$src/utils/authenticatorAttachment"; @@ -21,14 +22,22 @@ import { deviceRegistrationDisabledInfo } from "./deviceRegistrationModeDisabled import { showVerificationCode } from "./showVerificationCode"; /** - * Prompts the user to enter a device alias. When clicking next, the device is added tentatively to the given identity anchor. + * Runs the tentative device registration flow on a _new_ device: + * 1. The user interacts with the authenticator to create a new credential. + * 2. After adding it tentatively, the user is prompted to enter the verification + * code on an existing device. + * 3. This flows polls for the user to complete the verification. + * 4. Once verification is completed, a success screen is shown. + * + * If the user cancels at any point, the flow is aborted. + * * @param userNumber anchor to add the tentative device to. * @param connection connection to interact with the II canister. */ export const registerTentativeDevice = async ( userNumber: bigint, connection: Connection -): Promise<{ tag: "deviceAdded"; alias: string } | { tag: "canceled" }> => { +): Promise<{ tag: "deviceAdded" } | { tag: "canceled" }> => { // Kick-off fetching "ua-parser-js"; const uaParser = loadUAParser(); @@ -101,7 +110,9 @@ export const registerTentativeDevice = async ( } verificationCodeResult satisfies "ok"; - return { tag: "deviceAdded", alias }; + + await addDeviceSuccess({ deviceAlias: alias }); + return { tag: "deviceAdded" }; }; /** Create new WebAuthn credentials */ diff --git a/src/frontend/src/index.ts b/src/frontend/src/index.ts index ee017b46ff..c535bdf56e 100644 --- a/src/frontend/src/index.ts +++ b/src/frontend/src/index.ts @@ -1,5 +1,4 @@ import { handleLoginFlowResult } from "$src/components/authenticateBox"; -import { addDeviceSuccess } from "$src/flows/addDevice/manage/addDeviceSuccess"; import { nonNullish } from "@dfinity/utils"; import { registerTentativeDevice } from "./flows/addDevice/welcomeView/registerTentativeDevice"; import { authFlowAuthorize } from "./flows/authorize"; @@ -22,10 +21,6 @@ void createSpa(async (connection) => { return authFlowManage(connection); } registerDeviceResult satisfies { tag: "deviceAdded" }; - const { alias: deviceAlias } = registerDeviceResult; - - // Display a success page once device added (above registerTentativeDevice **never** returns if it fails) - await addDeviceSuccess({ deviceAlias }); const renderManage = renderManageWarmup(); diff --git a/src/frontend/src/test-e2e/addDevice.test.ts b/src/frontend/src/test-e2e/addDevice.test.ts index b549e7a06a..87fe01b874 100644 --- a/src/frontend/src/test-e2e/addDevice.test.ts +++ b/src/frontend/src/test-e2e/addDevice.test.ts @@ -154,6 +154,10 @@ test("Add remote device starting on new device", async () => { await addDeviceSuccessView.continue(); // browser 2 again + const addDeviceSuccessView2 = new AddDeviceSuccessView(browser2); + await addDeviceSuccessView2.waitForDisplay(); + await addDeviceSuccessView2.continue(); + // make sure the browser now shows the sign-in screen with the user number // pre-filled await focusBrowser(browser2); diff --git a/src/showcase/src/pages/addDeviceSuccess.astro b/src/showcase/src/pages/addDeviceSuccess.astro index f5e5f9884e..c41fb361ae 100644 --- a/src/showcase/src/pages/addDeviceSuccess.astro +++ b/src/showcase/src/pages/addDeviceSuccess.astro @@ -7,7 +7,7 @@ import Screen from "../layouts/Screen.astro"; import { toast } from "$src/components/toast"; import { i18n } from "../i18n"; import { chromeDevice } from "../constants"; - import { addDeviceSuccessPage } from "$src/flows/addDevice/manage/addDeviceSuccess"; + import { addDeviceSuccessPage } from "$src/flows/addDevice/addDeviceSuccess"; addDeviceSuccessPage({ i18n,