Skip to content

Commit

Permalink
Replace runtime check by type guards
Browse files Browse the repository at this point in the history
  • Loading branch information
Frederik Rothenberger committed Feb 14, 2023
1 parent 7b79421 commit 517e9e4
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 37 deletions.
20 changes: 12 additions & 8 deletions src/frontend/src/flows/manage/deviceSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { unreachable } from "../../utils/utils";
import { DeviceData } from "../../../generated/internet_identity_types";
import { phraseRecoveryPage } from "../recovery/recoverWith/phrase";
import { mainWindow } from "../../components/mainWindow";
import { recoveryDeviceToLabel } from "../../utils/recoveryDeviceLabel";
import {
isRecoveryDevice,
recoveryDeviceToLabel,
} from "../../utils/recoveryDevice";

// The "device settings" page where users can view information about a device,
// remove a device, make a recovery phrase protected, etc.
Expand All @@ -33,7 +36,7 @@ const deviceSettingsTemplate = ({
}) => {
const pageContentSlot = html` <article id="deviceSettings">
<h1 class="t-title">
${isRecovery(device)
${isRecoveryDevice(device)
? recoveryDeviceToLabel(device)
: `Device ${device.alias}`}
</h1>
Expand All @@ -59,13 +62,17 @@ const deviceSettingsTemplate = ({
data-action="remove"
class="c-button c-button--warning"
>
Delete ${isRecovery(device) ? "Recovery" : "Device"}
Delete ${isRecoveryDevice(device) ? "Recovery" : "Device"}
</button>`
: ""}
${!isOnlyDevice && isProtected(device)
? html`<p class="t-paragraph">
This ${isRecovery(device) ? device.alias : "device"} is protected
and you will be prompted to authenticate with it before removal.
This
${isRecoveryDevice(device)
? recoveryDeviceToLabel(device).toLowerCase()
: "device"}
is protected and you will be prompted to authenticate with it before
removal.
</p>`
: ""}
${isOnlyDevice
Expand Down Expand Up @@ -97,9 +104,6 @@ const shouldOfferToProtect = (device: DeviceData): boolean =>
const isProtected = (device: DeviceData): boolean =>
"protected" in device.protection;

const isRecovery = (device: DeviceData): boolean =>
"recovery" in device.purpose;

export const deviceSettingsPage = (
props: Parameters<typeof deviceSettingsTemplate>[0],
container?: HTMLElement
Expand Down
10 changes: 7 additions & 3 deletions src/frontend/src/flows/manage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import { chooseDeviceAddFlow } from "../addDevice/manage";
import { addLocalDevice } from "../addDevice/manage/addLocalDevice";
import { warnBox } from "../../components/warnBox";
import { mainWindow } from "../../components/mainWindow";
import { recoveryDeviceToLabel } from "../../utils/recoveryDeviceLabel";
import {
isRecoveryDevice,
recoveryDeviceToLabel,
} from "../../utils/recoveryDevice";

/* Template for the authbox when authenticating to II */
export const authnTemplateManage = (): AuthnTemplates => {
Expand Down Expand Up @@ -230,8 +233,9 @@ const recoverySection = (
};

const deviceListItem = (device: DeviceData) => {
const label =
"recovery" in device.purpose ? recoveryDeviceToLabel(device) : device.alias;
const label = isRecoveryDevice(device)
? recoveryDeviceToLabel(device)
: device.alias;
return html`
<div class="c-action-list__label">${label}</div>
<button
Expand Down
14 changes: 7 additions & 7 deletions src/frontend/src/flows/recovery/pickRecoveryDevice.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { html, render } from "lit-html";
import { DeviceData } from "../../../generated/internet_identity_types";
import { mainWindow } from "../../components/mainWindow";
import { securityKeyIcon, seedPhraseIcon } from "../../components/icons";
import { recoveryDeviceToLabel } from "../../utils/recoveryDeviceLabel";
import {
RecoveryDevice,
recoveryDeviceToLabel,
} from "../../utils/recoveryDevice";

const pageContent = () => {
const pageContentSlot = html`
Expand All @@ -23,16 +25,14 @@ const pageContent = () => {
};

export const pickRecoveryDevice = async (
devices: Omit<DeviceData, "alias">[]
): Promise<Omit<DeviceData, "alias">> => {
devices: RecoveryDevice[]
): Promise<RecoveryDevice> => {
const container = document.getElementById("pageContent") as HTMLElement;
render(pageContent(), container);
return init(devices);
};

export const init = (
devices: Omit<DeviceData, "alias">[]
): Promise<Omit<DeviceData, "alias">> =>
export const init = (devices: RecoveryDevice[]): Promise<RecoveryDevice> =>
new Promise((resolve) => {
const deviceList = document.getElementById("deviceList") as HTMLElement;
deviceList.innerHTML = ``;
Expand Down
5 changes: 3 additions & 2 deletions src/frontend/src/showcase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ import { displaySafariWarning } from "./flows/recovery/displaySafariWarning";
import { displayError } from "./components/displayError";
import { promptUserNumber } from "./components/promptUserNumber";
import { registerDisabled } from "./flows/registerDisabled";
import { RecoveryDevice } from "./utils/recoveryDevice";

// A "dummy" connection which actually is just undefined, hoping pages won't call it
const dummyConnection = undefined as unknown as AuthenticatedConnection;
const userNumber = BigInt(10000);

const i18n = new I18n("en");

const recoveryPhrase: DeviceData = {
const recoveryPhrase: RecoveryDevice & DeviceData = {
alias: "Recovery Phrase",
protection: { unprotected: null },
pubkey: [1, 2, 3, 4],
Expand All @@ -66,7 +67,7 @@ const recoveryPhrase: DeviceData = {
const recoveryPhraseText =
"10050 mandate vague same suspect eight pet gentle repeat maple actor about legal sword text food print material churn perfect sword blossom sleep vintage blouse";

const recoveryDevice: DeviceData = {
const recoveryDevice: RecoveryDevice & DeviceData = {
alias: "Recovery Device",
protection: { unprotected: null },
pubkey: [1, 2, 3, 4],
Expand Down
11 changes: 8 additions & 3 deletions src/frontend/src/utils/iiConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { unreachable } from "./utils";
import * as tweetnacl from "tweetnacl";
import { fromMnemonicWithoutValidation } from "../crypto/ed25519";
import { features } from "../features";
import { isRecoveryDevice, RecoveryDevice } from "./recoveryDevice";

/*
* A (dummy) identity that always uses the same keypair. The secret key is
Expand Down Expand Up @@ -397,10 +398,14 @@ export class Connection {

lookupRecovery = async (
userNumber: UserNumber
): Promise<Omit<DeviceData, "alias">[]> => {
): Promise<RecoveryDevice[]> => {
const actor = await this.createActor();
const allDevices = await actor.lookup(userNumber);
return allDevices.filter((device) => "recovery" in device.purpose);
const allDevices: Omit<DeviceData, "alias">[] = await actor.lookup(
userNumber
);
return allDevices.filter((device): device is RecoveryDevice =>
isRecoveryDevice(device)
);
};

// Create an actor representing the backend
Expand Down
17 changes: 17 additions & 0 deletions src/frontend/src/utils/recoveryDevice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { DeviceData, Purpose } from "../../generated/internet_identity_types";

export type RecoveryDevice = Omit<DeviceData, "alias"> & {
purpose: Extract<Purpose, { recovery: null }>;
};

export const recoveryDeviceToLabel = (
device: Omit<DeviceData, "alias"> & RecoveryDevice
): string => {
if ("seed_phrase" in device.key_type) {
return "Recovery phrase";
}
return "External Hardware";
};
export const isRecoveryDevice = (
device: Omit<DeviceData, "alias">
): device is RecoveryDevice => "recovery" in device.purpose;
14 changes: 0 additions & 14 deletions src/frontend/src/utils/recoveryDeviceLabel.ts

This file was deleted.

0 comments on commit 517e9e4

Please sign in to comment.