diff options
author | Chocobozzz <me@florianbigard.com> | 2022-10-10 11:19:58 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-10-10 11:19:58 +0200 |
commit | 63fa260a81a8930c157b73c897fe8696a8cc90d4 (patch) | |
tree | 705ebfae42f9c59b2a1ac97779e4037102dfed1c /server/controllers/api/users/two-factor.ts | |
parent | 9b99d32804e99462c6f22df3ec3db9ec5bf8a18c (diff) | |
parent | 1ea868a9456439108fbd87255537093ed8bd456f (diff) | |
download | PeerTube-63fa260a81a8930c157b73c897fe8696a8cc90d4.tar.gz PeerTube-63fa260a81a8930c157b73c897fe8696a8cc90d4.tar.zst PeerTube-63fa260a81a8930c157b73c897fe8696a8cc90d4.zip |
Merge branch 'feature/otp' into develop
Diffstat (limited to 'server/controllers/api/users/two-factor.ts')
-rw-r--r-- | server/controllers/api/users/two-factor.ts | 95 |
1 files changed, 95 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..e6ae9e4dd --- /dev/null +++ b/server/controllers/api/users/two-factor.ts | |||
@@ -0,0 +1,95 @@ | |||
1 | import express from 'express' | ||
2 | import { generateOTPSecret, isOTPValid } from '@server/helpers/otp' | ||
3 | import { encrypt } from '@server/helpers/peertube-crypto' | ||
4 | import { CONFIG } from '@server/initializers/config' | ||
5 | import { Redis } from '@server/lib/redis' | ||
6 | import { asyncMiddleware, authenticate, usersCheckCurrentPasswordFactory } from '@server/middlewares' | ||
7 | import { | ||
8 | confirmTwoFactorValidator, | ||
9 | disableTwoFactorValidator, | ||
10 | requestOrConfirmTwoFactorValidator | ||
11 | } from '@server/middlewares/validators/two-factor' | ||
12 | import { HttpStatusCode, TwoFactorEnableResult } from '@shared/models' | ||
13 | |||
14 | const twoFactorRouter = express.Router() | ||
15 | |||
16 | twoFactorRouter.post('/:id/two-factor/request', | ||
17 | authenticate, | ||
18 | asyncMiddleware(usersCheckCurrentPasswordFactory(req => req.params.id)), | ||
19 | asyncMiddleware(requestOrConfirmTwoFactorValidator), | ||
20 | asyncMiddleware(requestTwoFactor) | ||
21 | ) | ||
22 | |||
23 | twoFactorRouter.post('/:id/two-factor/confirm-request', | ||
24 | authenticate, | ||
25 | asyncMiddleware(requestOrConfirmTwoFactorValidator), | ||
26 | confirmTwoFactorValidator, | ||
27 | asyncMiddleware(confirmRequestTwoFactor) | ||
28 | ) | ||
29 | |||
30 | twoFactorRouter.post('/:id/two-factor/disable', | ||
31 | authenticate, | ||
32 | asyncMiddleware(usersCheckCurrentPasswordFactory(req => req.params.id)), | ||
33 | asyncMiddleware(disableTwoFactorValidator), | ||
34 | asyncMiddleware(disableTwoFactor) | ||
35 | ) | ||
36 | |||
37 | // --------------------------------------------------------------------------- | ||
38 | |||
39 | export { | ||
40 | twoFactorRouter | ||
41 | } | ||
42 | |||
43 | // --------------------------------------------------------------------------- | ||
44 | |||
45 | async function requestTwoFactor (req: express.Request, res: express.Response) { | ||
46 | const user = res.locals.user | ||
47 | |||
48 | const { secret, uri } = generateOTPSecret(user.email) | ||
49 | |||
50 | const encryptedSecret = await encrypt(secret, CONFIG.SECRETS.PEERTUBE) | ||
51 | const requestToken = await Redis.Instance.setTwoFactorRequest(user.id, encryptedSecret) | ||
52 | |||
53 | return res.json({ | ||
54 | otpRequest: { | ||
55 | requestToken, | ||
56 | secret, | ||
57 | uri | ||
58 | } | ||
59 | } as TwoFactorEnableResult) | ||
60 | } | ||
61 | |||
62 | async function confirmRequestTwoFactor (req: express.Request, res: express.Response) { | ||
63 | const requestToken = req.body.requestToken | ||
64 | const otpToken = req.body.otpToken | ||
65 | const user = res.locals.user | ||
66 | |||
67 | const encryptedSecret = await Redis.Instance.getTwoFactorRequestToken(user.id, requestToken) | ||
68 | if (!encryptedSecret) { | ||
69 | return res.fail({ | ||
70 | message: 'Invalid request token', | ||
71 | status: HttpStatusCode.FORBIDDEN_403 | ||
72 | }) | ||
73 | } | ||
74 | |||
75 | if (await isOTPValid({ encryptedSecret, token: otpToken }) !== true) { | ||
76 | return res.fail({ | ||
77 | message: 'Invalid OTP token', | ||
78 | status: HttpStatusCode.FORBIDDEN_403 | ||
79 | }) | ||
80 | } | ||
81 | |||
82 | user.otpSecret = encryptedSecret | ||
83 | await user.save() | ||
84 | |||
85 | return res.sendStatus(HttpStatusCode.NO_CONTENT_204) | ||
86 | } | ||
87 | |||
88 | async function disableTwoFactor (req: express.Request, res: express.Response) { | ||
89 | const user = res.locals.user | ||
90 | |||
91 | user.otpSecret = null | ||
92 | await user.save() | ||
93 | |||
94 | return res.sendStatus(HttpStatusCode.NO_CONTENT_204) | ||
95 | } | ||