2022-10-05 15:37:15 +02:00
|
|
|
import express from 'express'
|
|
|
|
import { generateOTPSecret, isOTPValid } from '@server/helpers/otp'
|
2022-10-10 11:12:23 +02:00
|
|
|
import { encrypt } from '@server/helpers/peertube-crypto'
|
|
|
|
import { CONFIG } from '@server/initializers/config'
|
2022-10-05 15:37:15 +02:00
|
|
|
import { Redis } from '@server/lib/redis'
|
2022-10-07 14:23:42 +02:00
|
|
|
import { asyncMiddleware, authenticate, usersCheckCurrentPasswordFactory } from '@server/middlewares'
|
2022-10-05 15:37:15 +02:00
|
|
|
import {
|
|
|
|
confirmTwoFactorValidator,
|
|
|
|
disableTwoFactorValidator,
|
|
|
|
requestOrConfirmTwoFactorValidator
|
|
|
|
} from '@server/middlewares/validators/two-factor'
|
|
|
|
import { HttpStatusCode, TwoFactorEnableResult } from '@shared/models'
|
|
|
|
|
|
|
|
const twoFactorRouter = express.Router()
|
|
|
|
|
|
|
|
twoFactorRouter.post('/:id/two-factor/request',
|
|
|
|
authenticate,
|
2022-10-07 14:23:42 +02:00
|
|
|
asyncMiddleware(usersCheckCurrentPasswordFactory(req => req.params.id)),
|
2022-10-05 15:37:15 +02:00
|
|
|
asyncMiddleware(requestOrConfirmTwoFactorValidator),
|
|
|
|
asyncMiddleware(requestTwoFactor)
|
|
|
|
)
|
|
|
|
|
|
|
|
twoFactorRouter.post('/:id/two-factor/confirm-request',
|
|
|
|
authenticate,
|
|
|
|
asyncMiddleware(requestOrConfirmTwoFactorValidator),
|
|
|
|
confirmTwoFactorValidator,
|
|
|
|
asyncMiddleware(confirmRequestTwoFactor)
|
|
|
|
)
|
|
|
|
|
|
|
|
twoFactorRouter.post('/:id/two-factor/disable',
|
|
|
|
authenticate,
|
2022-10-07 14:23:42 +02:00
|
|
|
asyncMiddleware(usersCheckCurrentPasswordFactory(req => req.params.id)),
|
2022-10-05 15:37:15 +02:00
|
|
|
asyncMiddleware(disableTwoFactorValidator),
|
|
|
|
asyncMiddleware(disableTwoFactor)
|
|
|
|
)
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
export {
|
|
|
|
twoFactorRouter
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
async function requestTwoFactor (req: express.Request, res: express.Response) {
|
|
|
|
const user = res.locals.user
|
|
|
|
|
|
|
|
const { secret, uri } = generateOTPSecret(user.email)
|
2022-10-10 11:12:23 +02:00
|
|
|
|
|
|
|
const encryptedSecret = await encrypt(secret, CONFIG.SECRETS.PEERTUBE)
|
|
|
|
const requestToken = await Redis.Instance.setTwoFactorRequest(user.id, encryptedSecret)
|
2022-10-05 15:37:15 +02:00
|
|
|
|
|
|
|
return res.json({
|
|
|
|
otpRequest: {
|
|
|
|
requestToken,
|
|
|
|
secret,
|
|
|
|
uri
|
|
|
|
}
|
|
|
|
} as TwoFactorEnableResult)
|
|
|
|
}
|
|
|
|
|
|
|
|
async function confirmRequestTwoFactor (req: express.Request, res: express.Response) {
|
|
|
|
const requestToken = req.body.requestToken
|
|
|
|
const otpToken = req.body.otpToken
|
|
|
|
const user = res.locals.user
|
|
|
|
|
2022-10-10 11:12:23 +02:00
|
|
|
const encryptedSecret = await Redis.Instance.getTwoFactorRequestToken(user.id, requestToken)
|
|
|
|
if (!encryptedSecret) {
|
2022-10-05 15:37:15 +02:00
|
|
|
return res.fail({
|
|
|
|
message: 'Invalid request token',
|
|
|
|
status: HttpStatusCode.FORBIDDEN_403
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-10-10 11:12:23 +02:00
|
|
|
if (await isOTPValid({ encryptedSecret, token: otpToken }) !== true) {
|
2022-10-05 15:37:15 +02:00
|
|
|
return res.fail({
|
|
|
|
message: 'Invalid OTP token',
|
|
|
|
status: HttpStatusCode.FORBIDDEN_403
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-10-10 11:12:23 +02:00
|
|
|
user.otpSecret = encryptedSecret
|
2022-10-05 15:37:15 +02:00
|
|
|
await user.save()
|
|
|
|
|
|
|
|
return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
|
|
|
|
}
|
|
|
|
|
|
|
|
async function disableTwoFactor (req: express.Request, res: express.Response) {
|
|
|
|
const user = res.locals.user
|
|
|
|
|
|
|
|
user.otpSecret = null
|
|
|
|
await user.save()
|
|
|
|
|
|
|
|
return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
|
|
|
|
}
|