aboutsummaryrefslogtreecommitdiffhomepage
path: root/packages/tests/src/api/users/oauth.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-07-31 14:34:36 +0200
committerChocobozzz <me@florianbigard.com>2023-08-11 15:02:33 +0200
commit3a4992633ee62d5edfbb484d9c6bcb3cf158489d (patch)
treee4510b39bdac9c318fdb4b47018d08f15368b8f0 /packages/tests/src/api/users/oauth.ts
parent04d1da5621d25d59bd5fa1543b725c497bf5d9a8 (diff)
downloadPeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.gz
PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.zst
PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.zip
Migrate server to ESM
Sorry for the very big commit that may lead to git log issues and merge conflicts, but it's a major step forward: * Server can be faster at startup because imports() are async and we can easily lazy import big modules * Angular doesn't seem to support ES import (with .js extension), so we had to correctly organize peertube into a monorepo: * Use yarn workspace feature * Use typescript reference projects for dependencies * Shared projects have been moved into "packages", each one is now a node module (with a dedicated package.json/tsconfig.json) * server/tools have been moved into apps/ and is now a dedicated app bundled and published on NPM so users don't have to build peertube cli tools manually * server/tests have been moved into packages/ so we don't compile them every time we want to run the server * Use isolatedModule option: * Had to move from const enum to const (https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums) * Had to explictely specify "type" imports when used in decorators * Prefer tsx (that uses esbuild under the hood) instead of ts-node to load typescript files (tests with mocha or scripts): * To reduce test complexity as esbuild doesn't support decorator metadata, we only test server files that do not import server models * We still build tests files into js files for a faster CI * Remove unmaintained peertube CLI import script * Removed some barrels to speed up execution (less imports)
Diffstat (limited to 'packages/tests/src/api/users/oauth.ts')
-rw-r--r--packages/tests/src/api/users/oauth.ts203
1 files changed, 203 insertions, 0 deletions
diff --git a/packages/tests/src/api/users/oauth.ts b/packages/tests/src/api/users/oauth.ts
new file mode 100644
index 000000000..fe50872cb
--- /dev/null
+++ b/packages/tests/src/api/users/oauth.ts
@@ -0,0 +1,203 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { wait } from '@peertube/peertube-core-utils'
5import { HttpStatusCode, OAuth2ErrorCode, PeerTubeProblemDocument } from '@peertube/peertube-models'
6import { SQLCommand } from '@tests/shared/sql-command.js'
7import {
8 cleanupTests,
9 createSingleServer,
10 killallServers,
11 PeerTubeServer,
12 setAccessTokensToServers
13} from '@peertube/peertube-server-commands'
14
15describe('Test oauth', function () {
16 let server: PeerTubeServer
17 let sqlCommand: SQLCommand
18
19 before(async function () {
20 this.timeout(30000)
21
22 server = await createSingleServer(1, {
23 rates_limit: {
24 login: {
25 max: 30
26 }
27 }
28 })
29
30 await setAccessTokensToServers([ server ])
31
32 sqlCommand = new SQLCommand(server)
33 })
34
35 describe('OAuth client', function () {
36
37 function expectInvalidClient (body: PeerTubeProblemDocument) {
38 expect(body.code).to.equal(OAuth2ErrorCode.INVALID_CLIENT)
39 expect(body.error).to.contain('client is invalid')
40 expect(body.type.startsWith('https://')).to.be.true
41 expect(body.type).to.contain(OAuth2ErrorCode.INVALID_CLIENT)
42 }
43
44 it('Should create a new client')
45
46 it('Should return the first client')
47
48 it('Should remove the last client')
49
50 it('Should not login with an invalid client id', async function () {
51 const client = { id: 'client', secret: server.store.client.secret }
52 const body = await server.login.login({ client, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
53
54 expectInvalidClient(body)
55 })
56
57 it('Should not login with an invalid client secret', async function () {
58 const client = { id: server.store.client.id, secret: 'coucou' }
59 const body = await server.login.login({ client, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
60
61 expectInvalidClient(body)
62 })
63 })
64
65 describe('Login', function () {
66
67 function expectInvalidCredentials (body: PeerTubeProblemDocument) {
68 expect(body.code).to.equal(OAuth2ErrorCode.INVALID_GRANT)
69 expect(body.error).to.contain('credentials are invalid')
70 expect(body.type.startsWith('https://')).to.be.true
71 expect(body.type).to.contain(OAuth2ErrorCode.INVALID_GRANT)
72 }
73
74 it('Should not login with an invalid username', async function () {
75 const user = { username: 'captain crochet', password: server.store.user.password }
76 const body = await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
77
78 expectInvalidCredentials(body)
79 })
80
81 it('Should not login with an invalid password', async function () {
82 const user = { username: server.store.user.username, password: 'mew_three' }
83 const body = await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
84
85 expectInvalidCredentials(body)
86 })
87
88 it('Should be able to login', async function () {
89 await server.login.login({ expectedStatus: HttpStatusCode.OK_200 })
90 })
91
92 it('Should be able to login with an insensitive username', async function () {
93 const user = { username: 'RoOt', password: server.store.user.password }
94 await server.login.login({ user, expectedStatus: HttpStatusCode.OK_200 })
95
96 const user2 = { username: 'rOoT', password: server.store.user.password }
97 await server.login.login({ user: user2, expectedStatus: HttpStatusCode.OK_200 })
98
99 const user3 = { username: 'ROOt', password: server.store.user.password }
100 await server.login.login({ user: user3, expectedStatus: HttpStatusCode.OK_200 })
101 })
102 })
103
104 describe('Logout', function () {
105
106 it('Should logout (revoke token)', async function () {
107 await server.login.logout({ token: server.accessToken })
108 })
109
110 it('Should not be able to get the user information', async function () {
111 await server.users.getMyInfo({ expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
112 })
113
114 it('Should not be able to upload a video', async function () {
115 await server.videos.upload({ attributes: { name: 'video' }, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
116 })
117
118 it('Should be able to login again', async function () {
119 const body = await server.login.login()
120 server.accessToken = body.access_token
121 server.refreshToken = body.refresh_token
122 })
123
124 it('Should be able to get my user information again', async function () {
125 await server.users.getMyInfo()
126 })
127
128 it('Should have an expired access token', async function () {
129 this.timeout(60000)
130
131 await sqlCommand.setTokenField(server.accessToken, 'accessTokenExpiresAt', new Date().toISOString())
132 await sqlCommand.setTokenField(server.accessToken, 'refreshTokenExpiresAt', new Date().toISOString())
133
134 await killallServers([ server ])
135 await server.run()
136
137 await server.users.getMyInfo({ expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
138 })
139
140 it('Should not be able to refresh an access token with an expired refresh token', async function () {
141 await server.login.refreshToken({ refreshToken: server.refreshToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
142 })
143
144 it('Should refresh the token', async function () {
145 this.timeout(50000)
146
147 const futureDate = new Date(new Date().getTime() + 1000 * 60).toISOString()
148 await sqlCommand.setTokenField(server.accessToken, 'refreshTokenExpiresAt', futureDate)
149
150 await killallServers([ server ])
151 await server.run()
152
153 const res = await server.login.refreshToken({ refreshToken: server.refreshToken })
154 server.accessToken = res.body.access_token
155 server.refreshToken = res.body.refresh_token
156 })
157
158 it('Should be able to get my user information again', async function () {
159 await server.users.getMyInfo()
160 })
161 })
162
163 describe('Custom token lifetime', function () {
164 before(async function () {
165 this.timeout(120_000)
166
167 await server.kill()
168 await server.run({
169 oauth2: {
170 token_lifetime: {
171 access_token: '2 seconds',
172 refresh_token: '2 seconds'
173 }
174 }
175 })
176 })
177
178 it('Should have a very short access token lifetime', async function () {
179 this.timeout(50000)
180
181 const { access_token: accessToken } = await server.login.login()
182 await server.users.getMyInfo({ token: accessToken })
183
184 await wait(3000)
185 await server.users.getMyInfo({ token: accessToken, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
186 })
187
188 it('Should have a very short refresh token lifetime', async function () {
189 this.timeout(50000)
190
191 const { refresh_token: refreshToken } = await server.login.login()
192 await server.login.refreshToken({ refreshToken })
193
194 await wait(3000)
195 await server.login.refreshToken({ refreshToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
196 })
197 })
198
199 after(async function () {
200 await sqlCommand.cleanup()
201 await cleanupTests([ server ])
202 })
203})