]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/users/two-factor.ts
Support two factor authentication in backend
[github/Chocobozzz/PeerTube.git] / server / tests / api / users / two-factor.ts
CommitLineData
56f47830
C
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { expectStartWith } from '@server/tests/shared'
5import { HttpStatusCode } from '@shared/models'
6import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, TwoFactorCommand } from '@shared/server-commands'
7
8async function login (options: {
9 server: PeerTubeServer
10 password?: string
11 otpToken?: string
12 expectedStatus?: HttpStatusCode
13}) {
14 const { server, password = server.store.user.password, otpToken, expectedStatus } = options
15
16 const user = { username: server.store.user.username, password }
17 const { res, body: { access_token: token } } = await server.login.loginAndGetResponse({ user, otpToken, expectedStatus })
18
19 return { res, token }
20}
21
22describe('Test users', function () {
23 let server: PeerTubeServer
24 let rootId: number
25 let otpSecret: string
26 let requestToken: string
27
28 before(async function () {
29 this.timeout(30000)
30
31 server = await createSingleServer(1)
32
33 await setAccessTokensToServers([ server ])
34
35 const { id } = await server.users.getMyInfo()
36 rootId = id
37 })
38
39 it('Should not add the header on login if two factor is not enabled', async function () {
40 const { res, token } = await login({ server })
41
42 expect(res.header['x-peertube-otp']).to.not.exist
43
44 await server.users.getMyInfo({ token })
45 })
46
47 it('Should request two factor and get the secret and uri', async function () {
48 const { otpRequest } = await server.twoFactor.request({
49 userId: rootId,
50 currentPassword: server.store.user.password
51 })
52
53 expect(otpRequest.requestToken).to.exist
54
55 expect(otpRequest.secret).to.exist
56 expect(otpRequest.secret).to.have.lengthOf(32)
57
58 expect(otpRequest.uri).to.exist
59 expectStartWith(otpRequest.uri, 'otpauth://')
60 expect(otpRequest.uri).to.include(otpRequest.secret)
61
62 requestToken = otpRequest.requestToken
63 otpSecret = otpRequest.secret
64 })
65
66 it('Should not have two factor confirmed yet', async function () {
67 const { twoFactorEnabled } = await server.users.getMyInfo()
68 expect(twoFactorEnabled).to.be.false
69 })
70
71 it('Should confirm two factor', async function () {
72 await server.twoFactor.confirmRequest({
73 userId: rootId,
74 otpToken: TwoFactorCommand.buildOTP({ secret: otpSecret }).generate(),
75 requestToken
76 })
77 })
78
79 it('Should not add the header on login if two factor is enabled and password is incorrect', async function () {
80 const { res, token } = await login({ server, password: 'fake', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
81
82 expect(res.header['x-peertube-otp']).to.not.exist
83 expect(token).to.not.exist
84 })
85
86 it('Should add the header on login if two factor is enabled and password is correct', async function () {
87 const { res, token } = await login({ server, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
88
89 expect(res.header['x-peertube-otp']).to.exist
90 expect(token).to.not.exist
91
92 await server.users.getMyInfo({ token })
93 })
94
95 it('Should not login with correct password and incorrect otp secret', async function () {
96 const otp = TwoFactorCommand.buildOTP({ secret: 'a'.repeat(32) })
97
98 const { res, token } = await login({ server, otpToken: otp.generate(), expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
99
100 expect(res.header['x-peertube-otp']).to.not.exist
101 expect(token).to.not.exist
102 })
103
104 it('Should not login with correct password and incorrect otp code', async function () {
105 const { res, token } = await login({ server, otpToken: '123456', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
106
107 expect(res.header['x-peertube-otp']).to.not.exist
108 expect(token).to.not.exist
109 })
110
111 it('Should not login with incorrect password and correct otp code', async function () {
112 const otpToken = TwoFactorCommand.buildOTP({ secret: otpSecret }).generate()
113
114 const { res, token } = await login({ server, password: 'fake', otpToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
115
116 expect(res.header['x-peertube-otp']).to.not.exist
117 expect(token).to.not.exist
118 })
119
120 it('Should correctly login with correct password and otp code', async function () {
121 const otpToken = TwoFactorCommand.buildOTP({ secret: otpSecret }).generate()
122
123 const { res, token } = await login({ server, otpToken })
124
125 expect(res.header['x-peertube-otp']).to.not.exist
126 expect(token).to.exist
127
128 await server.users.getMyInfo({ token })
129 })
130
131 it('Should have two factor enabled when getting my info', async function () {
132 const { twoFactorEnabled } = await server.users.getMyInfo()
133 expect(twoFactorEnabled).to.be.true
134 })
135
136 it('Should disable two factor and be able to login without otp token', async function () {
137 await server.twoFactor.disable({ userId: rootId, currentPassword: server.store.user.password })
138
139 const { res, token } = await login({ server })
140 expect(res.header['x-peertube-otp']).to.not.exist
141
142 await server.users.getMyInfo({ token })
143 })
144
145 it('Should have two factor disabled when getting my info', async function () {
146 const { twoFactorEnabled } = await server.users.getMyInfo()
147 expect(twoFactorEnabled).to.be.false
148 })
149
150 after(async function () {
151 await cleanupTests([ server ])
152 })
153})