aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/middlewares/validators/videos/shared/video-validators.ts8
-rw-r--r--server/tests/fixtures/peertube-plugin-test/main.js12
-rw-r--r--server/tests/plugins/action-hooks.ts8
-rw-r--r--server/tests/plugins/filter-hooks.ts19
-rw-r--r--shared/server-commands/videos/videos-command.ts30
5 files changed, 61 insertions, 16 deletions
diff --git a/server/middlewares/validators/videos/shared/video-validators.ts b/server/middlewares/validators/videos/shared/video-validators.ts
index 72536011d..95e4fef11 100644
--- a/server/middlewares/validators/videos/shared/video-validators.ts
+++ b/server/middlewares/validators/videos/shared/video-validators.ts
@@ -45,7 +45,7 @@ export async function isVideoFileAccepted (options: {
45 videoFile: express.VideoUploadFile 45 videoFile: express.VideoUploadFile
46 hook: Extract<ServerFilterHookName, 'filter:api.video.upload.accept.result' | 'filter:api.video.update-file.accept.result'> 46 hook: Extract<ServerFilterHookName, 'filter:api.video.upload.accept.result' | 'filter:api.video.update-file.accept.result'>
47}) { 47}) {
48 const { req, res, videoFile } = options 48 const { req, res, videoFile, hook } = options
49 49
50 // Check we accept this video 50 // Check we accept this video
51 const acceptParameters = { 51 const acceptParameters = {
@@ -53,11 +53,7 @@ export async function isVideoFileAccepted (options: {
53 videoFile, 53 videoFile,
54 user: res.locals.oauth.token.User 54 user: res.locals.oauth.token.User
55 } 55 }
56 const acceptedResult = await Hooks.wrapFun( 56 const acceptedResult = await Hooks.wrapFun(isLocalVideoFileAccepted, acceptParameters, hook)
57 isLocalVideoFileAccepted,
58 acceptParameters,
59 'filter:api.video.upload.accept.result'
60 )
61 57
62 if (!acceptedResult || acceptedResult.accepted !== true) { 58 if (!acceptedResult || acceptedResult.accepted !== true) {
63 logger.info('Refused local video file.', { acceptedResult, acceptParameters }) 59 logger.info('Refused local video file.', { acceptedResult, acceptParameters })
diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js
index 17032f6d9..e16bf0ca3 100644
--- a/server/tests/fixtures/peertube-plugin-test/main.js
+++ b/server/tests/fixtures/peertube-plugin-test/main.js
@@ -9,6 +9,8 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
9 'action:api.video.uploaded', 9 'action:api.video.uploaded',
10 'action:api.video.viewed', 10 'action:api.video.viewed',
11 11
12 'action:api.video.file-updated',
13
12 'action:api.video-channel.created', 14 'action:api.video-channel.created',
13 'action:api.video-channel.updated', 15 'action:api.video-channel.updated',
14 'action:api.video-channel.deleted', 16 'action:api.video-channel.deleted',
@@ -161,6 +163,16 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
161 } 163 }
162 164
163 registerHook({ 165 registerHook({
166 target: 'filter:api.video.update-file.accept.result',
167 handler: ({ accepted }, { videoFile }) => {
168 if (!accepted) return { accepted: false }
169 if (videoFile.filename.includes('webm')) return { accepted: false, errorMessage: 'no webm' }
170
171 return { accepted: true }
172 }
173 })
174
175 registerHook({
164 target: 'filter:api.video.pre-import-url.accept.result', 176 target: 'filter:api.video.pre-import-url.accept.result',
165 handler: ({ accepted }, { videoImportBody }) => { 177 handler: ({ accepted }, { videoImportBody }) => {
166 if (!accepted) return { accepted: false } 178 if (!accepted) return { accepted: false }
diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts
index 34b4e1891..773be0d76 100644
--- a/server/tests/plugins/action-hooks.ts
+++ b/server/tests/plugins/action-hooks.ts
@@ -40,6 +40,8 @@ describe('Test plugin action hooks', function () {
40 } 40 }
41 }) 41 })
42 42
43 await servers[0].config.enableFileUpdate()
44
43 await doubleFollow(servers[0], servers[1]) 45 await doubleFollow(servers[0], servers[1])
44 }) 46 })
45 47
@@ -70,6 +72,12 @@ describe('Test plugin action hooks', function () {
70 await checkHook('action:api.video.viewed') 72 await checkHook('action:api.video.viewed')
71 }) 73 })
72 74
75 it('Should run action:api.video.file-updated', async function () {
76 await servers[0].videos.replaceSourceFile({ videoId: videoUUID, fixture: 'video_short.mp4' })
77
78 await checkHook('action:api.video.file-updated')
79 })
80
73 it('Should run action:api.video.deleted', async function () { 81 it('Should run action:api.video.deleted', async function () {
74 await servers[0].videos.remove({ id: videoUUID }) 82 await servers[0].videos.remove({ id: videoUUID })
75 83
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts
index a75a8c8fa..8382b400f 100644
--- a/server/tests/plugins/filter-hooks.ts
+++ b/server/tests/plugins/filter-hooks.ts
@@ -64,6 +64,11 @@ describe('Test plugin filter hooks', function () {
64 newConfig: { 64 newConfig: {
65 live: { enabled: true }, 65 live: { enabled: true },
66 signup: { enabled: true }, 66 signup: { enabled: true },
67 videoFile: {
68 update: {
69 enabled: true
70 }
71 },
67 import: { 72 import: {
68 videos: { 73 videos: {
69 http: { enabled: true }, 74 http: { enabled: true },
@@ -178,7 +183,19 @@ describe('Test plugin filter hooks', function () {
178 describe('Video/live/import accept', function () { 183 describe('Video/live/import accept', function () {
179 184
180 it('Should run filter:api.video.upload.accept.result', async function () { 185 it('Should run filter:api.video.upload.accept.result', async function () {
181 await servers[0].videos.upload({ attributes: { name: 'video with bad word' }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) 186 const options = { attributes: { name: 'video with bad word' }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }
187 await servers[0].videos.upload({ mode: 'legacy', ...options })
188 await servers[0].videos.upload({ mode: 'resumable', ...options })
189 })
190
191 it('Should run filter:api.video.update-file.accept.result', async function () {
192 const res = await servers[0].videos.replaceSourceFile({
193 videoId: videoUUID,
194 fixture: 'video_short1.webm',
195 completedExpectedStatus: HttpStatusCode.FORBIDDEN_403
196 })
197
198 expect((res as any)?.error).to.equal('no webm')
182 }) 199 })
183 200
184 it('Should run filter:api.live-video.create.accept.result', async function () { 201 it('Should run filter:api.live-video.create.accept.result', async function () {
diff --git a/shared/server-commands/videos/videos-command.ts b/shared/server-commands/videos/videos-command.ts
index 3fdbc348a..a58f1c545 100644
--- a/shared/server-commands/videos/videos-command.ts
+++ b/shared/server-commands/videos/videos-command.ts
@@ -394,6 +394,7 @@ export class VideosCommand extends AbstractCommand {
394 attributes?: VideoEdit 394 attributes?: VideoEdit
395 mode?: 'legacy' | 'resumable' // default legacy 395 mode?: 'legacy' | 'resumable' // default legacy
396 waitTorrentGeneration?: boolean // default true 396 waitTorrentGeneration?: boolean // default true
397 completedExpectedStatus?: HttpStatusCode
397 } = {}) { 398 } = {}) {
398 const { mode = 'legacy', waitTorrentGeneration = true } = options 399 const { mode = 'legacy', waitTorrentGeneration = true } = options
399 let defaultChannelId = 1 400 let defaultChannelId = 1
@@ -461,8 +462,9 @@ export class VideosCommand extends AbstractCommand {
461 async buildResumeUpload (options: OverrideCommandOptions & { 462 async buildResumeUpload (options: OverrideCommandOptions & {
462 path: string 463 path: string
463 attributes: { fixture?: string } & { [id: string]: any } 464 attributes: { fixture?: string } & { [id: string]: any }
465 completedExpectedStatus?: HttpStatusCode // When the upload is finished
464 }): Promise<VideoCreateResult> { 466 }): Promise<VideoCreateResult> {
465 const { path, attributes, expectedStatus = HttpStatusCode.OK_200 } = options 467 const { path, attributes, expectedStatus = HttpStatusCode.OK_200, completedExpectedStatus } = options
466 468
467 let size = 0 469 let size = 0
468 let videoFilePath: string 470 let videoFilePath: string
@@ -503,7 +505,8 @@ export class VideosCommand extends AbstractCommand {
503 path, 505 path,
504 pathUploadId, 506 pathUploadId,
505 videoFilePath, 507 videoFilePath,
506 size 508 size,
509 expectedStatus: completedExpectedStatus
507 }) 510 })
508 511
509 if (result.statusCode === HttpStatusCode.OK_200) { 512 if (result.statusCode === HttpStatusCode.OK_200) {
@@ -600,12 +603,14 @@ export class VideosCommand extends AbstractCommand {
600 try { 603 try {
601 readable.pause() 604 readable.pause()
602 605
606 const byterangeStart = start + chunk.length - 1
607
603 const headers = { 608 const headers = {
604 'Authorization': 'Bearer ' + token, 609 'Authorization': 'Bearer ' + token,
605 'Content-Type': 'application/octet-stream', 610 'Content-Type': 'application/octet-stream',
606 'Content-Range': contentRangeBuilder 611 'Content-Range': contentRangeBuilder
607 ? contentRangeBuilder(start, chunk) 612 ? contentRangeBuilder(start, chunk)
608 : `bytes ${start}-${start + chunk.length - 1}/${size}`, 613 : `bytes ${start}-${byterangeStart}/${size}`,
609 'Content-Length': contentLength ? contentLength + '' : chunk.length + '' 614 'Content-Length': contentLength ? contentLength + '' : chunk.length + ''
610 } 615 }
611 616
@@ -625,13 +630,19 @@ export class VideosCommand extends AbstractCommand {
625 630
626 start += chunk.length 631 start += chunk.length
627 632
628 if (res.statusCode === expectedStatus) { 633 // Last request, check final status
629 return resolve(res) 634 if (byterangeStart + 1 === size) {
630 } 635 if (res.statusCode === expectedStatus) {
636 return resolve(res)
637 }
638
639 if (res.statusCode !== HttpStatusCode.PERMANENT_REDIRECT_308) {
640 readable.off('data', onData)
631 641
632 if (res.statusCode !== HttpStatusCode.PERMANENT_REDIRECT_308) { 642 // eslint-disable-next-line max-len
633 readable.off('data', onData) 643 const message = `Incorrect transient behaviour sending intermediary chunks. Status code is ${res.statusCode} instead of ${expectedStatus}`
634 return reject(new Error('Incorrect transient behaviour sending intermediary chunks')) 644 return reject(new Error(message))
645 }
635 } 646 }
636 647
637 readable.resume() 648 readable.resume()
@@ -694,6 +705,7 @@ export class VideosCommand extends AbstractCommand {
694 replaceSourceFile (options: OverrideCommandOptions & { 705 replaceSourceFile (options: OverrideCommandOptions & {
695 videoId: number | string 706 videoId: number | string
696 fixture: string 707 fixture: string
708 completedExpectedStatus?: HttpStatusCode
697 }) { 709 }) {
698 return this.buildResumeUpload({ 710 return this.buildResumeUpload({
699 ...options, 711 ...options,