-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtotpCode.ts
138 lines (135 loc) · 4.54 KB
/
totpCode.ts
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { callUserfront } from "../../services/userfront";
import { AuthMachineConfig, TotpCodeContext } from "../types";
// TOTP Authenticator state machine config
const totpCodeConfig: AuthMachineConfig = {
id: "useTotpCode",
initial: "showForm",
// If this is the first factor, the user needs to provide an email or username.
// If it's the second factor, we already have that info.
entry: ["clearError", "setupView", "setShowEmailOrUsernameIfFirstFactor"],
states: {
// Show the TOTP code entry form
showForm: {
on: {
// Send the TOTP code on submit
submit: {
actions: "setTotpCode",
target: "send",
},
// Go to the backup code entry view
useBackupCode: {
actions: "setUseBackupCode",
},
// Go back to the factor selection view
back: {
actions: "clearError",
target: "#backToFactors",
},
},
},
// Send the login request with the Userfront API
send: {
entry: "clearError",
invoke: {
// Set totpCode or backupCode and possibly emailOrUsername as arguments and call the method
src: (_context) => {
const context = <TotpCodeContext>_context;
const arg: Record<string, any> = {
method: "totp",
redirect: context.config.redirect,
};
if (context.view.useBackupCode) {
arg.backupCode = <string>context.view.backupCode;
} else {
arg.totpCode = context.view.totpCode;
}
if (context.view.emailOrUsername) {
arg.emailOrUsername = context.view.emailOrUsername;
} else if (context.user.email) {
arg.emailOrUsername = context.user.email;
} else if (context.user.username) {
arg.emailOrUsername = context.user.username;
} else if (context.user.emailOrUsername) {
arg.emailOrUsername = context.user.emailOrUsername;
}
return callUserfront({
// Method is ALWAYS login for TOTP code
method: "login",
args: [arg],
});
},
// On error, store the error and return to the form
onError: {
actions: "setErrorFromApiError",
target: "showForm",
},
onDone: [
// On success, proceed to second factor if required
{
actions: "setAllowedSecondFactors",
target: "#beginSecondFactor",
cond: "secondFactorRequired",
},
// Otherwise, we're signed in.
// Core JS redirects as appropriate here.
// Show the "verified" view in case we don't redirect.
{
target: "showTotpSuccess",
},
],
},
},
sendBackupCode: {
entry: "clearError",
invoke: {
// Set backupCode and possibly emailOrUsername as arguments and call the method
src: (_context) => {
const context = <TotpCodeContext>_context;
const arg: Record<string, any> = {
method: "totp",
backupCode: <string>context.view.backupCode,
redirect: context.config.redirect,
};
if (context.view.emailOrUsername) {
arg.emailOrUsername = context.view.emailOrUsername;
} else if (context.user.email) {
arg.emailOrUsername = context.user.email;
} else if (context.user.username) {
arg.emailOrUsername = context.user.username;
} else if (context.user.emailOrUsername) {
arg.emailOrUsername = context.user.emailOrUsername;
}
return callUserfront({
// Method is ALWAYS login for TOTP code
method: "login",
args: [arg],
});
},
// On error, store the error and return to the form
onError: {
actions: "setErrorFromApiError",
target: "showForm",
},
onDone: [
// On success, proceed to second factor if required
{
actions: "setAllowedSecondFactors",
target: "#beginSecondFactor",
cond: "secondFactorRequired",
},
// Otherwise, we're signed in.
// Core JS redirects as appropriate here.
// Show the "verified" view in case we don't redirect.
{
target: "showTotpSuccess",
},
],
},
},
// Show a confirmation view, in case we don't redirect
showTotpSuccess: {
type: "final",
},
},
};
export default totpCodeConfig;