1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
/* eslint-disable @typescript-eslint/camelcase */
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AuthMethod, ReducerStateBackup } from "anastasis-core";
import { AnastasisReducerApi } from "../../hooks/use-anastasis-reducer";
import { AuthMethodEmailSetup } from "./AuthMethodEmailSetup";
import { AuthMethodPostSetup } from "./AuthMethodPostSetup";
import { AuthMethodQuestionSetup } from "./AuthMethodQuestionSetup";
import { AuthMethodSmsSetup } from "./AuthMethodSmsSetup";
import { AnastasisClientFrame } from "./index";
export function AuthenticationEditorScreen(props: AuthenticationEditorProps): VNode {
const [selectedMethod, setSelectedMethod] = useState<string | undefined>(
undefined
);
const { reducer, backupState } = props;
const providers = backupState.authentication_providers!;
const authAvailableSet = new Set<string>();
for (const provKey of Object.keys(providers)) {
const p = providers[provKey];
if ("http_status" in p && (!("error_code" in p)) && p.methods) {
for (const meth of p.methods) {
authAvailableSet.add(meth.type);
}
}
}
if (selectedMethod) {
const cancel = (): void => setSelectedMethod(undefined);
const addMethod = (args: any): void => {
reducer.transition("add_authentication", args);
setSelectedMethod(undefined);
};
const methodMap: Record<
string, (props: AuthMethodSetupProps) => h.JSX.Element
> = {
sms: AuthMethodSmsSetup,
question: AuthMethodQuestionSetup,
email: AuthMethodEmailSetup,
post: AuthMethodPostSetup,
};
const AuthSetup = methodMap[selectedMethod] ?? AuthMethodNotImplemented;
return (
<AuthSetup
cancel={cancel}
addAuthMethod={addMethod}
method={selectedMethod} />
);
}
function MethodButton(props: { method: string; label: string }): VNode {
return (
<button
disabled={!authAvailableSet.has(props.method)}
onClick={() => {
setSelectedMethod(props.method);
reducer.dismissError();
}}
>
{props.label}
</button>
);
}
const configuredAuthMethods: AuthMethod[] = backupState.authentication_methods ?? [];
const haveMethodsConfigured = configuredAuthMethods.length;
return (
<AnastasisClientFrame title="Backup: Configure Authentication Methods">
<div>
<MethodButton method="sms" label="SMS" />
<MethodButton method="email" label="Email" />
<MethodButton method="question" label="Question" />
<MethodButton method="post" label="Physical Mail" />
<MethodButton method="totp" label="TOTP" />
<MethodButton method="iban" label="IBAN" />
</div>
<h2>Configured authentication methods</h2>
{haveMethodsConfigured ? (
configuredAuthMethods.map((x, i) => {
return (
<p key={i}>
{x.type} ({x.instructions}){" "}
<button
onClick={() => reducer.transition("delete_authentication", {
authentication_method: i,
})}
>
Delete
</button>
</p>
);
})
) : (
<p>No authentication methods configured yet.</p>
)}
</AnastasisClientFrame>
);
}
export interface AuthMethodSetupProps {
method: string;
addAuthMethod: (x: any) => void;
cancel: () => void;
}
function AuthMethodNotImplemented(props: AuthMethodSetupProps): VNode {
return (
<AnastasisClientFrame hideNav title={`Add ${props.method} authentication`}>
<p>This auth method is not implemented yet, please choose another one.</p>
<button onClick={() => props.cancel()}>Cancel</button>
</AnastasisClientFrame>
);
}
interface AuthenticationEditorProps {
reducer: AnastasisReducerApi;
backupState: ReducerStateBackup;
}
|