]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/api/check-params/plugins.ts
130cf6869062cf9a115c3e2f2098efc9547ee2c9
[github/Chocobozzz/PeerTube.git] / server / tests / api / check-params / plugins.ts
1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3 import 'mocha'
4 import { HttpStatusCode } from '@shared/core-utils'
5 import {
6 checkBadCountPagination,
7 checkBadSortPagination,
8 checkBadStartPagination,
9 cleanupTests,
10 createUser,
11 flushAndRunServer,
12 makeGetRequest,
13 makePostBodyRequest,
14 makePutBodyRequest,
15 ServerInfo,
16 setAccessTokensToServers
17 } from '@shared/extra-utils'
18 import { PeerTubePlugin, PluginType } from '@shared/models'
19
20 describe('Test server plugins API validators', function () {
21 let server: ServerInfo
22 let userAccessToken = null
23
24 const npmPlugin = 'peertube-plugin-hello-world'
25 const pluginName = 'hello-world'
26 let npmVersion: string
27
28 const themePlugin = 'peertube-theme-background-red'
29 const themeName = 'background-red'
30 let themeVersion: string
31
32 // ---------------------------------------------------------------
33
34 before(async function () {
35 this.timeout(30000)
36
37 server = await flushAndRunServer(1)
38
39 await setAccessTokensToServers([ server ])
40
41 const user = {
42 username: 'user1',
43 password: 'password'
44 }
45
46 await createUser({ url: server.url, accessToken: server.accessToken, username: user.username, password: user.password })
47 userAccessToken = await server.loginCommand.getAccessToken(user)
48
49 {
50 const res = await server.pluginsCommand.install({ npmName: npmPlugin })
51 const plugin = res.body as PeerTubePlugin
52 npmVersion = plugin.version
53 }
54
55 {
56 const res = await server.pluginsCommand.install({ npmName: themePlugin })
57 const plugin = res.body as PeerTubePlugin
58 themeVersion = plugin.version
59 }
60 })
61
62 describe('With static plugin routes', function () {
63 it('Should fail with an unknown plugin name/plugin version', async function () {
64 const paths = [
65 '/plugins/' + pluginName + '/0.0.1/auth/fake-auth',
66 '/plugins/' + pluginName + '/0.0.1/static/images/chocobo.png',
67 '/plugins/' + pluginName + '/0.0.1/client-scripts/client/common-client-plugin.js',
68 '/themes/' + themeName + '/0.0.1/static/images/chocobo.png',
69 '/themes/' + themeName + '/0.0.1/client-scripts/client/video-watch-client-plugin.js',
70 '/themes/' + themeName + '/0.0.1/css/assets/style1.css'
71 ]
72
73 for (const p of paths) {
74 await makeGetRequest({ url: server.url, path: p, statusCodeExpected: HttpStatusCode.NOT_FOUND_404 })
75 }
76 })
77
78 it('Should fail when requesting a plugin in the theme path', async function () {
79 await makeGetRequest({
80 url: server.url,
81 path: '/themes/' + pluginName + '/' + npmVersion + '/static/images/chocobo.png',
82 statusCodeExpected: HttpStatusCode.NOT_FOUND_404
83 })
84 })
85
86 it('Should fail with invalid versions', async function () {
87 const paths = [
88 '/plugins/' + pluginName + '/0.0.1.1/auth/fake-auth',
89 '/plugins/' + pluginName + '/0.0.1.1/static/images/chocobo.png',
90 '/plugins/' + pluginName + '/0.1/client-scripts/client/common-client-plugin.js',
91 '/themes/' + themeName + '/1/static/images/chocobo.png',
92 '/themes/' + themeName + '/0.0.1000a/client-scripts/client/video-watch-client-plugin.js',
93 '/themes/' + themeName + '/0.a.1/css/assets/style1.css'
94 ]
95
96 for (const p of paths) {
97 await makeGetRequest({ url: server.url, path: p, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 })
98 }
99 })
100
101 it('Should fail with invalid paths', async function () {
102 const paths = [
103 '/plugins/' + pluginName + '/' + npmVersion + '/static/images/../chocobo.png',
104 '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/../client/common-client-plugin.js',
105 '/themes/' + themeName + '/' + themeVersion + '/static/../images/chocobo.png',
106 '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/video-watch-client-plugin.js/..',
107 '/themes/' + themeName + '/' + themeVersion + '/css/../assets/style1.css'
108 ]
109
110 for (const p of paths) {
111 await makeGetRequest({ url: server.url, path: p, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 })
112 }
113 })
114
115 it('Should fail with an unknown auth name', async function () {
116 const path = '/plugins/' + pluginName + '/' + npmVersion + '/auth/bad-auth'
117
118 await makeGetRequest({ url: server.url, path, statusCodeExpected: HttpStatusCode.NOT_FOUND_404 })
119 })
120
121 it('Should fail with an unknown static file', async function () {
122 const paths = [
123 '/plugins/' + pluginName + '/' + npmVersion + '/static/fake/chocobo.png',
124 '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/client/fake.js',
125 '/themes/' + themeName + '/' + themeVersion + '/static/fake/chocobo.png',
126 '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/fake.js'
127 ]
128
129 for (const p of paths) {
130 await makeGetRequest({ url: server.url, path: p, statusCodeExpected: HttpStatusCode.NOT_FOUND_404 })
131 }
132 })
133
134 it('Should fail with an unknown CSS file', async function () {
135 await makeGetRequest({
136 url: server.url,
137 path: '/themes/' + themeName + '/' + themeVersion + '/css/assets/fake.css',
138 statusCodeExpected: HttpStatusCode.NOT_FOUND_404
139 })
140 })
141
142 it('Should succeed with the correct parameters', async function () {
143 const paths = [
144 '/plugins/' + pluginName + '/' + npmVersion + '/static/images/chocobo.png',
145 '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/client/common-client-plugin.js',
146 '/themes/' + themeName + '/' + themeVersion + '/static/images/chocobo.png',
147 '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/video-watch-client-plugin.js',
148 '/themes/' + themeName + '/' + themeVersion + '/css/assets/style1.css'
149 ]
150
151 for (const p of paths) {
152 await makeGetRequest({ url: server.url, path: p, statusCodeExpected: HttpStatusCode.OK_200 })
153 }
154
155 const authPath = '/plugins/' + pluginName + '/' + npmVersion + '/auth/fake-auth'
156 await makeGetRequest({ url: server.url, path: authPath, statusCodeExpected: HttpStatusCode.FOUND_302 })
157 })
158 })
159
160 describe('When listing available plugins/themes', function () {
161 const path = '/api/v1/plugins/available'
162 const baseQuery = {
163 search: 'super search',
164 pluginType: PluginType.PLUGIN,
165 currentPeerTubeEngine: '1.2.3'
166 }
167
168 it('Should fail with an invalid token', async function () {
169 await makeGetRequest({
170 url: server.url,
171 path,
172 token: 'fake_token',
173 query: baseQuery,
174 statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
175 })
176 })
177
178 it('Should fail if the user is not an administrator', async function () {
179 await makeGetRequest({
180 url: server.url,
181 path,
182 token: userAccessToken,
183 query: baseQuery,
184 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
185 })
186 })
187
188 it('Should fail with a bad start pagination', async function () {
189 await checkBadStartPagination(server.url, path, server.accessToken)
190 })
191
192 it('Should fail with a bad count pagination', async function () {
193 await checkBadCountPagination(server.url, path, server.accessToken)
194 })
195
196 it('Should fail with an incorrect sort', async function () {
197 await checkBadSortPagination(server.url, path, server.accessToken)
198 })
199
200 it('Should fail with an invalid plugin type', async function () {
201 const query = { ...baseQuery, pluginType: 5 }
202
203 await makeGetRequest({
204 url: server.url,
205 path,
206 token: server.accessToken,
207 query
208 })
209 })
210
211 it('Should fail with an invalid current peertube engine', async function () {
212 const query = { ...baseQuery, currentPeerTubeEngine: '1.0' }
213
214 await makeGetRequest({
215 url: server.url,
216 path,
217 token: server.accessToken,
218 query
219 })
220 })
221
222 it('Should success with the correct parameters', async function () {
223 await makeGetRequest({
224 url: server.url,
225 path,
226 token: server.accessToken,
227 query: baseQuery,
228 statusCodeExpected: HttpStatusCode.OK_200
229 })
230 })
231 })
232
233 describe('When listing local plugins/themes', function () {
234 const path = '/api/v1/plugins'
235 const baseQuery = {
236 pluginType: PluginType.THEME
237 }
238
239 it('Should fail with an invalid token', async function () {
240 await makeGetRequest({
241 url: server.url,
242 path,
243 token: 'fake_token',
244 query: baseQuery,
245 statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
246 })
247 })
248
249 it('Should fail if the user is not an administrator', async function () {
250 await makeGetRequest({
251 url: server.url,
252 path,
253 token: userAccessToken,
254 query: baseQuery,
255 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
256 })
257 })
258
259 it('Should fail with a bad start pagination', async function () {
260 await checkBadStartPagination(server.url, path, server.accessToken)
261 })
262
263 it('Should fail with a bad count pagination', async function () {
264 await checkBadCountPagination(server.url, path, server.accessToken)
265 })
266
267 it('Should fail with an incorrect sort', async function () {
268 await checkBadSortPagination(server.url, path, server.accessToken)
269 })
270
271 it('Should fail with an invalid plugin type', async function () {
272 const query = { ...baseQuery, pluginType: 5 }
273
274 await makeGetRequest({
275 url: server.url,
276 path,
277 token: server.accessToken,
278 query
279 })
280 })
281
282 it('Should success with the correct parameters', async function () {
283 await makeGetRequest({
284 url: server.url,
285 path,
286 token: server.accessToken,
287 query: baseQuery,
288 statusCodeExpected: HttpStatusCode.OK_200
289 })
290 })
291 })
292
293 describe('When getting a plugin or the registered settings or public settings', function () {
294 const path = '/api/v1/plugins/'
295
296 it('Should fail with an invalid token', async function () {
297 for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings` ]) {
298 await makeGetRequest({
299 url: server.url,
300 path: path + suffix,
301 token: 'fake_token',
302 statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
303 })
304 }
305 })
306
307 it('Should fail if the user is not an administrator', async function () {
308 for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings` ]) {
309 await makeGetRequest({
310 url: server.url,
311 path: path + suffix,
312 token: userAccessToken,
313 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
314 })
315 }
316 })
317
318 it('Should fail with an invalid npm name', async function () {
319 for (const suffix of [ 'toto', 'toto/registered-settings', 'toto/public-settings' ]) {
320 await makeGetRequest({
321 url: server.url,
322 path: path + suffix,
323 token: server.accessToken,
324 statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
325 })
326 }
327
328 for (const suffix of [ 'peertube-plugin-TOTO', 'peertube-plugin-TOTO/registered-settings', 'peertube-plugin-TOTO/public-settings' ]) {
329 await makeGetRequest({
330 url: server.url,
331 path: path + suffix,
332 token: server.accessToken,
333 statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
334 })
335 }
336 })
337
338 it('Should fail with an unknown plugin', async function () {
339 for (const suffix of [ 'peertube-plugin-toto', 'peertube-plugin-toto/registered-settings', 'peertube-plugin-toto/public-settings' ]) {
340 await makeGetRequest({
341 url: server.url,
342 path: path + suffix,
343 token: server.accessToken,
344 statusCodeExpected: HttpStatusCode.NOT_FOUND_404
345 })
346 }
347 })
348
349 it('Should succeed with the correct parameters', async function () {
350 for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings`, `${npmPlugin}/public-settings` ]) {
351 await makeGetRequest({
352 url: server.url,
353 path: path + suffix,
354 token: server.accessToken,
355 statusCodeExpected: HttpStatusCode.OK_200
356 })
357 }
358 })
359 })
360
361 describe('When updating plugin settings', function () {
362 const path = '/api/v1/plugins/'
363 const settings = { setting1: 'value1' }
364
365 it('Should fail with an invalid token', async function () {
366 await makePutBodyRequest({
367 url: server.url,
368 path: path + npmPlugin + '/settings',
369 fields: { settings },
370 token: 'fake_token',
371 statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
372 })
373 })
374
375 it('Should fail if the user is not an administrator', async function () {
376 await makePutBodyRequest({
377 url: server.url,
378 path: path + npmPlugin + '/settings',
379 fields: { settings },
380 token: userAccessToken,
381 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
382 })
383 })
384
385 it('Should fail with an invalid npm name', async function () {
386 await makePutBodyRequest({
387 url: server.url,
388 path: path + 'toto/settings',
389 fields: { settings },
390 token: server.accessToken,
391 statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
392 })
393
394 await makePutBodyRequest({
395 url: server.url,
396 path: path + 'peertube-plugin-TOTO/settings',
397 fields: { settings },
398 token: server.accessToken,
399 statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
400 })
401 })
402
403 it('Should fail with an unknown plugin', async function () {
404 await makePutBodyRequest({
405 url: server.url,
406 path: path + 'peertube-plugin-toto/settings',
407 fields: { settings },
408 token: server.accessToken,
409 statusCodeExpected: HttpStatusCode.NOT_FOUND_404
410 })
411 })
412
413 it('Should succeed with the correct parameters', async function () {
414 await makePutBodyRequest({
415 url: server.url,
416 path: path + npmPlugin + '/settings',
417 fields: { settings },
418 token: server.accessToken,
419 statusCodeExpected: HttpStatusCode.NO_CONTENT_204
420 })
421 })
422 })
423
424 describe('When installing/updating/uninstalling a plugin', function () {
425 const path = '/api/v1/plugins/'
426
427 it('Should fail with an invalid token', async function () {
428 for (const suffix of [ 'install', 'update', 'uninstall' ]) {
429 await makePostBodyRequest({
430 url: server.url,
431 path: path + suffix,
432 fields: { npmName: npmPlugin },
433 token: 'fake_token',
434 statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
435 })
436 }
437 })
438
439 it('Should fail if the user is not an administrator', async function () {
440 for (const suffix of [ 'install', 'update', 'uninstall' ]) {
441 await makePostBodyRequest({
442 url: server.url,
443 path: path + suffix,
444 fields: { npmName: npmPlugin },
445 token: userAccessToken,
446 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
447 })
448 }
449 })
450
451 it('Should fail with an invalid npm name', async function () {
452 for (const suffix of [ 'install', 'update', 'uninstall' ]) {
453 await makePostBodyRequest({
454 url: server.url,
455 path: path + suffix,
456 fields: { npmName: 'toto' },
457 token: server.accessToken,
458 statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
459 })
460 }
461
462 for (const suffix of [ 'install', 'update', 'uninstall' ]) {
463 await makePostBodyRequest({
464 url: server.url,
465 path: path + suffix,
466 fields: { npmName: 'peertube-plugin-TOTO' },
467 token: server.accessToken,
468 statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
469 })
470 }
471 })
472
473 it('Should succeed with the correct parameters', async function () {
474 this.timeout(10000)
475
476 const it = [
477 { suffix: 'install', status: HttpStatusCode.OK_200 },
478 { suffix: 'update', status: HttpStatusCode.OK_200 },
479 { suffix: 'uninstall', status: HttpStatusCode.NO_CONTENT_204 }
480 ]
481
482 for (const obj of it) {
483 await makePostBodyRequest({
484 url: server.url,
485 path: path + obj.suffix,
486 fields: { npmName: npmPlugin },
487 token: server.accessToken,
488 statusCodeExpected: obj.status
489 })
490 }
491 })
492 })
493
494 after(async function () {
495 await cleanupTests([ server ])
496 })
497 })