diff --git a/src/frontend/src/flows/addDevice/addCurrentDevice.ts b/src/frontend/src/flows/addDevice/addCurrentDevice.ts index 2ebf99d9fe..f3c2f78097 100644 --- a/src/frontend/src/flows/addDevice/addCurrentDevice.ts +++ b/src/frontend/src/flows/addDevice/addCurrentDevice.ts @@ -1,8 +1,10 @@ import { infoScreenTemplate } from "$src/components/infoScreen"; import { I18n } from "$src/i18n"; +import { AuthenticatedConnection } from "$src/utils/iiConnection"; import { renderPage } from "$src/utils/lit-html"; import { TemplateResult } from "lit-html"; import copyJson from "./addCurrentDevice.json"; +import { addCurrentDevice } from "./manage/addCurrentDevice"; const addCurrentDeviceTemplate = ({ add, @@ -33,14 +35,21 @@ export const addCurrentDevicePage = renderPage(addCurrentDeviceTemplate); // Prompt the user to add the current device (with the current origin). // Adding the current device to the current origin improves the UX of the user when they come back to this origin. -export const addCurrentDevice = (): Promise<{ - action: "skip" | "add-current-device"; -}> => { +export const addCurrentDeviceScreen = ( + userNumber: bigint, + connection: AuthenticatedConnection +): Promise => { return new Promise((resolve) => addCurrentDevicePage({ i18n: new I18n(), - add: () => resolve({ action: "add-current-device" }), - skip: () => resolve({ action: "skip" }), + add: async () => { + const existingDevices = await connection.lookupAuthenticators( + userNumber + ); + await addCurrentDevice(userNumber, connection, existingDevices); + resolve(); + }, + skip: () => resolve(), }) ); }; diff --git a/src/frontend/src/flows/addDevice/manage/addFIDODevice.ts b/src/frontend/src/flows/addDevice/manage/addCurrentDevice.ts similarity index 90% rename from src/frontend/src/flows/addDevice/manage/addFIDODevice.ts rename to src/frontend/src/flows/addDevice/manage/addCurrentDevice.ts index 7aa6188e42..0a48171686 100644 --- a/src/frontend/src/flows/addDevice/manage/addFIDODevice.ts +++ b/src/frontend/src/flows/addDevice/manage/addCurrentDevice.ts @@ -27,17 +27,21 @@ const displayFailedToAddDevice = (error: Error) => }); /** - * Add a new device (i.e. a device connected to the browser the user is - * currently using, like a YubiKey, or FaceID, or, or. Not meant to be used to - * add e.g. _another_ browser, macbook or iPhone.) + * Add a new device form the current browser. + * + * Used to add a device connected to the browser the user is + * currently using, like a YubiKey, or FaceID. + * + * Used to add current device in the current origin. + * * @param userNumber anchor to add the device to * @param connection authenticated II connection * @param devices already existing devices */ -export const addFIDODevice = async ( +export const addCurrentDevice = async ( userNumber: bigint, connection: AuthenticatedConnection, - devices: DeviceData[] + devices: Omit[] ): Promise => { // Kick-off fetching "ua-parser-js"; const uaParser = loadUAParser(); diff --git a/src/frontend/src/flows/addDevice/manage/addDevice.ts b/src/frontend/src/flows/addDevice/manage/addDevice.ts index ae00214cce..648fef250b 100644 --- a/src/frontend/src/flows/addDevice/manage/addDevice.ts +++ b/src/frontend/src/flows/addDevice/manage/addDevice.ts @@ -8,7 +8,7 @@ import { tentativeDeviceStepper } from "$src/flows/addDevice/stepper"; import { AuthenticatedConnection } from "$src/utils/iiConnection"; import { isNullish } from "@dfinity/utils"; import { addDeviceSuccess } from "../addDeviceSuccess"; -import { addFIDODevice } from "./addFIDODevice"; +import { addCurrentDevice } from "./addCurrentDevice"; import { pollForTentativeDevice } from "./pollForTentativeDevice"; import { verifyTentativeDevice } from "./verifyTentativeDevice"; @@ -51,7 +51,7 @@ export const addDevice = async ({ // If the user wants to add a FIDO device then we can (should) exit registration mode // (only used for adding extra browsers) await withLoader(() => connection.exitDeviceRegistrationMode()); - await addFIDODevice(userNumber, connection, anchorInfo.devices); + await addCurrentDevice(userNumber, connection, anchorInfo.devices); return; } else if (result === "canceled") { // If the user canceled, disable registration mode and return diff --git a/src/frontend/src/flows/authorize/index.ts b/src/frontend/src/flows/authorize/index.ts index b932dca979..59d1b45543 100644 --- a/src/frontend/src/flows/authorize/index.ts +++ b/src/frontend/src/flows/authorize/index.ts @@ -7,6 +7,7 @@ import { caretDownIcon } from "$src/components/icons"; import { withLoader } from "$src/components/loader"; import { showMessage } from "$src/components/message"; import { showSpinner } from "$src/components/spinner"; +import { DOMAIN_COMPATIBILITY } from "$src/featureFlags"; import { getDapps } from "$src/flows/dappsExplorer/dapps"; import { recoveryWizard } from "$src/flows/recovery/recoveryWizard"; import { I18n } from "$src/i18n"; @@ -19,6 +20,7 @@ import { nonNullish } from "@dfinity/utils"; import { TemplateResult, html } from "lit-html"; import { asyncReplace } from "lit-html/directives/async-replace.js"; import { validateDerivationOrigin } from "../../utils/validateDerivationOrigin"; +import { addCurrentDeviceScreen } from "../addDevice/addCurrentDevice"; import { Delegation, fetchDelegation } from "./fetchDelegation"; import copyJson from "./index.json"; import { AuthContext, authenticationProtocol } from "./postMessageInterface"; @@ -211,6 +213,13 @@ const authenticate = async ( autoSelectionIdentity: autoSelectionIdentity, }); + if (authSuccess.showAddCurrentDevice && DOMAIN_COMPATIBILITY.isEnabled()) { + await addCurrentDeviceScreen( + authSuccess.userNumber, + authSuccess.connection + ); + } + // at this point, derivationOrigin is either validated or undefined const derivationOrigin = authContext.authRequest.derivationOrigin ?? authContext.requestOrigin; diff --git a/src/frontend/src/flows/manage/index.ts b/src/frontend/src/flows/manage/index.ts index e647d662d7..6ea30bbb5d 100644 --- a/src/frontend/src/flows/manage/index.ts +++ b/src/frontend/src/flows/manage/index.ts @@ -15,7 +15,7 @@ import { logoutSection } from "$src/components/logout"; import { mainWindow } from "$src/components/mainWindow"; import { toast } from "$src/components/toast"; import { ENABLE_PIN_QUERY_PARAM_KEY, LEGACY_II_URL } from "$src/config"; -import { OPENID_AUTHENTICATION } from "$src/featureFlags"; +import { DOMAIN_COMPATIBILITY, OPENID_AUTHENTICATION } from "$src/featureFlags"; import { addDevice } from "$src/flows/addDevice/manage/addDevice"; import { dappsExplorer } from "$src/flows/dappsExplorer"; import { KnownDapp, getDapps } from "$src/flows/dappsExplorer/dapps"; @@ -50,6 +50,7 @@ import { OmitParams, shuffleArray, unreachable } from "$src/utils/utils"; import { Principal } from "@dfinity/principal"; import { isNullish, nonNullish } from "@dfinity/utils"; import { TemplateResult, html } from "lit-html"; +import { addCurrentDeviceScreen } from "../addDevice/addCurrentDevice"; import { authenticatorsSection } from "./authenticatorsSection"; import { deleteDevice, @@ -116,6 +117,7 @@ export const authFlowManage = async (connection: Connection) => { userNumber, connection: authenticatedConnection, newAnchor, + showAddCurrentDevice, } = await authenticateBox({ connection, i18n, @@ -124,6 +126,10 @@ export const authFlowManage = async (connection: Connection) => { allowPinRegistration, }); + if (showAddCurrentDevice && DOMAIN_COMPATIBILITY.isEnabled()) { + await addCurrentDeviceScreen(userNumber, authenticatedConnection); + } + // Here, if the user is returning & doesn't have any recovery device, we prompt them to add // one. The exact flow depends on the device they use. if (!newAnchor) {