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,