Skip to content

Commit

Permalink
Functionality to add current device to current origin (#2778)
Browse files Browse the repository at this point in the history
  • Loading branch information
lmuntaner authored Jan 14, 2025
1 parent b421f38 commit bd8ac9a
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 13 deletions.
19 changes: 14 additions & 5 deletions src/frontend/src/flows/addDevice/addCurrentDevice.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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<void> => {
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(),
})
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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<DeviceData, "alias">[]
): Promise<void> => {
// Kick-off fetching "ua-parser-js";
const uaParser = loadUAParser();
Expand Down
4 changes: 2 additions & 2 deletions src/frontend/src/flows/addDevice/manage/addDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions src/frontend/src/flows/authorize/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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";
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 7 additions & 1 deletion src/frontend/src/flows/manage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -116,6 +117,7 @@ export const authFlowManage = async (connection: Connection) => {
userNumber,
connection: authenticatedConnection,
newAnchor,
showAddCurrentDevice,
} = await authenticateBox({
connection,
i18n,
Expand All @@ -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) {
Expand Down

0 comments on commit bd8ac9a

Please sign in to comment.