aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api/users/two-factor.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/api/users/two-factor.ts')
-rw-r--r--server/controllers/api/users/two-factor.ts91
1 files changed, 91 insertions, 0 deletions
diff --git a/server/controllers/api/users/two-factor.ts b/server/controllers/api/users/two-factor.ts
new file mode 100644
index 000000000..1725294e7
--- /dev/null
+++ b/server/controllers/api/users/two-factor.ts
@@ -0,0 +1,91 @@
1import express from 'express'
2import { generateOTPSecret, isOTPValid } from '@server/helpers/otp'
3import { Redis } from '@server/lib/redis'
4import { asyncMiddleware, authenticate, usersCheckCurrentPassword } from '@server/middlewares'
5import {
6 confirmTwoFactorValidator,
7 disableTwoFactorValidator,
8 requestOrConfirmTwoFactorValidator
9} from '@server/middlewares/validators/two-factor'
10import { HttpStatusCode, TwoFactorEnableResult } from '@shared/models'
11
12const twoFactorRouter = express.Router()
13
14twoFactorRouter.post('/:id/two-factor/request',
15 authenticate,
16 asyncMiddleware(usersCheckCurrentPassword),
17 asyncMiddleware(requestOrConfirmTwoFactorValidator),
18 asyncMiddleware(requestTwoFactor)
19)
20
21twoFactorRouter.post('/:id/two-factor/confirm-request',
22 authenticate,
23 asyncMiddleware(requestOrConfirmTwoFactorValidator),
24 confirmTwoFactorValidator,
25 asyncMiddleware(confirmRequestTwoFactor)
26)
27
28twoFactorRouter.post('/:id/two-factor/disable',
29 authenticate,
30 asyncMiddleware(usersCheckCurrentPassword),
31 asyncMiddleware(disableTwoFactorValidator),
32 asyncMiddleware(disableTwoFactor)
33)
34
35// ---------------------------------------------------------------------------
36
37export {
38 twoFactorRouter
39}
40
41// ---------------------------------------------------------------------------
42
43async function requestTwoFactor (req: express.Request, res: express.Response) {
44 const user = res.locals.user
45
46 const { secret, uri } = generateOTPSecret(user.email)
47 const requestToken = await Redis.Instance.setTwoFactorRequest(user.id, secret)
48
49 return res.json({
50 otpRequest: {
51 requestToken,
52 secret,
53 uri
54 }
55 } as TwoFactorEnableResult)
56}
57
58async function confirmRequestTwoFactor (req: express.Request, res: express.Response) {
59 const requestToken = req.body.requestToken
60 const otpToken = req.body.otpToken
61 const user = res.locals.user
62
63 const secret = await Redis.Instance.getTwoFactorRequestToken(user.id, requestToken)
64 if (!secret) {
65 return res.fail({
66 message: 'Invalid request token',
67 status: HttpStatusCode.FORBIDDEN_403
68 })
69 }
70
71 if (isOTPValid({ secret, token: otpToken }) !== true) {
72 return res.fail({
73 message: 'Invalid OTP token',
74 status: HttpStatusCode.FORBIDDEN_403
75 })
76 }
77
78 user.otpSecret = secret
79 await user.save()
80
81 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
82}
83
84async function disableTwoFactor (req: express.Request, res: express.Response) {
85 const user = res.locals.user
86
87 user.otpSecret = null
88 await user.save()
89
90 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
91}