diff options
Diffstat (limited to 'packages/tests/src/api/users/two-factor.ts')
-rw-r--r-- | packages/tests/src/api/users/two-factor.ts | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/packages/tests/src/api/users/two-factor.ts b/packages/tests/src/api/users/two-factor.ts new file mode 100644 index 000000000..fda125d20 --- /dev/null +++ b/packages/tests/src/api/users/two-factor.ts | |||
@@ -0,0 +1,206 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { HttpStatusCode, HttpStatusCodeType } from '@peertube/peertube-models' | ||
5 | import { expectStartWith } from '@tests/shared/checks.js' | ||
6 | import { | ||
7 | cleanupTests, | ||
8 | createSingleServer, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | TwoFactorCommand | ||
12 | } from '@peertube/peertube-server-commands' | ||
13 | |||
14 | async function login (options: { | ||
15 | server: PeerTubeServer | ||
16 | username: string | ||
17 | password: string | ||
18 | otpToken?: string | ||
19 | expectedStatus?: HttpStatusCodeType | ||
20 | }) { | ||
21 | const { server, username, password, otpToken, expectedStatus } = options | ||
22 | |||
23 | const user = { username, password } | ||
24 | const { res, body: { access_token: token } } = await server.login.loginAndGetResponse({ user, otpToken, expectedStatus }) | ||
25 | |||
26 | return { res, token } | ||
27 | } | ||
28 | |||
29 | describe('Test users', function () { | ||
30 | let server: PeerTubeServer | ||
31 | let otpSecret: string | ||
32 | let requestToken: string | ||
33 | |||
34 | const userUsername = 'user1' | ||
35 | let userId: number | ||
36 | let userPassword: string | ||
37 | let userToken: string | ||
38 | |||
39 | before(async function () { | ||
40 | this.timeout(30000) | ||
41 | |||
42 | server = await createSingleServer(1) | ||
43 | |||
44 | await setAccessTokensToServers([ server ]) | ||
45 | const res = await server.users.generate(userUsername) | ||
46 | userId = res.userId | ||
47 | userPassword = res.password | ||
48 | userToken = res.token | ||
49 | }) | ||
50 | |||
51 | it('Should not add the header on login if two factor is not enabled', async function () { | ||
52 | const { res, token } = await login({ server, username: userUsername, password: userPassword }) | ||
53 | |||
54 | expect(res.header['x-peertube-otp']).to.not.exist | ||
55 | |||
56 | await server.users.getMyInfo({ token }) | ||
57 | }) | ||
58 | |||
59 | it('Should request two factor and get the secret and uri', async function () { | ||
60 | const { otpRequest } = await server.twoFactor.request({ userId, token: userToken, currentPassword: userPassword }) | ||
61 | |||
62 | expect(otpRequest.requestToken).to.exist | ||
63 | |||
64 | expect(otpRequest.secret).to.exist | ||
65 | expect(otpRequest.secret).to.have.lengthOf(32) | ||
66 | |||
67 | expect(otpRequest.uri).to.exist | ||
68 | expectStartWith(otpRequest.uri, 'otpauth://') | ||
69 | expect(otpRequest.uri).to.include(otpRequest.secret) | ||
70 | |||
71 | requestToken = otpRequest.requestToken | ||
72 | otpSecret = otpRequest.secret | ||
73 | }) | ||
74 | |||
75 | it('Should not have two factor confirmed yet', async function () { | ||
76 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
77 | expect(twoFactorEnabled).to.be.false | ||
78 | }) | ||
79 | |||
80 | it('Should confirm two factor', async function () { | ||
81 | await server.twoFactor.confirmRequest({ | ||
82 | userId, | ||
83 | token: userToken, | ||
84 | otpToken: TwoFactorCommand.buildOTP({ secret: otpSecret }).generate(), | ||
85 | requestToken | ||
86 | }) | ||
87 | }) | ||
88 | |||
89 | it('Should not add the header on login if two factor is enabled and password is incorrect', async function () { | ||
90 | const { res, token } = await login({ server, username: userUsername, password: 'fake', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
91 | |||
92 | expect(res.header['x-peertube-otp']).to.not.exist | ||
93 | expect(token).to.not.exist | ||
94 | }) | ||
95 | |||
96 | it('Should add the header on login if two factor is enabled and password is correct', async function () { | ||
97 | const { res, token } = await login({ | ||
98 | server, | ||
99 | username: userUsername, | ||
100 | password: userPassword, | ||
101 | expectedStatus: HttpStatusCode.UNAUTHORIZED_401 | ||
102 | }) | ||
103 | |||
104 | expect(res.header['x-peertube-otp']).to.exist | ||
105 | expect(token).to.not.exist | ||
106 | |||
107 | await server.users.getMyInfo({ token }) | ||
108 | }) | ||
109 | |||
110 | it('Should not login with correct password and incorrect otp secret', async function () { | ||
111 | const otp = TwoFactorCommand.buildOTP({ secret: 'a'.repeat(32) }) | ||
112 | |||
113 | const { res, token } = await login({ | ||
114 | server, | ||
115 | username: userUsername, | ||
116 | password: userPassword, | ||
117 | otpToken: otp.generate(), | ||
118 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
119 | }) | ||
120 | |||
121 | expect(res.header['x-peertube-otp']).to.not.exist | ||
122 | expect(token).to.not.exist | ||
123 | }) | ||
124 | |||
125 | it('Should not login with correct password and incorrect otp code', async function () { | ||
126 | const { res, token } = await login({ | ||
127 | server, | ||
128 | username: userUsername, | ||
129 | password: userPassword, | ||
130 | otpToken: '123456', | ||
131 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
132 | }) | ||
133 | |||
134 | expect(res.header['x-peertube-otp']).to.not.exist | ||
135 | expect(token).to.not.exist | ||
136 | }) | ||
137 | |||
138 | it('Should not login with incorrect password and correct otp code', async function () { | ||
139 | const otpToken = TwoFactorCommand.buildOTP({ secret: otpSecret }).generate() | ||
140 | |||
141 | const { res, token } = await login({ | ||
142 | server, | ||
143 | username: userUsername, | ||
144 | password: 'fake', | ||
145 | otpToken, | ||
146 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
147 | }) | ||
148 | |||
149 | expect(res.header['x-peertube-otp']).to.not.exist | ||
150 | expect(token).to.not.exist | ||
151 | }) | ||
152 | |||
153 | it('Should correctly login with correct password and otp code', async function () { | ||
154 | const otpToken = TwoFactorCommand.buildOTP({ secret: otpSecret }).generate() | ||
155 | |||
156 | const { res, token } = await login({ server, username: userUsername, password: userPassword, otpToken }) | ||
157 | |||
158 | expect(res.header['x-peertube-otp']).to.not.exist | ||
159 | expect(token).to.exist | ||
160 | |||
161 | await server.users.getMyInfo({ token }) | ||
162 | }) | ||
163 | |||
164 | it('Should have two factor enabled when getting my info', async function () { | ||
165 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
166 | expect(twoFactorEnabled).to.be.true | ||
167 | }) | ||
168 | |||
169 | it('Should disable two factor and be able to login without otp token', async function () { | ||
170 | await server.twoFactor.disable({ userId, token: userToken, currentPassword: userPassword }) | ||
171 | |||
172 | const { res, token } = await login({ server, username: userUsername, password: userPassword }) | ||
173 | expect(res.header['x-peertube-otp']).to.not.exist | ||
174 | |||
175 | await server.users.getMyInfo({ token }) | ||
176 | }) | ||
177 | |||
178 | it('Should have two factor disabled when getting my info', async function () { | ||
179 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
180 | expect(twoFactorEnabled).to.be.false | ||
181 | }) | ||
182 | |||
183 | it('Should enable two factor auth without password from an admin', async function () { | ||
184 | const { otpRequest } = await server.twoFactor.request({ userId }) | ||
185 | |||
186 | await server.twoFactor.confirmRequest({ | ||
187 | userId, | ||
188 | otpToken: TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate(), | ||
189 | requestToken: otpRequest.requestToken | ||
190 | }) | ||
191 | |||
192 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
193 | expect(twoFactorEnabled).to.be.true | ||
194 | }) | ||
195 | |||
196 | it('Should disable two factor auth without password from an admin', async function () { | ||
197 | await server.twoFactor.disable({ userId }) | ||
198 | |||
199 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
200 | expect(twoFactorEnabled).to.be.false | ||
201 | }) | ||
202 | |||
203 | after(async function () { | ||
204 | await cleanupTests([ server ]) | ||
205 | }) | ||
206 | }) | ||