Skip to content

Commit cf11d31

Browse files
author
Frederik Rothenberger
committed
Replace runtime check by type guards
1 parent 7b79421 commit cf11d31

File tree

7 files changed

+54
-36
lines changed

7 files changed

+54
-36
lines changed

src/frontend/src/flows/manage/deviceSettings.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import { unreachable } from "../../utils/utils";
1111
import { DeviceData } from "../../../generated/internet_identity_types";
1212
import { phraseRecoveryPage } from "../recovery/recoverWith/phrase";
1313
import { mainWindow } from "../../components/mainWindow";
14-
import { recoveryDeviceToLabel } from "../../utils/recoveryDeviceLabel";
14+
import {
15+
isRecoveryDevice,
16+
recoveryDeviceToLabel,
17+
} from "../../utils/recoveryDevice";
1518

1619
// The "device settings" page where users can view information about a device,
1720
// remove a device, make a recovery phrase protected, etc.
@@ -33,7 +36,7 @@ const deviceSettingsTemplate = ({
3336
}) => {
3437
const pageContentSlot = html` <article id="deviceSettings">
3538
<h1 class="t-title">
36-
${isRecovery(device)
39+
${isRecoveryDevice(device)
3740
? recoveryDeviceToLabel(device)
3841
: `Device ${device.alias}`}
3942
</h1>
@@ -59,13 +62,17 @@ const deviceSettingsTemplate = ({
5962
data-action="remove"
6063
class="c-button c-button--warning"
6164
>
62-
Delete ${isRecovery(device) ? "Recovery" : "Device"}
65+
Delete ${isRecoveryDevice(device) ? "Recovery" : "Device"}
6366
</button>`
6467
: ""}
6568
${!isOnlyDevice && isProtected(device)
6669
? html`<p class="t-paragraph">
67-
This ${isRecovery(device) ? device.alias : "device"} is protected
68-
and you will be prompted to authenticate with it before removal.
70+
This
71+
${isRecoveryDevice(device)
72+
? recoveryDeviceToLabel(device).toLowerCase()
73+
: "device"}
74+
is protected and you will be prompted to authenticate with it before
75+
removal.
6976
</p>`
7077
: ""}
7178
${isOnlyDevice
@@ -97,9 +104,6 @@ const shouldOfferToProtect = (device: DeviceData): boolean =>
97104
const isProtected = (device: DeviceData): boolean =>
98105
"protected" in device.protection;
99106

100-
const isRecovery = (device: DeviceData): boolean =>
101-
"recovery" in device.purpose;
102-
103107
export const deviceSettingsPage = (
104108
props: Parameters<typeof deviceSettingsTemplate>[0],
105109
container?: HTMLElement

src/frontend/src/flows/manage/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ import { chooseDeviceAddFlow } from "../addDevice/manage";
2121
import { addLocalDevice } from "../addDevice/manage/addLocalDevice";
2222
import { warnBox } from "../../components/warnBox";
2323
import { mainWindow } from "../../components/mainWindow";
24-
import { recoveryDeviceToLabel } from "../../utils/recoveryDeviceLabel";
24+
import {
25+
isRecoveryDevice,
26+
recoveryDeviceToLabel,
27+
} from "../../utils/recoveryDevice";
2528

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

232235
const deviceListItem = (device: DeviceData) => {
233-
const label =
234-
"recovery" in device.purpose ? recoveryDeviceToLabel(device) : device.alias;
236+
const label = isRecoveryDevice(device)
237+
? recoveryDeviceToLabel(device)
238+
: device.alias;
235239
return html`
236240
<div class="c-action-list__label">${label}</div>
237241
<button

src/frontend/src/flows/recovery/pickRecoveryDevice.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { html, render } from "lit-html";
22
import { DeviceData } from "../../../generated/internet_identity_types";
33
import { mainWindow } from "../../components/mainWindow";
44
import { securityKeyIcon, seedPhraseIcon } from "../../components/icons";
5-
import { recoveryDeviceToLabel } from "../../utils/recoveryDeviceLabel";
5+
import {
6+
RecoveryDevice,
7+
recoveryDeviceToLabel,
8+
} from "../../utils/recoveryDevice";
69

710
const pageContent = () => {
811
const pageContentSlot = html`
@@ -23,16 +26,14 @@ const pageContent = () => {
2326
};
2427

2528
export const pickRecoveryDevice = async (
26-
devices: Omit<DeviceData, "alias">[]
27-
): Promise<Omit<DeviceData, "alias">> => {
29+
devices: RecoveryDevice[]
30+
): Promise<RecoveryDevice> => {
2831
const container = document.getElementById("pageContent") as HTMLElement;
2932
render(pageContent(), container);
3033
return init(devices);
3134
};
3235

33-
export const init = (
34-
devices: Omit<DeviceData, "alias">[]
35-
): Promise<Omit<DeviceData, "alias">> =>
36+
export const init = (devices: RecoveryDevice[]): Promise<RecoveryDevice> =>
3637
new Promise((resolve) => {
3738
const deviceList = document.getElementById("deviceList") as HTMLElement;
3839
deviceList.innerHTML = ``;

src/frontend/src/showcase.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,15 @@ import { displaySafariWarning } from "./flows/recovery/displaySafariWarning";
4747
import { displayError } from "./components/displayError";
4848
import { promptUserNumber } from "./components/promptUserNumber";
4949
import { registerDisabled } from "./flows/registerDisabled";
50+
import { RecoveryDevice } from "./utils/recoveryDevice";
5051

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

5556
const i18n = new I18n("en");
5657

57-
const recoveryPhrase: DeviceData = {
58+
const recoveryPhrase: RecoveryDevice & DeviceData = {
5859
alias: "Recovery Phrase",
5960
protection: { unprotected: null },
6061
pubkey: [1, 2, 3, 4],
@@ -66,7 +67,7 @@ const recoveryPhrase: DeviceData = {
6667
const recoveryPhraseText =
6768
"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";
6869

69-
const recoveryDevice: DeviceData = {
70+
const recoveryDevice: RecoveryDevice & DeviceData = {
7071
alias: "Recovery Device",
7172
protection: { unprotected: null },
7273
pubkey: [1, 2, 3, 4],

src/frontend/src/utils/iiConnection.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { unreachable } from "./utils";
4040
import * as tweetnacl from "tweetnacl";
4141
import { fromMnemonicWithoutValidation } from "../crypto/ed25519";
4242
import { features } from "../features";
43+
import { isRecoveryDevice, RecoveryDevice } from "./recoveryDevice";
4344

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

398399
lookupRecovery = async (
399400
userNumber: UserNumber
400-
): Promise<Omit<DeviceData, "alias">[]> => {
401+
): Promise<RecoveryDevice[]> => {
401402
const actor = await this.createActor();
402-
const allDevices = await actor.lookup(userNumber);
403-
return allDevices.filter((device) => "recovery" in device.purpose);
403+
const allDevices: Omit<DeviceData, "alias">[] = await actor.lookup(
404+
userNumber
405+
);
406+
return allDevices.filter((device): device is RecoveryDevice =>
407+
isRecoveryDevice(device)
408+
);
404409
};
405410

406411
// Create an actor representing the backend
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { DeviceData, Purpose } from "../../generated/internet_identity_types";
2+
3+
export type RecoveryDevice = Omit<DeviceData, "alias"> & {
4+
purpose: Extract<Purpose, { recovery: null }>;
5+
};
6+
7+
export const recoveryDeviceToLabel = (
8+
device: Omit<DeviceData, "alias"> & RecoveryDevice
9+
): string => {
10+
if ("seed_phrase" in device.key_type) {
11+
return "Recovery phrase";
12+
}
13+
return "External Hardware";
14+
};
15+
export const isRecoveryDevice = (
16+
device: Omit<DeviceData, "alias">
17+
): device is RecoveryDevice => "recovery" in device.purpose;

src/frontend/src/utils/recoveryDeviceLabel.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)