From f2eb23cd87cf32b8fe545178143b5f49e06a58da Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Tue, 8 Dec 2020 21:16:10 +0100 Subject: [PATCH] emit more specific status codes on video upload (#3423) - reduce http status codes list to potentially useful codes - convert more codes to typed ones - factorize html generator for error responses --- .../contact-admin-modal.component.ts | 3 +- .../src/app/+accounts/accounts.component.ts | 6 +- .../my-video-channel-create.component.ts | 3 +- .../video-channels.component.ts | 6 +- .../video-upload.component.ts | 22 ++-- .../+video-watch/video-watch.component.ts | 24 +++- client/src/app/core/auth/auth.service.ts | 3 +- .../app/core/rest/rest-extractor.service.ts | 9 +- client/src/standalone/videos/embed.ts | 13 +- server/controllers/client.ts | 32 +---- server/controllers/static.ts | 14 +++ server/helpers/custom-validators/misc.ts | 46 ++++++++ server/helpers/custom-validators/videos.ts | 8 +- server/helpers/youtube-dl.ts | 5 +- server/lib/activitypub/actor.ts | 3 +- server/lib/activitypub/playlist.ts | 3 +- server/lib/activitypub/videos.ts | 3 +- server/lib/client-html.ts | 42 ++++++- server/middlewares/cache.ts | 6 +- .../middlewares/validators/videos/videos.ts | 41 +++++-- server/tests/api/activitypub/client.ts | 3 +- server/tests/api/activitypub/refresher.ts | 15 +-- server/tests/api/check-params/accounts.ts | 3 +- server/tests/api/check-params/contact-form.ts | 59 ++++++++-- server/tests/api/check-params/users.ts | 12 +- server/tests/api/check-params/videos.ts | 18 ++- server/tests/api/live/live-save-replay.ts | 33 +++--- server/tests/api/live/live.ts | 19 +-- server/tests/api/server/config.ts | 9 +- server/tests/api/server/contact-form.ts | 3 +- server/tests/api/server/email.ts | 13 +- server/tests/api/server/follow-constraints.ts | 17 +-- server/tests/api/server/handle-down.ts | 3 +- server/tests/api/server/no-client.ts | 3 +- server/tests/api/server/reverse-proxy.ts | 25 ++-- server/tests/api/videos/multiple-servers.ts | 5 +- .../api/videos/video-change-ownership.ts | 14 ++- server/tests/api/videos/video-hls.ts | 9 +- server/tests/api/videos/video-playlists.ts | 13 +- server/tests/api/videos/video-privacy.ts | 13 +- server/tests/api/videos/videos-history.ts | 3 +- server/tests/cli/reset-password.ts | 3 +- server/tests/feeds/feeds.ts | 17 ++- server/tests/plugins/filter-hooks.ts | 24 ++-- server/tests/plugins/video-constants.ts | 10 +- server/tools/peertube-redundancy.ts | 5 +- shared/core-utils/miscs/http-error-codes.ts | 111 ++++-------------- shared/extra-utils/server/activitypub.ts | 3 +- shared/extra-utils/server/redundancy.ts | 8 +- shared/extra-utils/users/login.ts | 13 +- shared/extra-utils/videos/video-history.ts | 8 +- shared/extra-utils/videos/videos.ts | 4 +- support/doc/api/openapi.yaml | 20 ++-- 53 files changed, 503 insertions(+), 307 deletions(-) diff --git a/client/src/app/+about/about-instance/contact-admin-modal.component.ts b/client/src/app/+about/about-instance/contact-admin-modal.component.ts index 11e442f6b..ac2a6c980 100644 --- a/client/src/app/+about/about-instance/contact-admin-modal.component.ts +++ b/client/src/app/+about/about-instance/contact-admin-modal.component.ts @@ -10,6 +10,7 @@ import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' import { InstanceService } from '@app/shared/shared-instance' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' import { ServerConfig } from '@shared/models' @Component({ @@ -78,7 +79,7 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit { }, err => { - this.error = err.status === 403 + this.error = err.status === HttpStatusCode.FORBIDDEN_403 ? $localize`You already sent this form recently` : err.message } diff --git a/client/src/app/+accounts/accounts.component.ts b/client/src/app/+accounts/accounts.component.ts index dbc7c8887..4820eaf32 100644 --- a/client/src/app/+accounts/accounts.component.ts +++ b/client/src/app/+accounts/accounts.component.ts @@ -6,6 +6,7 @@ import { AuthService, Notifier, RedirectService, RestExtractor, ScreenService, U import { Account, AccountService, DropdownAction, ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main' import { AccountReportComponent } from '@app/shared/shared-moderation' import { User, UserRight } from '@shared/models' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' @Component({ templateUrl: './accounts.component.html', @@ -47,7 +48,10 @@ export class AccountsComponent implements OnInit, OnDestroy { switchMap(accountId => this.accountService.getAccount(accountId)), tap(account => this.onAccount(account)), switchMap(account => this.videoChannelService.listAccountVideoChannels(account)), - catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])) + catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ + HttpStatusCode.BAD_REQUEST_400, + HttpStatusCode.NOT_FOUND_404 + ])) ) .subscribe( videoChannels => this.videoChannels = videoChannels.data, diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts index 1d0cbf246..a625493de 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts +++ b/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts @@ -10,6 +10,7 @@ import { import { FormValidatorService } from '@app/shared/shared-forms' import { VideoChannelService } from '@app/shared/shared-main' import { VideoChannelCreate } from '@shared/models' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' import { MyVideoChannelEdit } from './my-video-channel-edit' @Component({ @@ -58,7 +59,7 @@ export class MyVideoChannelCreateComponent extends MyVideoChannelEdit implements }, err => { - if (err.status === 409) { + if (err.status === HttpStatusCode.CONFLICT_409) { this.error = $localize`This name already exists on this instance.` return } diff --git a/client/src/app/+video-channels/video-channels.component.ts b/client/src/app/+video-channels/video-channels.component.ts index ea8bda1cf..d2fd265c4 100644 --- a/client/src/app/+video-channels/video-channels.component.ts +++ b/client/src/app/+video-channels/video-channels.component.ts @@ -6,6 +6,7 @@ import { ActivatedRoute } from '@angular/router' import { AuthService, Notifier, RestExtractor, ScreenService } from '@app/core' import { ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main' import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' @Component({ templateUrl: './video-channels.component.html', @@ -37,7 +38,10 @@ export class VideoChannelsComponent implements OnInit, OnDestroy { map(params => params[ 'videoChannelName' ]), distinctUntilChanged(), switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)), - catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])) + catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ + HttpStatusCode.BAD_REQUEST_400, + HttpStatusCode.NOT_FOUND_404 + ])) ) .subscribe(videoChannel => { this.videoChannel = videoChannel diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts index bee3679f7..cafb030b9 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts @@ -9,6 +9,7 @@ import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/sh import { LoadingBarService } from '@ngx-loading-bar/core' import { VideoPrivacy } from '@shared/models' import { VideoSend } from './video-send' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' @Component({ selector: 'my-video-upload', @@ -129,17 +130,17 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy cancelUpload () { if (this.videoUploadObservable !== null) { this.videoUploadObservable.unsubscribe() + } - this.isUploadingVideo = false - this.videoUploadPercents = 0 - this.videoUploadObservable = null + this.isUploadingVideo = false + this.videoUploadPercents = 0 + this.videoUploadObservable = null - this.firstStepError.emit() - this.enableRetryAfterError = false - this.error = '' + this.firstStepError.emit() + this.enableRetryAfterError = false + this.error = '' - this.notifier.info($localize`Upload cancelled`) - } + this.notifier.info($localize`Upload cancelled`) } uploadFirstStep (clickedOnButton = false) { @@ -229,6 +230,11 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy notifier: this.notifier, sticky: false }) + + if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413 || + err.status === HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415) { + this.cancelUpload() + } } ) } diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts index b15de2a79..33de901c0 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts @@ -39,6 +39,7 @@ import { isWebRTCDisabled, timeToInt } from '../../../assets/player/utils' import { environment } from '../../../environments/environment' import { VideoSupportComponent } from './modal/video-support.component' import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' type URLOptions = CustomizationOptions & { playerMode: PlayerMode } @@ -412,13 +413,25 @@ export class VideoWatchComponent implements OnInit, OnDestroy { $localize`This video is not available on this instance. Do you want to be redirected on the origin instance: ${originUrl}?`, $localize`Redirection` ).then(res => { - if (res === false) return this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ]) + if (res === false) { + return this.restExtractor.redirectTo404IfNotFound(err, [ + HttpStatusCode.BAD_REQUEST_400, + HttpStatusCode.UNAUTHORIZED_401, + HttpStatusCode.FORBIDDEN_403, + HttpStatusCode.NOT_FOUND_404 + ]) + } return window.location.href = originUrl }) } - return this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ]) + return this.restExtractor.redirectTo404IfNotFound(err, [ + HttpStatusCode.BAD_REQUEST_400, + HttpStatusCode.UNAUTHORIZED_401, + HttpStatusCode.FORBIDDEN_403, + HttpStatusCode.NOT_FOUND_404 + ]) }) ) .subscribe(([ video, captionsResult ]) => { @@ -450,7 +463,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy { this.playlistService.getVideoPlaylist(playlistId) .pipe( // If 401, the video is private or blocked so redirect to 404 - catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ])) + catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ + HttpStatusCode.BAD_REQUEST_400, + HttpStatusCode.UNAUTHORIZED_401, + HttpStatusCode.FORBIDDEN_403, + HttpStatusCode.NOT_FOUND_404 + ])) ) .subscribe(playlist => { this.playlist = playlist diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index fd6062d3f..cdf13186b 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts @@ -11,6 +11,7 @@ import { environment } from '../../../environments/environment' import { RestExtractor } from '../rest/rest-extractor.service' import { AuthStatus } from './auth-status.model' import { AuthUser } from './auth-user.model' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' interface UserLoginWithUsername extends UserLogin { access_token: string @@ -94,7 +95,7 @@ export class AuthService { error => { let errorMessage = error.message - if (error.status === 403) { + if (error.status === HttpStatusCode.FORBIDDEN_403) { errorMessage = $localize`Cannot retrieve OAuth Client credentials: ${error.text}. Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.` } diff --git a/client/src/app/core/rest/rest-extractor.service.ts b/client/src/app/core/rest/rest-extractor.service.ts index 4b8c1e155..84d9ed074 100644 --- a/client/src/app/core/rest/rest-extractor.service.ts +++ b/client/src/app/core/rest/rest-extractor.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core' import { Router } from '@angular/router' import { dateToHuman } from '@app/helpers' import { ResultList } from '@shared/models' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' @Injectable() export class RestExtractor { @@ -57,9 +58,9 @@ export class RestExtractor { errorMessage = errorsArray.join('. ') } else if (err.error && err.error.error) { errorMessage = err.error.error - } else if (err.status === 413) { + } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) { errorMessage = $localize`Media is too large for the server. Please contact you administrator if you want to increase the limit size.` - } else if (err.status === 429) { + } else if (err.status === HttpStatusCode.TOO_MANY_REQUESTS_429) { const secondsLeft = err.headers.get('retry-after') if (secondsLeft) { const minutesLeft = Math.floor(parseInt(secondsLeft, 10) / 60) @@ -67,7 +68,7 @@ export class RestExtractor { } else { errorMessage = $localize`Too many attempts, please try again later.` } - } else if (err.status === 500) { + } else if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) { errorMessage = $localize`Server error. Please retry later.` } @@ -92,7 +93,7 @@ export class RestExtractor { return observableThrowError(errorObj) } - redirectTo404IfNotFound (obj: { status: number }, status = [ 404 ]) { + redirectTo404IfNotFound (obj: { status: number }, status = [ HttpStatusCode.NOT_FOUND_404 ]) { if (obj && obj.status && status.indexOf(obj.status) !== -1) { // Do not use redirectService to avoid circular dependencies this.router.navigate([ '/404' ], { skipLocationChange: true }) diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 48f7e7749..1709d44e7 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts @@ -13,6 +13,7 @@ import { PluginType, ClientHookName } from '../../../../shared/models' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' import { P2PMediaLoaderOptions, PeertubePlayerManagerOptions, PlayerMode } from '../../assets/player/peertube-player-manager' import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' import { TranslationsManager } from '../../assets/player/translations-manager' @@ -85,7 +86,7 @@ export class PeerTubeEmbed { refreshFetch (url: string, options?: RequestInit) { return fetch(url, options) .then((res: Response) => { - if (res.status !== 401) return res + if (res.status !== HttpStatusCode.UNAUTHORIZED_401) return res const refreshingTokenPromise = new Promise((resolve, reject) => { const clientId: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID) @@ -107,7 +108,7 @@ export class PeerTubeEmbed { method: 'POST', body: objectToUrlEncoded(data) }).then(res => { - if (res.status === 401) return undefined + if (res.status === HttpStatusCode.UNAUTHORIZED_401) return undefined return res.json() }).then((obj: UserRefreshToken & { code: 'invalid_grant'}) => { @@ -338,7 +339,7 @@ export class PeerTubeEmbed { try { playlistResponse = await playlistPromise - isResponseOk = playlistResponse.status === 200 + isResponseOk = playlistResponse.status === HttpStatusCode.OK_200 } catch (err) { console.error(err) isResponseOk = false @@ -347,7 +348,7 @@ export class PeerTubeEmbed { if (!isResponseOk) { const serverTranslations = await this.translationsPromise - if (playlistResponse?.status === 404) { + if (playlistResponse?.status === HttpStatusCode.NOT_FOUND_404) { this.playlistNotFound(serverTranslations) return undefined } @@ -367,7 +368,7 @@ export class PeerTubeEmbed { try { videoResponse = await videoPromise - isResponseOk = videoResponse.status === 200 + isResponseOk = videoResponse.status === HttpStatusCode.OK_200 } catch (err) { console.error(err) @@ -377,7 +378,7 @@ export class PeerTubeEmbed { if (!isResponseOk) { const serverTranslations = await this.translationsPromise - if (videoResponse?.status === 404) { + if (videoResponse?.status === HttpStatusCode.NOT_FOUND_404) { this.videoNotFound(serverTranslations) return undefined } diff --git a/server/controllers/client.ts b/server/controllers/client.ts index 49e6fd661..bd1f19f8c 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts @@ -3,12 +3,11 @@ import { constants, promises as fs } from 'fs' import { join } from 'path' import { CONFIG } from '@server/initializers/config' import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '@shared/core-utils/i18n' +import { HttpStatusCode } from '@shared/core-utils' import { root } from '../helpers/core-utils' -import { logger } from '../helpers/logger' -import { ACCEPT_HEADERS, STATIC_MAX_AGE } from '../initializers/constants' -import { ClientHtml } from '../lib/client-html' +import { STATIC_MAX_AGE } from '../initializers/constants' +import { ClientHtml, sendHTML, serveIndexHTML } from '../lib/client-html' import { asyncMiddleware, embedCSP } from '../middlewares' -import { HttpStatusCode } from '@shared/core-utils' const clientsRouter = express.Router() @@ -118,31 +117,12 @@ function serveServerTranslations (req: express.Request, res: express.Response) { return res.sendStatus(HttpStatusCode.NOT_FOUND_404) } -async function serveIndexHTML (req: express.Request, res: express.Response) { - if (req.accepts(ACCEPT_HEADERS) === 'html') { - try { - await generateHTMLPage(req, res, req.params.language) - return - } catch (err) { - logger.error('Cannot generate HTML page.', err) - } - } - - return res.status(HttpStatusCode.INTERNAL_SERVER_ERROR_500).end() -} - async function generateEmbedHtmlPage (req: express.Request, res: express.Response) { const html = await ClientHtml.getEmbedHTML() return sendHTML(html, res) } -async function generateHTMLPage (req: express.Request, res: express.Response, paramLang?: string) { - const html = await ClientHtml.getDefaultHTMLPage(req, res, paramLang) - - return sendHTML(html, res) -} - async function generateWatchHtmlPage (req: express.Request, res: express.Response) { const html = await ClientHtml.getWatchHTMLPage(req.params.id + '', req, res) @@ -167,12 +147,6 @@ async function generateVideoChannelHtmlPage (req: express.Request, res: express. return sendHTML(html, res) } -function sendHTML (html: string, res: express.Response) { - res.set('Content-Type', 'text/html; charset=UTF-8') - - return res.send(html) -} - async function generateManifest (req: express.Request, res: express.Response) { const manifestPhysicalPath = join(root(), 'client', 'dist', 'manifest.webmanifest') const manifestJson = await fs.readFile(manifestPhysicalPath, 'utf8') diff --git a/server/controllers/static.ts b/server/controllers/static.ts index ff77452dd..f12f00e1b 100644 --- a/server/controllers/static.ts +++ b/server/controllers/static.ts @@ -27,6 +27,7 @@ import { getTorrentFilePath, getVideoFilePath } from '@server/lib/video-paths' import { getThemeOrDefault } from '../lib/plugins/theme-utils' import { getEnabledResolutions, getRegisteredPlugins, getRegisteredThemes } from '@server/controllers/api/config' import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' +import { serveIndexHTML } from '@server/lib/client-html' const staticRouter = express.Router() @@ -119,6 +120,11 @@ staticRouter.get('/robots.txt', } ) +staticRouter.all('/teapot', + getCup, + asyncMiddleware(serveIndexHTML) +) + // security.txt service staticRouter.get('/security.txt', (_, res: express.Response) => { @@ -391,3 +397,11 @@ function getHLSPlaylist (video: MVideoFullLight) { return Object.assign(playlist, { Video: video }) } + +function getCup (req: express.Request, res: express.Response, next: express.NextFunction) { + res.status(HttpStatusCode.I_AM_A_TEAPOT_418) + res.setHeader('Accept-Additions', 'Non-Dairy;1,Sugar;1') + res.setHeader('Safe', 'if-sepia-awake') + + return next() +} diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts index 61c03f0c9..effdd98cb 100644 --- a/server/helpers/custom-validators/misc.ts +++ b/server/helpers/custom-validators/misc.ts @@ -86,6 +86,50 @@ function toIntArray (value: any) { return value.map(v => validator.toInt(v)) } +function isFileFieldValid ( + files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], + field: string, + optional = false +) { + // Should have files + if (!files) return optional + if (isArray(files)) return optional + + // Should have a file + const fileArray = files[field] + if (!fileArray || fileArray.length === 0) { + return optional + } + + // The file should exist + const file = fileArray[0] + if (!file || !file.originalname) return false + return file +} + +function isFileMimeTypeValid ( + files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], + mimeTypeRegex: string, + field: string, + optional = false +) { + // Should have files + if (!files) return optional + if (isArray(files)) return optional + + // Should have a file + const fileArray = files[field] + if (!fileArray || fileArray.length === 0) { + return optional + } + + // The file should exist + const file = fileArray[0] + if (!file || !file.originalname) return false + + return new RegExp(`^${mimeTypeRegex}$`, 'i').test(file.mimetype) +} + function isFileValid ( files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], mimeTypeRegex: string, @@ -132,5 +176,7 @@ export { toIntOrNull, toArray, toIntArray, + isFileFieldValid, + isFileMimeTypeValid, isFileValid } diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index 8b309ae42..87966798f 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts @@ -11,7 +11,7 @@ import { VIDEO_STATES, VIDEO_LIVE } from '../../initializers/constants' -import { exists, isArray, isDateValid, isFileValid } from './misc' +import { exists, isArray, isDateValid, isFileMimeTypeValid, isFileValid } from './misc' import * as magnetUtil from 'magnet-uri' const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS @@ -81,8 +81,8 @@ function isVideoFileExtnameValid (value: string) { return exists(value) && (value === VIDEO_LIVE.EXTENSION || MIMETYPES.VIDEO.EXT_MIMETYPE[value] !== undefined) } -function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) { - return isFileValid(files, MIMETYPES.VIDEO.MIMETYPES_REGEX, 'videofile', null) +function isVideoFileMimeTypeValid (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) { + return isFileMimeTypeValid(files, MIMETYPES.VIDEO.MIMETYPES_REGEX, 'videofile') } const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME @@ -143,12 +143,12 @@ export { isVideoFPSResolutionValid, isScheduleVideoUpdatePrivacyValid, isVideoOriginallyPublishedAtValid, - isVideoFile, isVideoMagnetUriValid, isVideoStateValid, isVideoViewsValid, isVideoRatingTypeValid, isVideoFileExtnameValid, + isVideoFileMimeTypeValid, isVideoDurationValid, isVideoTagValid, isVideoPrivacyValid, diff --git a/server/helpers/youtube-dl.ts b/server/helpers/youtube-dl.ts index 302b2e206..9e8ef90d8 100644 --- a/server/helpers/youtube-dl.ts +++ b/server/helpers/youtube-dl.ts @@ -7,6 +7,7 @@ import { ensureDir, remove, writeFile } from 'fs-extra' import * as request from 'request' import { createWriteStream } from 'fs' import { CONFIG } from '@server/initializers/config' +import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' export type YoutubeDLInfo = { name?: string @@ -154,7 +155,7 @@ async function updateYoutubeDLBinary () { return res() } - if (result.statusCode !== 302) { + if (result.statusCode !== HttpStatusCode.FOUND_302) { logger.error('youtube-dl update error: did not get redirect for the latest version link. Status %d', result.statusCode) return res() } @@ -164,7 +165,7 @@ async function updateYoutubeDLBinary () { const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[1] downloadFile.on('response', result => { - if (result.statusCode !== 200) { + if (result.statusCode !== HttpStatusCode.OK_200) { logger.error('Cannot update youtube-dl: new version response is not 200, it\'s %d.', result.statusCode) return res() } diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index fb5558ff6..52547536c 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -36,6 +36,7 @@ import { } from '../../types/models' import { extname } from 'path' import { getServerActor } from '@server/models/application/application' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' // Set account keys, this could be long so process after the account creation and do not block the client function setAsyncActorKeys (actor: T) { @@ -277,7 +278,7 @@ async function refreshActorIfNeeded Redis.Instance.getPrefix(), statusCodes: { - exclude: [ 404, 403 ] + exclude: [ + HttpStatusCode.FORBIDDEN_403, + HttpStatusCode.NOT_FOUND_404 + ] } } diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 9834f714b..8bc37b0ab 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts @@ -8,6 +8,7 @@ import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/vid import { isBooleanValid, isDateValid, + isFileFieldValid, isIdOrUUIDValid, isIdValid, isUUIDValid, @@ -22,7 +23,8 @@ import { isScheduleVideoUpdatePrivacyValid, isVideoCategoryValid, isVideoDescriptionValid, - isVideoFile, + isVideoFileMimeTypeValid, + isVideoFileSizeValid, isVideoFilterValid, isVideoImage, isVideoLanguageValid, @@ -55,11 +57,11 @@ import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-c const videosAddValidator = getCommonVideoEditAttributes().concat([ body('videofile') - .custom((value, { req }) => isVideoFile(req.files)).withMessage( - 'This file is not supported or too large. Please, make sure it is of the following type: ' + - CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') - ), - body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), + .custom((value, { req }) => isFileFieldValid(req.files, 'videofile')) + .withMessage('Should have a file'), + body('name') + .custom(isVideoNameValid) + .withMessage('Should have a valid name'), body('channelId') .customSanitizer(toIntOrNull) .custom(isIdValid).withMessage('Should have correct video channel id'), @@ -75,8 +77,27 @@ const videosAddValidator = getCommonVideoEditAttributes().concat([ if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) + if (!isVideoFileMimeTypeValid(req.files)) { + res.status(HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415) + .json({ + error: 'This file is not supported. Please, make sure it is of the following type: ' + + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') + }) + + return cleanUpReqFiles(req) + } + + if (!isVideoFileSizeValid(videoFile.size.toString())) { + res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413) + .json({ + error: 'This file is too large.' + }) + + return cleanUpReqFiles(req) + } + if (await isAbleToUploadVideo(user.id, videoFile.size) === false) { - res.status(HttpStatusCode.FORBIDDEN_403) + res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413) .json({ error: 'The user video quota is exceeded with this video.' }) return cleanUpReqFiles(req) @@ -88,8 +109,8 @@ const videosAddValidator = getCommonVideoEditAttributes().concat([ duration = await getDurationFromVideoFile(videoFile.path) } catch (err) { logger.error('Invalid input file in videosAddValidator.', { err }) - res.status(HttpStatusCode.BAD_REQUEST_400) - .json({ error: 'Invalid input file.' }) + res.status(HttpStatusCode.UNPROCESSABLE_ENTITY_422) + .json({ error: 'Video file unreadable.' }) return cleanUpReqFiles(req) } @@ -295,7 +316,7 @@ const videosAcceptChangeOwnershipValidator = [ const videoChangeOwnership = res.locals.videoChangeOwnership const isAble = await isAbleToUploadVideo(user.id, videoChangeOwnership.Video.getMaxQualityFile().size) if (isAble === false) { - res.status(HttpStatusCode.FORBIDDEN_403) + res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413) .json({ error: 'The user video quota is exceeded with this video.' }) return diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts index d16f05108..b6c538e19 100644 --- a/server/tests/api/activitypub/client.ts +++ b/server/tests/api/activitypub/client.ts @@ -11,6 +11,7 @@ import { setAccessTokensToServers, uploadVideo } from '../../../../shared/extra-utils' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -53,7 +54,7 @@ describe('Test activitypub', function () { }) it('Should redirect to the origin video object', async function () { - const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, 302) + const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, HttpStatusCode.FOUND_302) expect(res.header.location).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID) }) diff --git a/server/tests/api/activitypub/refresher.ts b/server/tests/api/activitypub/refresher.ts index 232c5d823..c717f1a30 100644 --- a/server/tests/api/activitypub/refresher.ts +++ b/server/tests/api/activitypub/refresher.ts @@ -24,6 +24,7 @@ import { } from '../../../../shared/extra-utils' import { getAccount } from '../../../../shared/extra-utils/users/accounts' import { VideoPlaylistPrivacy } from '../../../../shared/models/videos' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' describe('Test AP refresher', function () { let servers: ServerInfo[] = [] @@ -86,8 +87,8 @@ describe('Test AP refresher', function () { await waitJobs(servers) - await getVideo(servers[0].url, videoUUID1, 404) - await getVideo(servers[0].url, videoUUID2, 200) + await getVideo(servers[0].url, videoUUID1, HttpStatusCode.NOT_FOUND_404) + await getVideo(servers[0].url, videoUUID2, HttpStatusCode.OK_200) }) it('Should not update a remote video if the remote instance is down', async function () { @@ -106,7 +107,7 @@ describe('Test AP refresher', function () { await reRunServer(servers[1]) - await getVideo(servers[0].url, videoUUID3, 200) + await getVideo(servers[0].url, videoUUID3, HttpStatusCode.OK_200) }) }) @@ -126,8 +127,8 @@ describe('Test AP refresher', function () { await waitJobs(servers) - await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port, 200) - await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port, 404) + await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port, HttpStatusCode.OK_200) + await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port, HttpStatusCode.NOT_FOUND_404) }) }) @@ -146,8 +147,8 @@ describe('Test AP refresher', function () { await waitJobs(servers) - await getVideoPlaylist(servers[0].url, playlistUUID1, 200) - await getVideoPlaylist(servers[0].url, playlistUUID2, 404) + await getVideoPlaylist(servers[0].url, playlistUUID1, HttpStatusCode.OK_200) + await getVideoPlaylist(servers[0].url, playlistUUID2, HttpStatusCode.NOT_FOUND_404) }) }) diff --git a/server/tests/api/check-params/accounts.ts b/server/tests/api/check-params/accounts.ts index c29af7cd7..d1712cff6 100644 --- a/server/tests/api/check-params/accounts.ts +++ b/server/tests/api/check-params/accounts.ts @@ -9,6 +9,7 @@ import { checkBadStartPagination } from '../../../../shared/extra-utils/requests/check-api-params' import { getAccount } from '../../../../shared/extra-utils/users/accounts' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' describe('Test accounts API validators', function () { const path = '/api/v1/accounts/' @@ -38,7 +39,7 @@ describe('Test accounts API validators', function () { describe('When getting an account', function () { it('Should return 404 with a non existing name', async function () { - await getAccount(server.url, 'arfaze', 404) + await getAccount(server.url, 'arfaze', HttpStatusCode.NOT_FOUND_404) }) }) diff --git a/server/tests/api/check-params/contact-form.ts b/server/tests/api/check-params/contact-form.ts index b2126b9b0..c7f9c1b47 100644 --- a/server/tests/api/check-params/contact-form.ts +++ b/server/tests/api/check-params/contact-form.ts @@ -5,6 +5,7 @@ import 'mocha' import { cleanupTests, flushAndRunServer, immutableAssign, killallServers, reRunServer, ServerInfo } from '../../../../shared/extra-utils' import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' describe('Test contact form API validators', function () { let server: ServerInfo @@ -29,7 +30,7 @@ describe('Test contact form API validators', function () { }) it('Should not accept a contact form if emails are disabled', async function () { - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 409 })) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: HttpStatusCode.CONFLICT_409 })) }) it('Should not accept a contact form if it is disabled in the configuration', async function () { @@ -39,7 +40,7 @@ describe('Test contact form API validators', function () { // Contact form is disabled await reRunServer(server, { smtp: { hostname: 'localhost', port: emailPort }, contact_form: { enabled: false } }) - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 409 })) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: HttpStatusCode.CONFLICT_409 })) }) it('Should not accept a contact form if from email is invalid', async function () { @@ -50,21 +51,57 @@ describe('Test contact form API validators', function () { // Email & contact form enabled await reRunServer(server, { smtp: { hostname: 'localhost', port: emailPort } }) - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromEmail: 'badEmail' })) - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromEmail: 'badEmail@' })) - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromEmail: undefined })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + fromEmail: 'badEmail' + })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + fromEmail: 'badEmail@' + })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + fromEmail: undefined + })) }) it('Should not accept a contact form if from name is invalid', async function () { - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromName: 'name'.repeat(100) })) - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromName: '' })) - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromName: undefined })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + fromName: 'name'.repeat(100) + })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + fromName: '' + })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + fromName: undefined + })) }) it('Should not accept a contact form if body is invalid', async function () { - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, body: 'body'.repeat(5000) })) - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, body: 'a' })) - await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, body: undefined })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + body: 'body'.repeat(5000) + })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + body: 'a' + })) + await sendContactForm(immutableAssign(defaultBody, { + url: server.url, + expectedStatus: HttpStatusCode.BAD_REQUEST_400, + body: undefined + })) }) it('Should accept a contact form with the correct parameters', async function () { diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 21ace36aa..0a13f5b67 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts @@ -1102,7 +1102,7 @@ describe('Test users API validators', function () { videoQuota: 42 }) - await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.FORBIDDEN_403) + await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413) }) it('Should fail with a registered user having too many videos', async function () { @@ -1120,7 +1120,7 @@ describe('Test users API validators', function () { await uploadVideo(server.url, userAccessToken, videoAttributes) await uploadVideo(server.url, userAccessToken, videoAttributes) await uploadVideo(server.url, userAccessToken, videoAttributes) - await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.FORBIDDEN_403) + await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413) }) it('Should fail to import with HTTP/Torrent/magnet', async function () { @@ -1151,7 +1151,7 @@ describe('Test users API validators', function () { }) describe('When having a daily video quota', function () { - it('Should fail with a user having too many videos', async function () { + it('Should fail with a user having too many videos daily', async function () { await updateUser({ url: server.url, userId: rootId, @@ -1159,7 +1159,7 @@ describe('Test users API validators', function () { videoQuotaDaily: 42 }) - await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.FORBIDDEN_403) + await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413) }) }) @@ -1173,7 +1173,7 @@ describe('Test users API validators', function () { videoQuotaDaily: 1024 * 1024 * 1024 }) - await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.FORBIDDEN_403) + await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413) }) it('Should fail if exceeding daily quota', async function () { @@ -1185,7 +1185,7 @@ describe('Test users API validators', function () { videoQuotaDaily: 42 }) - await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.FORBIDDEN_403) + await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413) }) }) diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index d60546917..5faba82c4 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts @@ -348,12 +348,26 @@ describe('Test videos API validator', function () { let attaches = { videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') } - await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) + await makeUploadRequest({ + url: server.url, + path: path + '/upload', + token: server.accessToken, + fields, + attaches, + statusCodeExpected: HttpStatusCode.UNPROCESSABLE_ENTITY_422 + }) attaches = { videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') } - await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) + await makeUploadRequest({ + url: server.url, + path: path + '/upload', + token: server.accessToken, + fields, + attaches, + statusCodeExpected: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415 + }) }) it('Should fail with an incorrect thumbnail file', async function () { diff --git a/server/tests/api/live/live-save-replay.ts b/server/tests/api/live/live-save-replay.ts index 3ffa0c093..e300ec345 100644 --- a/server/tests/api/live/live-save-replay.ts +++ b/server/tests/api/live/live-save-replay.ts @@ -25,6 +25,7 @@ import { waitJobs, waitUntilLiveStarts } from '../../../../shared/extra-utils' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -118,7 +119,7 @@ describe('Save replay setting', function () { await waitJobs(servers) - await checkVideosExist(liveVideoUUID, false, 200) + await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE) }) @@ -130,7 +131,7 @@ describe('Save replay setting', function () { await waitJobs(servers) - await checkVideosExist(liveVideoUUID, true, 200) + await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) }) @@ -142,7 +143,7 @@ describe('Save replay setting', function () { await waitJobs(servers) // Live still exist, but cannot be played anymore - await checkVideosExist(liveVideoUUID, false, 200) + await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) await checkVideoState(liveVideoUUID, VideoState.LIVE_ENDED) // No resolutions saved since we did not save replay @@ -158,7 +159,7 @@ describe('Save replay setting', function () { await waitUntilLiveStarts(servers[0].url, servers[0].accessToken, liveVideoUUID) await waitJobs(servers) - await checkVideosExist(liveVideoUUID, true, 200) + await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) await Promise.all([ addVideoToBlacklist(servers[0].url, servers[0].accessToken, liveVideoUUID, 'bad live', true), @@ -169,8 +170,8 @@ describe('Save replay setting', function () { await checkVideosExist(liveVideoUUID, false) - await getVideo(servers[0].url, liveVideoUUID, 401) - await getVideo(servers[1].url, liveVideoUUID, 404) + await getVideo(servers[0].url, liveVideoUUID, HttpStatusCode.UNAUTHORIZED_401) + await getVideo(servers[1].url, liveVideoUUID, HttpStatusCode.NOT_FOUND_404) await checkLiveCleanup(servers[0], liveVideoUUID, []) }) @@ -184,7 +185,7 @@ describe('Save replay setting', function () { await waitUntilLiveStarts(servers[0].url, servers[0].accessToken, liveVideoUUID) await waitJobs(servers) - await checkVideosExist(liveVideoUUID, true, 200) + await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) await Promise.all([ testFfmpegStreamError(ffmpegCommand, true), @@ -193,7 +194,7 @@ describe('Save replay setting', function () { await waitJobs(servers) - await checkVideosExist(liveVideoUUID, false, 404) + await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) await checkLiveCleanup(servers[0], liveVideoUUID, []) }) }) @@ -207,7 +208,7 @@ describe('Save replay setting', function () { await waitJobs(servers) - await checkVideosExist(liveVideoUUID, false, 200) + await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE) }) @@ -219,7 +220,7 @@ describe('Save replay setting', function () { await waitJobs(servers) - await checkVideosExist(liveVideoUUID, true, 200) + await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) }) @@ -231,7 +232,7 @@ describe('Save replay setting', function () { await waitJobs(servers) // Live has been transcoded - await checkVideosExist(liveVideoUUID, true, 200) + await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) }) @@ -261,7 +262,7 @@ describe('Save replay setting', function () { await waitUntilLiveStarts(servers[0].url, servers[0].accessToken, liveVideoUUID) await waitJobs(servers) - await checkVideosExist(liveVideoUUID, true, 200) + await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) await Promise.all([ addVideoToBlacklist(servers[0].url, servers[0].accessToken, liveVideoUUID, 'bad live', true), @@ -272,8 +273,8 @@ describe('Save replay setting', function () { await checkVideosExist(liveVideoUUID, false) - await getVideo(servers[0].url, liveVideoUUID, 401) - await getVideo(servers[1].url, liveVideoUUID, 404) + await getVideo(servers[0].url, liveVideoUUID, HttpStatusCode.UNAUTHORIZED_401) + await getVideo(servers[1].url, liveVideoUUID, HttpStatusCode.NOT_FOUND_404) await checkLiveCleanup(servers[0], liveVideoUUID, [ 720 ]) }) @@ -287,7 +288,7 @@ describe('Save replay setting', function () { await waitUntilLiveStarts(servers[0].url, servers[0].accessToken, liveVideoUUID) await waitJobs(servers) - await checkVideosExist(liveVideoUUID, true, 200) + await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) await Promise.all([ removeVideo(servers[0].url, servers[0].accessToken, liveVideoUUID), @@ -296,7 +297,7 @@ describe('Save replay setting', function () { await waitJobs(servers) - await checkVideosExist(liveVideoUUID, false, 404) + await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) await checkLiveCleanup(servers[0], liveVideoUUID, []) }) }) diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts index d784650b5..fdfc6105f 100644 --- a/server/tests/api/live/live.ts +++ b/server/tests/api/live/live.ts @@ -44,6 +44,7 @@ import { waitUntilLiveStarts, waitUntilLog } from '../../../../shared/extra-utils' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -164,8 +165,8 @@ describe('Test live', function () { expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED) expect(video.nsfw).to.be.true - await makeRawRequest(server.url + video.thumbnailPath, 200) - await makeRawRequest(server.url + video.previewPath, 200) + await makeRawRequest(server.url + video.thumbnailPath, HttpStatusCode.OK_200) + await makeRawRequest(server.url + video.previewPath, HttpStatusCode.OK_200) } }) @@ -179,7 +180,7 @@ describe('Test live', function () { }) it('Should not be able to update a live of another server', async function () { - await updateLive(servers[1].url, servers[1].accessToken, liveVideoUUID, { saveReplay: false }, 403) + await updateLive(servers[1].url, servers[1].accessToken, liveVideoUUID, { saveReplay: false }, HttpStatusCode.FORBIDDEN_403) }) it('Should update the live', async function () { @@ -215,8 +216,8 @@ describe('Test live', function () { it('Should have the live deleted', async function () { for (const server of servers) { - await getVideo(server.url, liveVideoUUID, 404) - await getLive(server.url, server.accessToken, liveVideoUUID, 404) + await getVideo(server.url, liveVideoUUID, HttpStatusCode.NOT_FOUND_404) + await getLive(server.url, server.accessToken, liveVideoUUID, HttpStatusCode.NOT_FOUND_404) } }) }) @@ -430,8 +431,8 @@ describe('Test live', function () { expect(video.files).to.have.lengthOf(0) const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) - await makeRawRequest(hlsPlaylist.playlistUrl, 200) - await makeRawRequest(hlsPlaylist.segmentsSha256Url, 200) + await makeRawRequest(hlsPlaylist.playlistUrl, HttpStatusCode.OK_200) + await makeRawRequest(hlsPlaylist.segmentsSha256Url, HttpStatusCode.OK_200) expect(hlsPlaylist.files).to.have.lengthOf(resolutions.length) @@ -455,8 +456,8 @@ describe('Test live', function () { expect(probe.format.bit_rate).to.be.below(bitrateLimits[videoStream.height]) - await makeRawRequest(file.torrentUrl, 200) - await makeRawRequest(file.fileUrl, 200) + await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200) + await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) } } }) diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index eb51d8909..a505b8ede 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts @@ -21,6 +21,7 @@ import { uploadVideo } from '../../../../shared/extra-utils' import { ServerConfig } from '../../../../shared/models' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -237,8 +238,8 @@ describe('Test config', function () { expect(data.video.file.extensions).to.contain('.webm') expect(data.video.file.extensions).to.contain('.ogv') - await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 400) - await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 400) + await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415) + await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415) expect(data.contactForm.enabled).to.be.true }) @@ -427,8 +428,8 @@ describe('Test config', function () { expect(data.video.file.extensions).to.contain('.ogg') expect(data.video.file.extensions).to.contain('.flac') - await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 200) - await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 200) + await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, HttpStatusCode.OK_200) + await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, HttpStatusCode.OK_200) }) it('Should have the configuration updated after a restart', async function () { diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts index c0965d9d1..9b4af1915 100644 --- a/server/tests/api/server/contact-form.ts +++ b/server/tests/api/server/contact-form.ts @@ -6,6 +6,7 @@ import { cleanupTests, flushAndRunServer, ServerInfo, setAccessTokensToServers, import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' import { waitJobs } from '../../../../shared/extra-utils/server/jobs' import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -67,7 +68,7 @@ describe('Test contact form', function () { body: 'my super message', fromName: 'Super toto', subject: 'my subject', - expectedStatus: 403 + expectedStatus: HttpStatusCode.FORBIDDEN_403 }) }) diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts index 53f96a94f..17d9e902c 100644 --- a/server/tests/api/server/email.ts +++ b/server/tests/api/server/email.ts @@ -22,6 +22,7 @@ import { } from '../../../../shared/extra-utils' import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' import { waitJobs } from '../../../../shared/extra-utils/server/jobs' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -116,7 +117,7 @@ describe('Test emails', function () { }) it('Should not reset the password with an invalid verification string', async function () { - await resetPassword(server.url, userId, verificationString + 'b', 'super_password2', 403) + await resetPassword(server.url, userId, verificationString + 'b', 'super_password2', HttpStatusCode.FORBIDDEN_403) }) it('Should reset the password', async function () { @@ -124,7 +125,7 @@ describe('Test emails', function () { }) it('Should not reset the password with the same verification string', async function () { - await resetPassword(server.url, userId, verificationString, 'super_password3', 403) + await resetPassword(server.url, userId, verificationString, 'super_password3', HttpStatusCode.FORBIDDEN_403) }) it('Should login with this new password', async function () { @@ -169,7 +170,7 @@ describe('Test emails', function () { }) it('Should not reset the password with an invalid verification string', async function () { - await resetPassword(server.url, userId2, verificationString2 + 'c', 'newly_created_password', 403) + await resetPassword(server.url, userId2, verificationString2 + 'c', 'newly_created_password', HttpStatusCode.FORBIDDEN_403) }) it('Should reset the password', async function () { @@ -210,7 +211,7 @@ describe('Test emails', function () { this.timeout(10000) const reason = 'my super bad reason' - await blockUser(server.url, userId, server.accessToken, 204, reason) + await blockUser(server.url, userId, server.accessToken, HttpStatusCode.NO_CONTENT_204, reason) await waitJobs(server) expect(emails).to.have.lengthOf(4) @@ -228,7 +229,7 @@ describe('Test emails', function () { it('Should send the notification email when unblocking a user', async function () { this.timeout(10000) - await unblockUser(server.url, userId, server.accessToken, 204) + await unblockUser(server.url, userId, server.accessToken, HttpStatusCode.NO_CONTENT_204) await waitJobs(server) expect(emails).to.have.lengthOf(5) @@ -317,7 +318,7 @@ describe('Test emails', function () { }) it('Should not verify the email with an invalid verification string', async function () { - await verifyEmail(server.url, userId, verificationString + 'b', false, 403) + await verifyEmail(server.url, userId, verificationString + 'b', false, HttpStatusCode.FORBIDDEN_403) }) it('Should verify the email', async function () { diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts index a73440286..0846b04f4 100644 --- a/server/tests/api/server/follow-constraints.ts +++ b/server/tests/api/server/follow-constraints.ts @@ -17,6 +17,7 @@ import { import { unfollow } from '../../../../shared/extra-utils/server/follows' import { userLogin } from '../../../../shared/extra-utils/users/login' import { createUser } from '../../../../shared/extra-utils/users/users' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -58,11 +59,11 @@ describe('Test follow constraints', function () { describe('With an unlogged user', function () { it('Should get the local video', async function () { - await getVideo(servers[0].url, video1UUID, 200) + await getVideo(servers[0].url, video1UUID, HttpStatusCode.OK_200) }) it('Should get the remote video', async function () { - await getVideo(servers[0].url, video2UUID, 200) + await getVideo(servers[0].url, video2UUID, HttpStatusCode.OK_200) }) it('Should list local account videos', async function () { @@ -98,11 +99,11 @@ describe('Test follow constraints', function () { describe('With a logged user', function () { it('Should get the local video', async function () { - await getVideoWithToken(servers[0].url, userAccessToken, video1UUID, 200) + await getVideoWithToken(servers[0].url, userAccessToken, video1UUID, HttpStatusCode.OK_200) }) it('Should get the remote video', async function () { - await getVideoWithToken(servers[0].url, userAccessToken, video2UUID, 200) + await getVideoWithToken(servers[0].url, userAccessToken, video2UUID, HttpStatusCode.OK_200) }) it('Should list local account videos', async function () { @@ -148,11 +149,11 @@ describe('Test follow constraints', function () { describe('With an unlogged user', function () { it('Should get the local video', async function () { - await getVideo(servers[0].url, video1UUID, 200) + await getVideo(servers[0].url, video1UUID, HttpStatusCode.OK_200) }) it('Should not get the remote video', async function () { - await getVideo(servers[0].url, video2UUID, 403) + await getVideo(servers[0].url, video2UUID, HttpStatusCode.FORBIDDEN_403) }) it('Should list local account videos', async function () { @@ -188,11 +189,11 @@ describe('Test follow constraints', function () { describe('With a logged user', function () { it('Should get the local video', async function () { - await getVideoWithToken(servers[0].url, userAccessToken, video1UUID, 200) + await getVideoWithToken(servers[0].url, userAccessToken, video1UUID, HttpStatusCode.OK_200) }) it('Should get the remote video', async function () { - await getVideoWithToken(servers[0].url, userAccessToken, video2UUID, 200) + await getVideoWithToken(servers[0].url, userAccessToken, video2UUID, HttpStatusCode.OK_200) }) it('Should list local account videos', async function () { diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts index 2cf6e15ad..043754e70 100644 --- a/server/tests/api/server/handle-down.ts +++ b/server/tests/api/server/handle-down.ts @@ -33,6 +33,7 @@ import { getVideoCommentThreads, getVideoThreadComments } from '../../../../shared/extra-utils/videos/video-comments' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -352,7 +353,7 @@ describe('Test handle downs', function () { } for (const id of videoIdsServer1) { - await getVideo(servers[1].url, id, 403) + await getVideo(servers[1].url, id, HttpStatusCode.FORBIDDEN_403) } }) diff --git a/server/tests/api/server/no-client.ts b/server/tests/api/server/no-client.ts index d0450aba0..d589f51f3 100644 --- a/server/tests/api/server/no-client.ts +++ b/server/tests/api/server/no-client.ts @@ -2,6 +2,7 @@ import 'mocha' import * as request from 'supertest' import { ServerInfo } from '../../../../shared/extra-utils' import { cleanupTests, flushAndRunServer } from '../../../../shared/extra-utils/server/servers' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' describe('Start and stop server without web client routes', function () { let server: ServerInfo @@ -16,7 +17,7 @@ describe('Start and stop server without web client routes', function () { const req = request(server.url) .get('/') - return req.expect(404) + return req.expect(HttpStatusCode.NOT_FOUND_404) }) after(async function () { diff --git a/server/tests/api/server/reverse-proxy.ts b/server/tests/api/server/reverse-proxy.ts index d0d79c4f6..17d1ee4a5 100644 --- a/server/tests/api/server/reverse-proxy.ts +++ b/server/tests/api/server/reverse-proxy.ts @@ -4,6 +4,7 @@ import 'mocha' import * as chai from 'chai' import { cleanupTests, getVideo, registerUser, uploadVideo, userLogin, viewVideo, wait } from '../../../../shared/extra-utils' import { flushAndRunServer, setAccessTokensToServers } from '../../../../shared/extra-utils/index' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -56,8 +57,8 @@ describe('Test application behind a reverse proxy', function () { it('Should view a video 2 times with the X-Forwarded-For header set', async function () { this.timeout(20000) - await viewVideo(server.url, videoId, 204, '0.0.0.1,127.0.0.1') - await viewVideo(server.url, videoId, 204, '0.0.0.2,127.0.0.1') + await viewVideo(server.url, videoId, HttpStatusCode.NO_CONTENT_204, '0.0.0.1,127.0.0.1') + await viewVideo(server.url, videoId, HttpStatusCode.NO_CONTENT_204, '0.0.0.2,127.0.0.1') // Wait the repeatable job await wait(8000) @@ -69,8 +70,8 @@ describe('Test application behind a reverse proxy', function () { it('Should view a video only once with the same client IP in the X-Forwarded-For header', async function () { this.timeout(20000) - await viewVideo(server.url, videoId, 204, '0.0.0.4,0.0.0.3,::ffff:127.0.0.1') - await viewVideo(server.url, videoId, 204, '0.0.0.5,0.0.0.3,127.0.0.1') + await viewVideo(server.url, videoId, HttpStatusCode.NO_CONTENT_204, '0.0.0.4,0.0.0.3,::ffff:127.0.0.1') + await viewVideo(server.url, videoId, HttpStatusCode.NO_CONTENT_204, '0.0.0.5,0.0.0.3,127.0.0.1') // Wait the repeatable job await wait(8000) @@ -82,8 +83,8 @@ describe('Test application behind a reverse proxy', function () { it('Should view a video two times with a different client IP in the X-Forwarded-For header', async function () { this.timeout(20000) - await viewVideo(server.url, videoId, 204, '0.0.0.8,0.0.0.6,127.0.0.1') - await viewVideo(server.url, videoId, 204, '0.0.0.8,0.0.0.7,127.0.0.1') + await viewVideo(server.url, videoId, HttpStatusCode.NO_CONTENT_204, '0.0.0.8,0.0.0.6,127.0.0.1') + await viewVideo(server.url, videoId, HttpStatusCode.NO_CONTENT_204, '0.0.0.8,0.0.0.7,127.0.0.1') // Wait the repeatable job await wait(8000) @@ -96,10 +97,10 @@ describe('Test application behind a reverse proxy', function () { const user = { username: 'root', password: 'fail' } for (let i = 0; i < 19; i++) { - await userLogin(server, user, 400) + await userLogin(server, user, HttpStatusCode.BAD_REQUEST_400) } - await userLogin(server, user, 429) + await userLogin(server, user, HttpStatusCode.TOO_MANY_REQUESTS_429) }) it('Should rate limit signup', async function () { @@ -111,7 +112,7 @@ describe('Test application behind a reverse proxy', function () { } } - await registerUser(server.url, 'test42', 'password', 429) + await registerUser(server.url, 'test42', 'password', HttpStatusCode.TOO_MANY_REQUESTS_429) }) it('Should not rate limit failed signup', async function () { @@ -120,10 +121,10 @@ describe('Test application behind a reverse proxy', function () { await wait(7000) for (let i = 0; i < 3; i++) { - await registerUser(server.url, 'test' + i, 'password', 409) + await registerUser(server.url, 'test' + i, 'password', HttpStatusCode.CONFLICT_409) } - await registerUser(server.url, 'test43', 'password', 204) + await registerUser(server.url, 'test43', 'password', HttpStatusCode.NO_CONTENT_204) }) @@ -140,7 +141,7 @@ describe('Test application behind a reverse proxy', function () { } } - await getVideo(server.url, videoId, 429) + await getVideo(server.url, videoId, HttpStatusCode.TOO_MANY_REQUESTS_429) }) after(async function () { diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts index fdd5e33f3..f754df04e 100644 --- a/server/tests/api/videos/multiple-servers.ts +++ b/server/tests/api/videos/multiple-servers.ts @@ -41,6 +41,7 @@ import { findCommentId } from '../../../../shared/extra-utils/videos/video-comments' import { waitJobs } from '../../../../shared/extra-utils/server/jobs' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -999,7 +1000,7 @@ describe('Test multiple servers', function () { expect(res.body.downloadEnabled).to.be.false const text = 'my super forbidden comment' - await addVideoCommentThread(server.url, server.accessToken, videoUUID, text, 409) + await addVideoCommentThread(server.url, server.accessToken, videoUUID, text, HttpStatusCode.CONFLICT_409) } }) }) @@ -1021,7 +1022,7 @@ describe('Test multiple servers', function () { const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm') await req.attach('videofile', filePath) - .expect(200) + .expect(HttpStatusCode.OK_200) await waitJobs(servers) diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts index dee6575b9..fad4c8b1f 100644 --- a/server/tests/api/videos/video-change-ownership.ts +++ b/server/tests/api/videos/video-change-ownership.ts @@ -23,6 +23,7 @@ import { import { waitJobs } from '../../../../shared/extra-utils/server/jobs' import { User } from '../../../../shared/models/users' import { VideoDetails } from '../../../../shared/models/videos' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -140,7 +141,7 @@ describe('Test video change ownership - nominal', function () { it('Should not be possible to refuse the change of ownership from first user', async function () { this.timeout(10000) - await refuseChangeOwnership(servers[0].url, firstUserAccessToken, lastRequestChangeOwnershipId, 403) + await refuseChangeOwnership(servers[0].url, firstUserAccessToken, lastRequestChangeOwnershipId, HttpStatusCode.FORBIDDEN_403) }) it('Should be possible to refuse the change of ownership from second user', async function () { @@ -177,7 +178,7 @@ describe('Test video change ownership - nominal', function () { const secondUserInformationResponse = await getMyUserInformation(servers[0].url, secondUserAccessToken) const secondUserInformation: User = secondUserInformationResponse.body const channelId = secondUserInformation.videoChannels[0].id - await acceptChangeOwnership(servers[0].url, firstUserAccessToken, lastRequestChangeOwnershipId, channelId, 403) + await acceptChangeOwnership(servers[0].url, firstUserAccessToken, lastRequestChangeOwnershipId, channelId, HttpStatusCode.FORBIDDEN_403) }) it('Should be possible to accept the change of ownership from second user', async function () { @@ -294,7 +295,14 @@ describe('Test video change ownership - quota too small', function () { const secondUserInformationResponse = await getMyUserInformation(server.url, secondUserAccessToken) const secondUserInformation: User = secondUserInformationResponse.body const channelId = secondUserInformation.videoChannels[0].id - await acceptChangeOwnership(server.url, secondUserAccessToken, lastRequestChangeOwnershipId, channelId, 403) + + await acceptChangeOwnership( + server.url, + secondUserAccessToken, + lastRequestChangeOwnershipId, + channelId, + HttpStatusCode.PAYLOAD_TOO_LARGE_413 + ) }) after(async function () { diff --git a/server/tests/api/videos/video-hls.ts b/server/tests/api/videos/video-hls.ts index 3a65cc1d2..f3dbbb114 100644 --- a/server/tests/api/videos/video-hls.ts +++ b/server/tests/api/videos/video-hls.ts @@ -26,6 +26,7 @@ import { import { VideoDetails } from '../../../../shared/models/videos' import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -57,8 +58,8 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, hlsOn ) expect(file.resolution.label).to.equal(resolution + 'p') - await makeRawRequest(file.torrentUrl, 200) - await makeRawRequest(file.fileUrl, 200) + await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200) + await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) const torrent = await webtorrentAdd(file.magnetUri, true) expect(torrent.files).to.be.an('array') @@ -144,8 +145,8 @@ describe('Test HLS videos', function () { await waitJobs(servers) for (const server of servers) { - await getVideo(server.url, videoUUID, 404) - await getVideo(server.url, videoAudioUUID, 404) + await getVideo(server.url, videoUUID, HttpStatusCode.NOT_FOUND_404) + await getVideo(server.url, videoAudioUUID, HttpStatusCode.NOT_FOUND_404) } }) diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts index 7d1215990..0a96ea9a0 100644 --- a/server/tests/api/videos/video-playlists.ts +++ b/server/tests/api/videos/video-playlists.ts @@ -61,6 +61,7 @@ import { removeServerFromAccountBlocklist, removeServerFromServerBlocklist } from '../../../../shared/extra-utils/users/blocklist' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -1091,7 +1092,7 @@ describe('Test video playlists', function () { await waitJobs(servers) for (const server of servers) { - await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200) + await getVideoPlaylist(server.url, videoPlaylistIds.uuid, HttpStatusCode.OK_200) } const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE } @@ -1100,11 +1101,11 @@ describe('Test video playlists', function () { await waitJobs(servers) for (const server of [ servers[1], servers[2] ]) { - await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404) + await getVideoPlaylist(server.url, videoPlaylistIds.uuid, HttpStatusCode.NOT_FOUND_404) } - await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401) + await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, HttpStatusCode.UNAUTHORIZED_401) - await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200) + await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, HttpStatusCode.OK_200) }) }) @@ -1118,7 +1119,7 @@ describe('Test video playlists', function () { await waitJobs(servers) for (const server of servers) { - await getVideoPlaylist(server.url, playlistServer1UUID, 404) + await getVideoPlaylist(server.url, playlistServer1UUID, HttpStatusCode.NOT_FOUND_404) } }) @@ -1178,7 +1179,7 @@ describe('Test video playlists', function () { expect(res3.body.displayName).to.equal('channel playlist') expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE) - await getVideoPlaylist(servers[1].url, videoPlaylistUUID, 404) + await getVideoPlaylist(servers[1].url, videoPlaylistUUID, HttpStatusCode.NOT_FOUND_404) }) it('Should delete an account and delete its playlists', async function () { diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts index 38e93bbe6..f25d75af4 100644 --- a/server/tests/api/videos/video-privacy.ts +++ b/server/tests/api/videos/video-privacy.ts @@ -18,6 +18,7 @@ import { createUser } from '../../../../shared/extra-utils/users/users' import { getMyVideos, getVideo, getVideoWithToken, updateVideo } from '../../../../shared/extra-utils/videos/videos' import { waitJobs } from '../../../../shared/extra-utils/server/jobs' import { Video } from '@shared/models' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -110,8 +111,8 @@ describe('Test video privacy', function () { }) it('Should not be able to watch the private/internal video with non authenticated user', async function () { - await getVideo(servers[0].url, privateVideoUUID, 401) - await getVideo(servers[0].url, internalVideoUUID, 401) + await getVideo(servers[0].url, privateVideoUUID, HttpStatusCode.UNAUTHORIZED_401) + await getVideo(servers[0].url, internalVideoUUID, HttpStatusCode.UNAUTHORIZED_401) }) it('Should not be able to watch the private video with another user', async function () { @@ -124,15 +125,15 @@ describe('Test video privacy', function () { await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) anotherUserToken = await userLogin(servers[0], user) - await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, 403) + await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, HttpStatusCode.FORBIDDEN_403) }) it('Should be able to watch the internal video with another user', async function () { - await getVideoWithToken(servers[0].url, anotherUserToken, internalVideoUUID, 200) + await getVideoWithToken(servers[0].url, anotherUserToken, internalVideoUUID, HttpStatusCode.OK_200) }) it('Should be able to watch the private video with the correct user', async function () { - await getVideoWithToken(servers[0].url, servers[0].accessToken, privateVideoUUID, 200) + await getVideoWithToken(servers[0].url, servers[0].accessToken, privateVideoUUID, HttpStatusCode.OK_200) }) it('Should upload an unlisted video on server 2', async function () { @@ -202,7 +203,7 @@ describe('Test video privacy', function () { }) it('Should not be able to get non-federated unlisted video from federated server', async function () { - await getVideo(servers[1].url, nonFederatedUnlistedVideoUUID, 404) + await getVideo(servers[1].url, nonFederatedUnlistedVideoUUID, HttpStatusCode.NOT_FOUND_404) }) it('Should update the private and internal videos to public on server 1', async function () { diff --git a/server/tests/api/videos/videos-history.ts b/server/tests/api/videos/videos-history.ts index 6f90e9a57..661d603cb 100644 --- a/server/tests/api/videos/videos-history.ts +++ b/server/tests/api/videos/videos-history.ts @@ -20,6 +20,7 @@ import { } from '../../../../shared/extra-utils' import { Video, VideoDetails } from '../../../../shared/models/videos' import { listMyVideosHistory, removeMyVideosHistory, userWatchVideo } from '../../../../shared/extra-utils/videos/video-history' +import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -171,7 +172,7 @@ describe('Test videos history', function () { videosHistoryEnabled: false }) - await userWatchVideo(server.url, server.accessToken, video2UUID, 8, 409) + await userWatchVideo(server.url, server.accessToken, video2UUID, 8, HttpStatusCode.CONFLICT_409) }) it('Should re-enable videos history', async function () { diff --git a/server/tests/cli/reset-password.ts b/server/tests/cli/reset-password.ts index 6abb6738f..a84463b33 100644 --- a/server/tests/cli/reset-password.ts +++ b/server/tests/cli/reset-password.ts @@ -10,6 +10,7 @@ import { ServerInfo, setAccessTokensToServers } from '../../../shared/extra-utils' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' describe('Test reset password scripts', function () { let server: ServerInfo @@ -28,7 +29,7 @@ describe('Test reset password scripts', function () { const env = getEnvCli(server) await execCLI(`echo coucou | ${env} npm run reset-password -- -u user_1`) - await login(server.url, server.client, { username: 'user_1', password: 'coucou' }, 200) + await login(server.url, server.client, { username: 'user_1', password: 'coucou' }, HttpStatusCode.OK_200) }) after(async function () { diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 92a468192..f1055ea44 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts @@ -31,6 +31,7 @@ import { import { waitJobs } from '../../../shared/extra-utils/server/jobs' import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments' import { User } from '../../../shared/models/users' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' chai.use(require('chai-xml')) chai.use(require('chai-json-schema')) @@ -330,11 +331,16 @@ describe('Test syndication feeds', () => { }) it('Should fail with an invalid token', async function () { - await getJSONfeed(servers[0].url, 'subscriptions', { accountId: feeduserAccountId, token: 'toto' }, 403) + await getJSONfeed(servers[0].url, 'subscriptions', { accountId: feeduserAccountId, token: 'toto' }, HttpStatusCode.FORBIDDEN_403) }) it('Should fail with a token of another user', async function () { - await getJSONfeed(servers[0].url, 'subscriptions', { accountId: feeduserAccountId, token: userFeedToken }, 403) + await getJSONfeed( + servers[0].url, + 'subscriptions', + { accountId: feeduserAccountId, token: userFeedToken }, + HttpStatusCode.FORBIDDEN_403 + ) }) it('Should list no videos for a user with videos but no subscriptions', async function () { @@ -382,7 +388,12 @@ describe('Test syndication feeds', () => { it('Should renew the token, and so have an invalid old token', async function () { await renewUserScopedTokens(servers[0].url, userAccessToken) - await getJSONfeed(servers[0].url, 'subscriptions', { accountId: userAccountId, token: userFeedToken, version: 3 }, 403) + await getJSONfeed( + servers[0].url, + 'subscriptions', + { accountId: userAccountId, token: userFeedToken, version: 3 }, + HttpStatusCode.FORBIDDEN_403 + ) }) it('Should succeed with the new token', async function () { diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index 2441940c3..cdde6cd30 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts @@ -31,6 +31,7 @@ import { cleanupTests, flushAndRunMultipleServers, ServerInfo } from '../../../s import { getGoodVideoUrl, getMyVideoImports, importVideo } from '../../../shared/extra-utils/videos/video-imports' import { VideoDetails, VideoImport, VideoImportState, VideoPrivacy } from '../../../shared/models/videos' import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -127,7 +128,7 @@ describe('Test plugin filter hooks', function () { }) it('Should run filter:api.video.upload.accept.result', async function () { - await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video with bad word' }, 403) + await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video with bad word' }, HttpStatusCode.FORBIDDEN_403) }) it('Should run filter:api.live-video.create.accept.result', async function () { @@ -137,7 +138,7 @@ describe('Test plugin filter hooks', function () { channelId: servers[0].videoChannel.id } - await createLive(servers[0].url, servers[0].accessToken, attributes, 403) + await createLive(servers[0].url, servers[0].accessToken, attributes, HttpStatusCode.FORBIDDEN_403) }) it('Should run filter:api.video.pre-import-url.accept.result', async function () { @@ -147,7 +148,7 @@ describe('Test plugin filter hooks', function () { channelId: servers[0].videoChannel.id, targetUrl: getGoodVideoUrl() + 'bad' } - await importVideo(servers[0].url, servers[0].accessToken, baseAttributes, 403) + await importVideo(servers[0].url, servers[0].accessToken, baseAttributes, HttpStatusCode.FORBIDDEN_403) }) it('Should run filter:api.video.pre-import-torrent.accept.result', async function () { @@ -157,7 +158,7 @@ describe('Test plugin filter hooks', function () { channelId: servers[0].videoChannel.id, torrentfile: 'video-720p.torrent' as any } - await importVideo(servers[0].url, servers[0].accessToken, baseAttributes, 403) + await importVideo(servers[0].url, servers[0].accessToken, baseAttributes, HttpStatusCode.FORBIDDEN_403) }) it('Should run filter:api.video.post-import-url.accept.result', async function () { @@ -219,15 +220,22 @@ describe('Test plugin filter hooks', function () { }) it('Should run filter:api.video-thread.create.accept.result', async function () { - await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'comment with bad word', 403) + await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'comment with bad word', HttpStatusCode.FORBIDDEN_403) }) it('Should run filter:api.video-comment-reply.create.accept.result', async function () { const res = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'thread') threadId = res.body.comment.id - await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID, threadId, 'comment with bad word', 403) - await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID, threadId, 'comment with good word', 200) + await addVideoCommentReply( + servers[0].url, + servers[0].accessToken, + videoUUID, + threadId, + 'comment with bad word', + HttpStatusCode.FORBIDDEN_403 + ) + await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID, threadId, 'comment with good word', HttpStatusCode.OK_200) }) it('Should run filter:api.video-threads.list.params', async function () { @@ -326,7 +334,7 @@ describe('Test plugin filter hooks', function () { }) it('Should not allow a signup', async function () { - const res = await registerUser(servers[0].url, 'jma', 'password', 403) + const res = await registerUser(servers[0].url, 'jma', 'password', HttpStatusCode.FORBIDDEN_403) expect(res.body.error).to.equal('No jma') }) diff --git a/server/tests/plugins/video-constants.ts b/server/tests/plugins/video-constants.ts index fec9196e2..5ee41fee1 100644 --- a/server/tests/plugins/video-constants.ts +++ b/server/tests/plugins/video-constants.ts @@ -16,6 +16,7 @@ import { uploadVideo } from '../../../shared/extra-utils' import { VideoDetails, VideoPlaylistPrivacy } from '../../../shared/models/videos' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' const expect = chai.expect @@ -89,12 +90,17 @@ describe('Test plugin altering video constants', function () { it('Should not be able to create a video with this privacy', async function () { const attrs = { name: 'video', privacy: 2 } - await uploadVideo(server.url, server.accessToken, attrs, 400) + await uploadVideo(server.url, server.accessToken, attrs, HttpStatusCode.BAD_REQUEST_400) }) it('Should not be able to create a video with this privacy', async function () { const attrs = { displayName: 'video playlist', privacy: VideoPlaylistPrivacy.PRIVATE } - await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs: attrs, expectedStatus: 400 }) + await createVideoPlaylist({ + url: server.url, + token: server.accessToken, + playlistAttrs: attrs, + expectedStatus: HttpStatusCode.BAD_REQUEST_400 + }) }) it('Should be able to upload a video with these values', async function () { diff --git a/server/tools/peertube-redundancy.ts b/server/tools/peertube-redundancy.ts index 1ab58a438..fe482daf4 100644 --- a/server/tools/peertube-redundancy.ts +++ b/server/tools/peertube-redundancy.ts @@ -7,6 +7,7 @@ import * as program from 'commander' import { getAdminTokenOrDie, getServerCredentials } from './cli' import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy } from '@shared/extra-utils/server/redundancy' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' import validator from 'validator' import * as CliTable3 from 'cli-table3' import { URL } from 'url' @@ -124,9 +125,9 @@ async function addRedundancyCLI (options: { videoId: number }) { process.exit(0) } catch (err) { - if (err.message.includes(409)) { + if (err.message.includes(HttpStatusCode.CONFLICT_409)) { console.error('This video is already duplicated by your instance.') - } else if (err.message.includes(404)) { + } else if (err.message.includes(HttpStatusCode.NOT_FOUND_404)) { console.error('This video id does not exist.') } else { console.error(err) diff --git a/shared/core-utils/miscs/http-error-codes.ts b/shared/core-utils/miscs/http-error-codes.ts index 8c8b87ba0..9ac8a6c83 100644 --- a/shared/core-utils/miscs/http-error-codes.ts +++ b/shared/core-utils/miscs/http-error-codes.ts @@ -1,6 +1,8 @@ /** * Hypertext Transfer Protocol (HTTP) response status codes. * @see {@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes} + * + * WebDAV and other codes useless with regards to PeerTube are not listed. */ export enum HttpStatusCode { @@ -47,15 +49,6 @@ export enum HttpStatusCode { */ ACCEPTED_202 = 202, - /** - * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.3.4 - * - * SINCE HTTP/1.1 - * The server is a transforming proxy that received a 200 OK from its origin, - * but is returning a modified version of the origin's response. - */ - NON_AUTHORITATIVE_INFORMATION_203 = 203, - /** * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.3.5 * @@ -77,18 +70,6 @@ export enum HttpStatusCode { */ PARTIAL_CONTENT_206 = 206, - /** - * The message body that follows is an XML message and can contain a number of separate response codes, - * depending on how many sub-requests were made. - */ - MULTI_STATUS_207 = 207, - - /** - * The server has fulfilled a request for the resource, - * and the response is a representation of the result of one or more instance-manipulations applied to the current instance. - */ - IM_USED_226 = 226, - /** * Indicates multiple options for the resource from which the client may choose (via agent-driven content negotiation). * For example, this code could be used to present multiple video format options, @@ -128,20 +109,6 @@ export enum HttpStatusCode { */ NOT_MODIFIED_304 = 304, - /** - * @deprecated - * SINCE HTTP/1.1 - * The requested resource is available only through a proxy, the address for which is provided in the response. - * Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly handle responses with this status - * code, primarily for security reasons. - */ - USE_PROXY_305 = 305, - - /** - * No longer used. Originally meant "Subsequent requests should use the specified proxy." - */ - SWITCH_PROXY_306 = 306, - /** * SINCE HTTP/1.1 * In this case, the request should be repeated with another URI; however, future requests should still use the original URI. @@ -175,6 +142,8 @@ export enum HttpStatusCode { UNAUTHORIZED_401 = 401, /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.5.2 + * * Reserved for future use. The original intention was that this code might be used as part of some form of digital * cash or micro payment scheme, but that has not happened, and this code is not usually used. * Google Developers API uses this status if a particular developer has exceeded the daily limit on requests. @@ -210,11 +179,6 @@ export enum HttpStatusCode { */ NOT_ACCEPTABLE_406 = 406, - /** - * The client must first authenticate itself with the proxy. - */ - PROXY_AUTHENTICATION_REQUIRED_407 = 407, - /** * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.5.7 * @@ -222,10 +186,14 @@ export enum HttpStatusCode { * It means that the server would like to shut down this unused connection. This response is used much more since * some browsers, like Chrome, Firefox 27+, or IE9, use HTTP pre-connection mechanisms to speed up surfing. Also * note that some servers merely shut down the connection without sending this message. + * + * @ */ REQUEST_TIMEOUT_408 = 408, /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.5.8 + * * Indicates that the request could not be processed because of conflict in the request, * such as an edit conflict between multiple simultaneous updates. */ @@ -284,52 +252,39 @@ export enum HttpStatusCode { RANGE_NOT_SATISFIABLE_416 = 416, /** - * The server cannot meet the requirements of the Expect request-header field. + * The server cannot meet the requirements of the `Expect` request-header field. */ EXPECTATION_FAILED_417 = 417, /** + * Official Documentation @ https://tools.ietf.org/html/rfc2324 + * * This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot Control Protocol, * and is not expected to be implemented by actual HTTP servers. The RFC specifies this code should be returned by * teapots requested to brew coffee. This HTTP status is used as an Easter egg in some websites, including PeerTube instances ;-). */ I_AM_A_TEAPOT_418 = 418, - /** - * The request was directed at a server that is not able to produce a response (for example because a connection reuse). - */ - MISDIRECTED_REQUEST_421 = 421, - /** * Official Documentation @ https://tools.ietf.org/html/rfc2518#section-10.3 * * The request was well-formed but was unable to be followed due to semantic errors. + * + * @see HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415 if the `Content-Type` was not supported. + * @see HttpStatusCode.BAD_REQUEST_400 if the request was not parsable (broken JSON, XML) */ UNPROCESSABLE_ENTITY_422 = 422, /** - * The resource that is being accessed is locked. + * Official Documentation @ https://tools.ietf.org/html/rfc4918#section-11.3 + * + * The resource that is being accessed is locked. WebDAV-specific but used by some HTTP services. + * + * @deprecated use `If-Match` / `If-None-Match` instead + * @see {@link https://evertpot.com/http/423-locked} */ LOCKED_423 = 423, - /** - * The request failed due to failure of a previous request (e.g., a PROPPATCH). - */ - FAILED_DEPENDENCY_424 = 424, - - /** - * The client should switch to a different protocol such as TLS/1.0, given in the Upgrade header field. - */ - UPGRADE_REQUIRED_426 = 426, - - /** - * The origin server requires the request to be conditional. - * Intended to prevent "the 'lost update' problem, where a client - * GETs a resource's state, modifies it, and PUTs it back to the server, - * when meanwhile a third party has modified the state on the server, leading to a conflict." - */ - PRECONDITION_REQUIRED_428 = 428, - /** * Official Documentation @ https://tools.ietf.org/html/rfc6585#section-4 * @@ -359,6 +314,8 @@ export enum HttpStatusCode { INTERNAL_SERVER_ERROR_500 = 500, /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.6.2 + * * The server either does not recognize the request method, or it lacks the ability to fulfill the request. * Usually this implies future availability (e.g., a new feature of a web-service API). */ @@ -385,11 +342,6 @@ export enum HttpStatusCode { */ HTTP_VERSION_NOT_SUPPORTED_505 = 505, - /** - * Transparent content negotiation for the request results in a circular reference. - */ - VARIANT_ALSO_NEGOTIATES_506 = 506, - /** * Official Documentation @ https://tools.ietf.org/html/rfc2518#section-10.6 * @@ -397,23 +349,8 @@ export enum HttpStatusCode { * server is unable to store the representation needed to successfully complete the request. This condition is * considered to be temporary. If the request which received this status code was the result of a user action, * the request MUST NOT be repeated until it is requested by a separate user action. + * + * @see HttpStatusCode.PAYLOAD_TOO_LARGE_413 for quota errors */ INSUFFICIENT_STORAGE_507 = 507, - - /** - * The server detected an infinite loop while processing the request. - */ - LOOP_DETECTED_508 = 508, - - /** - * Further extensions to the request are required for the server to fulfill it. - */ - NOT_EXTENDED_510 = 510, - - /** - * The client needs to authenticate to gain network access. - * Intended for use by intercepting proxies used to control access to the network (e.g., "captive portals" used - * to require agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot). - */ - NETWORK_AUTHENTICATION_REQUIRED_511 = 511 } diff --git a/shared/extra-utils/server/activitypub.ts b/shared/extra-utils/server/activitypub.ts index eccb198ca..cf967ed7d 100644 --- a/shared/extra-utils/server/activitypub.ts +++ b/shared/extra-utils/server/activitypub.ts @@ -1,6 +1,7 @@ import * as request from 'supertest' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -function makeActivityPubGetRequest (url: string, path: string, expectedStatus = 200) { +function makeActivityPubGetRequest (url: string, path: string, expectedStatus = HttpStatusCode.OK_200) { return request(url) .get(path) .set('Accept', 'application/activity+json,text/html;q=0.9,\\*/\\*;q=0.8') diff --git a/shared/extra-utils/server/redundancy.ts b/shared/extra-utils/server/redundancy.ts index 3aca4ebfd..b83815a37 100644 --- a/shared/extra-utils/server/redundancy.ts +++ b/shared/extra-utils/server/redundancy.ts @@ -2,7 +2,13 @@ import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequ import { VideoRedundanciesTarget } from '@shared/models' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) { +function updateRedundancy ( + url: string, + accessToken: string, + host: string, + redundancyAllowed: boolean, + expectedStatus = HttpStatusCode.NO_CONTENT_204 +) { const path = '/api/v1/server/redundancy/' + host return makePutBodyRequest({ diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts index 275bb0826..39e1a2747 100644 --- a/shared/extra-utils/users/login.ts +++ b/shared/extra-utils/users/login.ts @@ -2,12 +2,13 @@ import * as request from 'supertest' import { ServerInfo } from '../server/servers' import { getClient } from '../server/clients' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' type Client = { id: string, secret: string } type User = { username: string, password: string } type Server = { url: string, client: Client, user: User } -function login (url: string, client: Client, user: User, expectedStatus = 200) { +function login (url: string, client: Client, user: User, expectedStatus = HttpStatusCode.OK_200) { const path = '/api/v1/users/token' const body = { @@ -27,7 +28,7 @@ function login (url: string, client: Client, user: User, expectedStatus = 200) { .expect(expectedStatus) } -function logout (url: string, token: string, expectedStatus = 200) { +function logout (url: string, token: string, expectedStatus = HttpStatusCode.OK_200) { const path = '/api/v1/users/revoke-token' return request(url) @@ -38,12 +39,12 @@ function logout (url: string, token: string, expectedStatus = 200) { } async function serverLogin (server: Server) { - const res = await login(server.url, server.client, server.user, 200) + const res = await login(server.url, server.client, server.user, HttpStatusCode.OK_200) return res.body.access_token as string } -function refreshToken (server: ServerInfo, refreshToken: string, expectedStatus = 200) { +function refreshToken (server: ServerInfo, refreshToken: string, expectedStatus = HttpStatusCode.OK_200) { const path = '/api/v1/users/token' const body = { @@ -61,7 +62,7 @@ function refreshToken (server: ServerInfo, refreshToken: string, expectedStatus .expect(expectedStatus) } -async function userLogin (server: Server, user: User, expectedStatus = 200) { +async function userLogin (server: Server, user: User, expectedStatus = HttpStatusCode.OK_200) { const res = await login(server.url, server.client, user, expectedStatus) return res.body.access_token as string @@ -95,7 +96,7 @@ function setAccessTokensToServers (servers: ServerInfo[]) { return Promise.all(tasks) } -function loginUsingExternalToken (server: Server, username: string, externalAuthToken: string, expectedStatus = 200) { +function loginUsingExternalToken (server: Server, username: string, externalAuthToken: string, expectedStatus = HttpStatusCode.OK_200) { const path = '/api/v1/users/token' const body = { diff --git a/shared/extra-utils/videos/video-history.ts b/shared/extra-utils/videos/video-history.ts index 2d751cf14..0dd3afb24 100644 --- a/shared/extra-utils/videos/video-history.ts +++ b/shared/extra-utils/videos/video-history.ts @@ -1,7 +1,13 @@ import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -function userWatchVideo (url: string, token: string, videoId: number | string, currentTime: number, statusCodeExpected = 204) { +function userWatchVideo ( + url: string, + token: string, + videoId: number | string, + currentTime: number, + statusCodeExpected = HttpStatusCode.NO_CONTENT_204 +) { const path = '/api/v1/videos/' + videoId + '/watching' const fields = { currentTime } diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index a4b9d688e..a2438d712 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -155,7 +155,7 @@ function getVideosListWithToken (url: string, token: string, query: { nsfw?: boo .set('Authorization', 'Bearer ' + token) .query(immutableAssign(query, { sort: 'name' })) .set('Accept', 'application/json') - .expect(200) + .expect(HttpStatusCode.OK_200) .expect('Content-Type', /json/) } @@ -166,7 +166,7 @@ function getLocalVideos (url: string) { .get(path) .query({ sort: 'name', filter: 'local' }) .set('Accept', 'application/json') - .expect(200) + .expect(HttpStatusCode.OK_200) .expect('Content-Type', /json/) } diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 2d6b4df27..ba420b4a9 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml @@ -1312,20 +1312,24 @@ paths: application/json: schema: $ref: '#/components/schemas/VideoUploadResponse' + '400': + description: invalid file field, schedule date or parameter '403': - description: user video quota is exceeded with this video + description: video didn't pass upload filter '408': description: upload has timed out '413': - description: video file too large + description: video file too large, due to quota or max body size limit set by the reverse-proxy headers: X-File-Maximum-Size: schema: type: string format: Nginx size description: Maximum file size for the video + '415': + description: video type unsupported '422': - description: invalid input file + description: video unreadable requestBody: content: multipart/form-data: @@ -1534,10 +1538,12 @@ paths: application/json: schema: $ref: '#/components/schemas/VideoUploadResponse' - '409': - description: HTTP or Torrent/magnetURI import not enabled '400': description: '`magnetUri` or `targetUrl` or a torrent file missing' + '403': + description: video didn't pass pre-import filter + '409': + description: HTTP or Torrent/magnetURI import not enabled /videos/live: post: @@ -3572,7 +3578,7 @@ components: name: name in: path required: true - description: The name of the account + description: The username or handle of the account schema: type: string example: chocobozzz | chocobozzz@example.org @@ -5175,7 +5181,7 @@ components: properties: name: type: string - description: The name for the default channel + description: The username for the default channel pattern: '/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\\-_.:]+$/' displayName: type: string -- 2.41.0