This repository has been archived by the owner on Jan 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 26
/
register.ts
96 lines (85 loc) 路 2.85 KB
/
register.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
import { buildTemplate } from 'lib/email/build-template';
import { setPassword } from 'lib/account/set-password';
import { checkEmail } from 'lib/email/check';
import { cleanEmail } from 'lib/email/clean';
import { emailToId } from 'lib/email/to-id';
import { sendMail } from 'lib/email/send';
import { Accownt } from 'types/accownt';
import { signJWT } from 'lib/jwt';
import storage from 'node-persist';
import axios from 'axios';
import qs from 'qs';
const {
EMAIL_VERIFICATION_HTML_TEMPLATE,
EMAIL_VERIFICATION_TEXT_TEMPLATE,
TEMP_JWT_EXPIRES_IN,
ACCOWNT_API_URL,
JWT_EXPIRES_IN,
RECAPTCHA_KEY,
NAME
} = process.enve;
export async function startRegistration(
email: Accownt.User['email'],
pass?: Accownt.User['password'],
recaptcha?: string
): Promise<string> {
// Check if recaptcha response is valid
if (RECAPTCHA_KEY) {
const captcha = await axios.post(
'https://www.google.com/recaptcha/api/siteverify',
qs.stringify({ secret: RECAPTCHA_KEY, response: recaptcha })
);
if (!captcha.data.success) throw 'Invalid captcha';
}
email = cleanEmail(email);
const { available } = await checkEmail(email);
if (!available) throw 'Email is already taken';
// Create user- and email- storage entries
const user: Accownt.User = {
id: Date.now(),
email,
password: null,
verified: false,
totpSecret: null,
failedLogins: 0,
lastFailedLogin: 0
};
await storage.setItem(`user-${user.id}`, user);
await storage.setItem(`email-${email}`, user.id);
// Set password if needed
if (pass) await setPassword(user.id, pass);
// Send verification email
const token = await signJWT(user.id, email, TEMP_JWT_EXPIRES_IN);
const link = `${ACCOWNT_API_URL}/register?jwt=${token}`;
await sendMail({
subject: `${NAME} Email Verification`,
html: await buildTemplate({
name: 'LINK',
file: EMAIL_VERIFICATION_HTML_TEMPLATE,
value: link,
fallback: '<a href="%LINK%">Verify my email.</a>'
}),
text: await buildTemplate({
name: 'LINK',
file: EMAIL_VERIFICATION_TEXT_TEMPLATE,
value: link,
fallback: 'Verify your email: %LINK%"'
}),
to: email
});
return token;
}
export async function finishRegistration(jwt?: Accownt.JWT): Promise<string> {
if (jwt === null) throw 'Invalid or expired token';
// Verify JWT's userId matches the userId that the JWT's email points to
// This way only the most recent email verification JWT is valid since it
// will point to the newest user
const userId = await emailToId(jwt.email);
if (userId != jwt.userId)
throw 'This token has been invalidated by a newer one';
// Verify user's email
const user: Accownt.User = await storage.getItem(`user-${jwt.userId}`);
user.verified = true;
await storage.setItem(`user-${jwt.userId}`, user);
return await signJWT(jwt.userId, jwt.email, JWT_EXPIRES_IN);
}