2022-10-05 15:37:15 +02:00
|
|
|
import { TOTP } from 'otpauth'
|
|
|
|
import { HttpStatusCode, TwoFactorEnableResult } from '@shared/models'
|
|
|
|
import { unwrapBody } from '../requests'
|
|
|
|
import { AbstractCommand, OverrideCommandOptions } from '../shared'
|
|
|
|
|
|
|
|
export class TwoFactorCommand extends AbstractCommand {
|
|
|
|
|
|
|
|
static buildOTP (options: {
|
|
|
|
secret: string
|
|
|
|
}) {
|
|
|
|
const { secret } = options
|
|
|
|
|
|
|
|
return new TOTP({
|
|
|
|
issuer: 'PeerTube',
|
|
|
|
algorithm: 'SHA1',
|
|
|
|
digits: 6,
|
|
|
|
period: 30,
|
|
|
|
secret
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
request (options: OverrideCommandOptions & {
|
|
|
|
userId: number
|
2022-10-07 14:23:42 +02:00
|
|
|
currentPassword?: string
|
2022-10-05 15:37:15 +02:00
|
|
|
}) {
|
|
|
|
const { currentPassword, userId } = options
|
|
|
|
|
|
|
|
const path = '/api/v1/users/' + userId + '/two-factor/request'
|
|
|
|
|
|
|
|
return unwrapBody<TwoFactorEnableResult>(this.postBodyRequest({
|
|
|
|
...options,
|
|
|
|
|
|
|
|
path,
|
|
|
|
fields: { currentPassword },
|
|
|
|
implicitToken: true,
|
|
|
|
defaultExpectedStatus: HttpStatusCode.OK_200
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
confirmRequest (options: OverrideCommandOptions & {
|
|
|
|
userId: number
|
|
|
|
requestToken: string
|
|
|
|
otpToken: string
|
|
|
|
}) {
|
|
|
|
const { userId, requestToken, otpToken } = options
|
|
|
|
|
|
|
|
const path = '/api/v1/users/' + userId + '/two-factor/confirm-request'
|
|
|
|
|
|
|
|
return this.postBodyRequest({
|
|
|
|
...options,
|
|
|
|
|
|
|
|
path,
|
|
|
|
fields: { requestToken, otpToken },
|
|
|
|
implicitToken: true,
|
|
|
|
defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
disable (options: OverrideCommandOptions & {
|
|
|
|
userId: number
|
2022-10-07 14:23:42 +02:00
|
|
|
currentPassword?: string
|
2022-10-05 15:37:15 +02:00
|
|
|
}) {
|
|
|
|
const { userId, currentPassword } = options
|
|
|
|
const path = '/api/v1/users/' + userId + '/two-factor/disable'
|
|
|
|
|
|
|
|
return this.postBodyRequest({
|
|
|
|
...options,
|
|
|
|
|
|
|
|
path,
|
|
|
|
fields: { currentPassword },
|
|
|
|
implicitToken: true,
|
|
|
|
defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
|
|
|
|
})
|
|
|
|
}
|
2022-10-07 14:23:42 +02:00
|
|
|
|
|
|
|
async requestAndConfirm (options: OverrideCommandOptions & {
|
|
|
|
userId: number
|
|
|
|
currentPassword?: string
|
|
|
|
}) {
|
|
|
|
const { userId, currentPassword } = options
|
|
|
|
|
|
|
|
const { otpRequest } = await this.request({ userId, currentPassword })
|
|
|
|
|
|
|
|
await this.confirmRequest({
|
|
|
|
userId,
|
|
|
|
requestToken: otpRequest.requestToken,
|
|
|
|
otpToken: TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate()
|
|
|
|
})
|
|
|
|
|
|
|
|
return otpRequest
|
|
|
|
}
|
2022-10-05 15:37:15 +02:00
|
|
|
}
|