diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-02 18:15:41 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-02 18:15:41 +0200 |
commit | e030bfb59dd5ee65f20a64686ec9b22ca39f70ae (patch) | |
tree | c9a439159ef540291e3c030bcaf958b953442147 | |
parent | 463206948d6a9d46e7e68d55c7b763e601ecc870 (diff) | |
download | PeerTube-e030bfb59dd5ee65f20a64686ec9b22ca39f70ae.tar.gz PeerTube-e030bfb59dd5ee65f20a64686ec9b22ca39f70ae.tar.zst PeerTube-e030bfb59dd5ee65f20a64686ec9b22ca39f70ae.zip |
Refactor server errors handler
20 files changed, 236 insertions, 60 deletions
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts index 727bbc32f..15178a267 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts | |||
@@ -8,7 +8,7 @@ import { FormValidatorService } from '@app/shared/shared-forms' | |||
8 | import { VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' | 8 | import { VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' |
9 | import { LiveVideoService } from '@app/shared/shared-video-live' | 9 | import { LiveVideoService } from '@app/shared/shared-video-live' |
10 | import { LoadingBarService } from '@ngx-loading-bar/core' | 10 | import { LoadingBarService } from '@ngx-loading-bar/core' |
11 | import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, ServerErrorCode, VideoPrivacy } from '@shared/models' | 11 | import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, PeerTubeProblemDocument, ServerErrorCode, VideoPrivacy } from '@shared/models' |
12 | import { VideoSend } from './video-send' | 12 | import { VideoSend } from './video-send' |
13 | 13 | ||
14 | @Component({ | 14 | @Component({ |
@@ -92,9 +92,11 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView | |||
92 | 92 | ||
93 | let message = err.message | 93 | let message = err.message |
94 | 94 | ||
95 | if (err.body?.code === ServerErrorCode.MAX_INSTANCE_LIVES_LIMIT_REACHED) { | 95 | const error = err.body as PeerTubeProblemDocument |
96 | |||
97 | if (error?.code === ServerErrorCode.MAX_INSTANCE_LIVES_LIMIT_REACHED) { | ||
96 | message = $localize`Cannot create live because this instance have too many created lives` | 98 | message = $localize`Cannot create live because this instance have too many created lives` |
97 | } else if (err.body?.code) { | 99 | } else if (error?.code === ServerErrorCode.MAX_USER_LIVES_LIMIT_REACHED) { |
98 | message = $localize`Cannot create live because you created too many lives` | 100 | message = $localize`Cannot create live because you created too many lives` |
99 | } | 101 | } |
100 | 102 | ||
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts index 23bd5ef76..2837b30c1 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts | |||
@@ -5,7 +5,7 @@ import { scrollToTop } from '@app/helpers' | |||
5 | import { FormValidatorService } from '@app/shared/shared-forms' | 5 | import { FormValidatorService } from '@app/shared/shared-forms' |
6 | import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' | 6 | import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' |
7 | import { LoadingBarService } from '@ngx-loading-bar/core' | 7 | import { LoadingBarService } from '@ngx-loading-bar/core' |
8 | import { ServerErrorCode, VideoPrivacy, VideoUpdate } from '@shared/models' | 8 | import { PeerTubeProblemDocument, ServerErrorCode, VideoPrivacy, VideoUpdate } from '@shared/models' |
9 | import { hydrateFormFromVideo } from '../shared/video-edit-utils' | 9 | import { hydrateFormFromVideo } from '../shared/video-edit-utils' |
10 | import { VideoSend } from './video-send' | 10 | import { VideoSend } from './video-send' |
11 | 11 | ||
@@ -115,7 +115,9 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Af | |||
115 | this.firstStepError.emit() | 115 | this.firstStepError.emit() |
116 | 116 | ||
117 | let message = err.message | 117 | let message = err.message |
118 | if (err.body?.code === ServerErrorCode.INCORRECT_FILES_IN_TORRENT) { | 118 | |
119 | const error = err.body as PeerTubeProblemDocument | ||
120 | if (error?.code === ServerErrorCode.INCORRECT_FILES_IN_TORRENT) { | ||
119 | message = $localize`Torrents with only 1 file are supported.` | 121 | message = $localize`Torrents with only 1 file are supported.` |
120 | } | 122 | } |
121 | 123 | ||
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 8034ccebf..540b568ed 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts | |||
@@ -28,7 +28,7 @@ import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/sha | |||
28 | import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' | 28 | import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' |
29 | import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' | 29 | import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' |
30 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | 30 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' |
31 | import { ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models' | 31 | import { PeerTubeProblemDocument, ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models' |
32 | import { | 32 | import { |
33 | cleanupVideoWatch, | 33 | cleanupVideoWatch, |
34 | getStoredP2PEnabled, | 34 | getStoredP2PEnabled, |
@@ -431,9 +431,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
431 | .pipe( | 431 | .pipe( |
432 | // If 400, 403 or 404, the video is private or blocked so redirect to 404 | 432 | // If 400, 403 or 404, the video is private or blocked so redirect to 404 |
433 | catchError(err => { | 433 | catchError(err => { |
434 | if (err.body.type === ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS && err.body.originUrl) { | 434 | const errorBody = err.body as PeerTubeProblemDocument |
435 | |||
436 | if (errorBody.code === ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS && errorBody.originUrl) { | ||
435 | const search = window.location.search | 437 | const search = window.location.search |
436 | let originUrl = err.body.originUrl | 438 | let originUrl = errorBody.originUrl |
437 | if (search) originUrl += search | 439 | if (search) originUrl += search |
438 | 440 | ||
439 | this.confirmService.confirm( | 441 | this.confirmService.confirm( |
diff --git a/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts b/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts index 4fe3b964d..5bcad36d0 100644 --- a/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts +++ b/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts | |||
@@ -5,6 +5,7 @@ import { Injectable, Injector } from '@angular/core' | |||
5 | import { AuthService } from '@app/core/auth/auth.service' | 5 | import { AuthService } from '@app/core/auth/auth.service' |
6 | import { Router } from '@angular/router' | 6 | import { Router } from '@angular/router' |
7 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | 7 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' |
8 | import { OAuth2ErrorCode, PeerTubeProblemDocument, ServerErrorCode } from '@shared/models/server' | ||
8 | 9 | ||
9 | @Injectable() | 10 | @Injectable() |
10 | export class AuthInterceptor implements HttpInterceptor { | 11 | export class AuthInterceptor implements HttpInterceptor { |
@@ -25,7 +26,9 @@ export class AuthInterceptor implements HttpInterceptor { | |||
25 | return next.handle(authReq) | 26 | return next.handle(authReq) |
26 | .pipe( | 27 | .pipe( |
27 | catchError((err: HttpErrorResponse) => { | 28 | catchError((err: HttpErrorResponse) => { |
28 | if (err.status === HttpStatusCode.UNAUTHORIZED_401 && err.error && err.error.code === 'invalid_token') { | 29 | const error = err.error as PeerTubeProblemDocument |
30 | |||
31 | if (err.status === HttpStatusCode.UNAUTHORIZED_401 && error && error.code === OAuth2ErrorCode.INVALID_TOKEN) { | ||
29 | return this.handleTokenExpired(req, next) | 32 | return this.handleTokenExpired(req, next) |
30 | } | 33 | } |
31 | 34 | ||
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index fc61d3730..4ce5c78e8 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts | |||
@@ -5,6 +5,7 @@ import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-c | |||
5 | import { | 5 | import { |
6 | ClientHookName, | 6 | ClientHookName, |
7 | HTMLServerConfig, | 7 | HTMLServerConfig, |
8 | OAuth2ErrorCode, | ||
8 | PluginType, | 9 | PluginType, |
9 | ResultList, | 10 | ResultList, |
10 | UserRefreshToken, | 11 | UserRefreshToken, |
@@ -118,8 +119,8 @@ export class PeerTubeEmbed { | |||
118 | if (res.status === HttpStatusCode.UNAUTHORIZED_401) return undefined | 119 | if (res.status === HttpStatusCode.UNAUTHORIZED_401) return undefined |
119 | 120 | ||
120 | return res.json() | 121 | return res.json() |
121 | }).then((obj: UserRefreshToken & { code: 'invalid_grant'}) => { | 122 | }).then((obj: UserRefreshToken & { code?: OAuth2ErrorCode }) => { |
122 | if (!obj || obj.code === 'invalid_grant') { | 123 | if (!obj || obj.code === OAuth2ErrorCode.INVALID_GRANT) { |
123 | Tokens.flush() | 124 | Tokens.flush() |
124 | this.removeTokensFromHeaders() | 125 | this.removeTokensFromHeaders() |
125 | 126 | ||
@@ -106,6 +106,7 @@ import { | |||
106 | downloadRouter | 106 | downloadRouter |
107 | } from './server/controllers' | 107 | } from './server/controllers' |
108 | import { advertiseDoNotTrack } from './server/middlewares/dnt' | 108 | import { advertiseDoNotTrack } from './server/middlewares/dnt' |
109 | import { apiFailMiddleware } from './server/middlewares/error' | ||
109 | import { Redis } from './server/lib/redis' | 110 | import { Redis } from './server/lib/redis' |
110 | import { ActorFollowScheduler } from './server/lib/schedulers/actor-follow-scheduler' | 111 | import { ActorFollowScheduler } from './server/lib/schedulers/actor-follow-scheduler' |
111 | import { RemoveOldViewsScheduler } from './server/lib/schedulers/remove-old-views-scheduler' | 112 | import { RemoveOldViewsScheduler } from './server/lib/schedulers/remove-old-views-scheduler' |
@@ -127,7 +128,6 @@ import { LiveManager } from './server/lib/live-manager' | |||
127 | import { HttpStatusCode } from './shared/core-utils/miscs/http-error-codes' | 128 | import { HttpStatusCode } from './shared/core-utils/miscs/http-error-codes' |
128 | import { VideosTorrentCache } from '@server/lib/files-cache/videos-torrent-cache' | 129 | import { VideosTorrentCache } from '@server/lib/files-cache/videos-torrent-cache' |
129 | import { ServerConfigManager } from '@server/lib/server-config-manager' | 130 | import { ServerConfigManager } from '@server/lib/server-config-manager' |
130 | import { apiResponseHelpers } from '@server/helpers/express-utils' | ||
131 | 131 | ||
132 | // ----------- Command line ----------- | 132 | // ----------- Command line ----------- |
133 | 133 | ||
@@ -169,8 +169,8 @@ app.use(morgan('combined', { | |||
169 | skip: req => CONFIG.LOG.LOG_PING_REQUESTS === false && req.originalUrl === '/api/v1/ping' | 169 | skip: req => CONFIG.LOG.LOG_PING_REQUESTS === false && req.originalUrl === '/api/v1/ping' |
170 | })) | 170 | })) |
171 | 171 | ||
172 | // Response helpers used for errors | 172 | // Add .fail() helper to response |
173 | app.use(apiResponseHelpers) | 173 | app.use(apiFailMiddleware) |
174 | 174 | ||
175 | // For body requests | 175 | // For body requests |
176 | app.use(express.urlencoded({ extended: false })) | 176 | app.use(express.urlencoded({ extended: false })) |
@@ -179,6 +179,7 @@ app.use(express.json({ | |||
179 | limit: '500kb', | 179 | limit: '500kb', |
180 | verify: (req: express.Request, res: express.Response, buf: Buffer) => { | 180 | verify: (req: express.Request, res: express.Response, buf: Buffer) => { |
181 | const valid = isHTTPSignatureDigestValid(buf, req) | 181 | const valid = isHTTPSignatureDigestValid(buf, req) |
182 | |||
182 | if (valid !== true) { | 183 | if (valid !== true) { |
183 | res.fail({ | 184 | res.fail({ |
184 | status: HttpStatusCode.FORBIDDEN_403, | 185 | status: HttpStatusCode.FORBIDDEN_403, |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index db23e5630..7671f099e 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -2,6 +2,7 @@ import * as express from 'express' | |||
2 | import toInt from 'validator/lib/toInt' | 2 | import toInt from 'validator/lib/toInt' |
3 | import { doJSONRequest } from '@server/helpers/requests' | 3 | import { doJSONRequest } from '@server/helpers/requests' |
4 | import { LiveManager } from '@server/lib/live-manager' | 4 | import { LiveManager } from '@server/lib/live-manager' |
5 | import { docMiddleware } from '@server/middlewares/doc' | ||
5 | import { getServerActor } from '@server/models/application/application' | 6 | import { getServerActor } from '@server/models/application/application' |
6 | import { MVideoAccountLight } from '@server/types/models' | 7 | import { MVideoAccountLight } from '@server/types/models' |
7 | import { VideosCommonQuery } from '../../../../shared' | 8 | import { VideosCommonQuery } from '../../../../shared' |
@@ -83,6 +84,7 @@ videosRouter.get('/:id/metadata/:videoFileId', | |||
83 | asyncMiddleware(getVideoFileMetadata) | 84 | asyncMiddleware(getVideoFileMetadata) |
84 | ) | 85 | ) |
85 | videosRouter.get('/:id', | 86 | videosRouter.get('/:id', |
87 | docMiddleware('https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo'), | ||
86 | optionalAuthenticate, | 88 | optionalAuthenticate, |
87 | asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), | 89 | asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), |
88 | asyncMiddleware(checkVideoFollowConstraints), | 90 | asyncMiddleware(checkVideoFollowConstraints), |
@@ -94,6 +96,7 @@ videosRouter.post('/:id/views', | |||
94 | ) | 96 | ) |
95 | 97 | ||
96 | videosRouter.delete('/:id', | 98 | videosRouter.delete('/:id', |
99 | docMiddleware('https://docs.joinpeertube.org/api-rest-reference.html#operation/delVideo'), | ||
97 | authenticate, | 100 | authenticate, |
98 | asyncMiddleware(videosRemoveValidator), | 101 | asyncMiddleware(videosRemoveValidator), |
99 | asyncRetryTransactionMiddleware(removeVideo) | 102 | asyncRetryTransactionMiddleware(removeVideo) |
diff --git a/server/controllers/api/videos/update.ts b/server/controllers/api/videos/update.ts index 2450abd0e..09e584d30 100644 --- a/server/controllers/api/videos/update.ts +++ b/server/controllers/api/videos/update.ts | |||
@@ -20,6 +20,7 @@ import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' | |||
20 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videosUpdateValidator } from '../../../middlewares' | 20 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videosUpdateValidator } from '../../../middlewares' |
21 | import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update' | 21 | import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update' |
22 | import { VideoModel } from '../../../models/video/video' | 22 | import { VideoModel } from '../../../models/video/video' |
23 | import { docMiddleware } from '@server/middlewares/doc' | ||
23 | 24 | ||
24 | const lTags = loggerTagsFactory('api', 'video') | 25 | const lTags = loggerTagsFactory('api', 'video') |
25 | const auditLogger = auditLoggerFactory('videos') | 26 | const auditLogger = auditLoggerFactory('videos') |
@@ -35,6 +36,7 @@ const reqVideoFileUpdate = createReqFiles( | |||
35 | ) | 36 | ) |
36 | 37 | ||
37 | updateRouter.put('/:id', | 38 | updateRouter.put('/:id', |
39 | docMiddleware('https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo'), | ||
38 | authenticate, | 40 | authenticate, |
39 | reqVideoFileUpdate, | 41 | reqVideoFileUpdate, |
40 | asyncMiddleware(videosUpdateValidator), | 42 | asyncMiddleware(videosUpdateValidator), |
diff --git a/server/controllers/api/videos/upload.ts b/server/controllers/api/videos/upload.ts index c33d7fcb9..93a68f759 100644 --- a/server/controllers/api/videos/upload.ts +++ b/server/controllers/api/videos/upload.ts | |||
@@ -6,6 +6,7 @@ import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | |||
6 | import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' | 6 | import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' |
7 | import { addOptimizeOrMergeAudioJob, buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' | 7 | import { addOptimizeOrMergeAudioJob, buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' |
8 | import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths' | 8 | import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths' |
9 | import { docMiddleware } from '@server/middlewares/doc' | ||
9 | import { MVideo, MVideoFile, MVideoFullLight } from '@server/types/models' | 10 | import { MVideo, MVideoFile, MVideoFullLight } from '@server/types/models' |
10 | import { uploadx } from '@uploadx/core' | 11 | import { uploadx } from '@uploadx/core' |
11 | import { VideoCreate, VideoState } from '../../../../shared' | 12 | import { VideoCreate, VideoState } from '../../../../shared' |
@@ -60,6 +61,7 @@ const reqVideoFileAddResumable = createReqFiles( | |||
60 | ) | 61 | ) |
61 | 62 | ||
62 | uploadRouter.post('/upload', | 63 | uploadRouter.post('/upload', |
64 | docMiddleware('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadLegacy'), | ||
63 | authenticate, | 65 | authenticate, |
64 | reqVideoFileAdd, | 66 | reqVideoFileAdd, |
65 | asyncMiddleware(videosAddLegacyValidator), | 67 | asyncMiddleware(videosAddLegacyValidator), |
@@ -67,6 +69,7 @@ uploadRouter.post('/upload', | |||
67 | ) | 69 | ) |
68 | 70 | ||
69 | uploadRouter.post('/upload-resumable', | 71 | uploadRouter.post('/upload-resumable', |
72 | docMiddleware('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumableInit'), | ||
70 | authenticate, | 73 | authenticate, |
71 | reqVideoFileAddResumable, | 74 | reqVideoFileAddResumable, |
72 | asyncMiddleware(videosAddResumableInitValidator), | 75 | asyncMiddleware(videosAddResumableInitValidator), |
@@ -79,6 +82,7 @@ uploadRouter.delete('/upload-resumable', | |||
79 | ) | 82 | ) |
80 | 83 | ||
81 | uploadRouter.put('/upload-resumable', | 84 | uploadRouter.put('/upload-resumable', |
85 | docMiddleware('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumable'), | ||
82 | authenticate, | 86 | authenticate, |
83 | uploadxMiddleware, // uploadx doesn't use call next() before the file upload completes | 87 | uploadxMiddleware, // uploadx doesn't use call next() before the file upload completes |
84 | asyncMiddleware(videosAddResumableValidator), | 88 | asyncMiddleware(videosAddResumableValidator), |
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts index 10a860787..010c6961a 100644 --- a/server/helpers/express-utils.ts +++ b/server/helpers/express-utils.ts | |||
@@ -8,7 +8,6 @@ import { isArray } from './custom-validators/misc' | |||
8 | import { logger } from './logger' | 8 | import { logger } from './logger' |
9 | import { deleteFileAndCatch, generateRandomString } from './utils' | 9 | import { deleteFileAndCatch, generateRandomString } from './utils' |
10 | import { getExtFromMimetype } from './video' | 10 | import { getExtFromMimetype } from './video' |
11 | import { ProblemDocument, ProblemDocumentExtension } from 'http-problem-details' | ||
12 | 11 | ||
13 | function buildNSFWFilter (res?: express.Response, paramNSFW?: string) { | 12 | function buildNSFWFilter (res?: express.Response, paramNSFW?: string) { |
14 | if (paramNSFW === 'true') return true | 13 | if (paramNSFW === 'true') return true |
@@ -126,34 +125,6 @@ function getCountVideos (req: express.Request) { | |||
126 | return req.query.skipCount !== true | 125 | return req.query.skipCount !== true |
127 | } | 126 | } |
128 | 127 | ||
129 | // helpers added in server.ts and used in subsequent controllers used | ||
130 | const apiResponseHelpers = (req, res: express.Response, next = null) => { | ||
131 | res.fail = (options) => { | ||
132 | const { data, status = HttpStatusCode.BAD_REQUEST_400, message, title, type, docs = res.docs, instance } = options | ||
133 | |||
134 | const extension = new ProblemDocumentExtension({ | ||
135 | ...data, | ||
136 | docs, | ||
137 | // fields for <= 3.2 compatibility, deprecated | ||
138 | error: message, | ||
139 | code: type | ||
140 | }) | ||
141 | |||
142 | res.status(status) | ||
143 | res.setHeader('Content-Type', 'application/problem+json') | ||
144 | res.json(new ProblemDocument({ | ||
145 | status, | ||
146 | title, | ||
147 | instance, | ||
148 | // fields intended to replace 'error' and 'code' respectively | ||
149 | detail: message, | ||
150 | type: type && 'https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/' + type | ||
151 | }, extension)) | ||
152 | } | ||
153 | |||
154 | if (next) next() | ||
155 | } | ||
156 | |||
157 | // --------------------------------------------------------------------------- | 128 | // --------------------------------------------------------------------------- |
158 | 129 | ||
159 | export { | 130 | export { |
@@ -163,6 +134,5 @@ export { | |||
163 | badRequest, | 134 | badRequest, |
164 | createReqFiles, | 135 | createReqFiles, |
165 | cleanUpReqFiles, | 136 | cleanUpReqFiles, |
166 | getCountVideos, | 137 | getCountVideos |
167 | apiResponseHelpers | ||
168 | } | 138 | } |
diff --git a/server/middlewares/doc.ts b/server/middlewares/doc.ts new file mode 100644 index 000000000..aa852cd77 --- /dev/null +++ b/server/middlewares/doc.ts | |||
@@ -0,0 +1,13 @@ | |||
1 | import * as express from 'express' | ||
2 | |||
3 | function docMiddleware (docUrl: string) { | ||
4 | return (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
5 | res.locals.docUrl = docUrl | ||
6 | |||
7 | if (next) return next() | ||
8 | } | ||
9 | } | ||
10 | |||
11 | export { | ||
12 | docMiddleware | ||
13 | } | ||
diff --git a/server/middlewares/error.ts b/server/middlewares/error.ts new file mode 100644 index 000000000..e3eb1c8f5 --- /dev/null +++ b/server/middlewares/error.ts | |||
@@ -0,0 +1,39 @@ | |||
1 | import * as express from 'express' | ||
2 | import { ProblemDocument, ProblemDocumentExtension } from 'http-problem-details' | ||
3 | import { HttpStatusCode } from '@shared/core-utils' | ||
4 | |||
5 | function apiFailMiddleware (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
6 | res.fail = options => { | ||
7 | const { status = HttpStatusCode.BAD_REQUEST_400, message, title, type, data, instance } = options | ||
8 | |||
9 | const extension = new ProblemDocumentExtension({ | ||
10 | ...data, | ||
11 | |||
12 | docs: res.locals.docUrl, | ||
13 | code: type, | ||
14 | |||
15 | // For <= 3.2 compatibility | ||
16 | error: message | ||
17 | }) | ||
18 | |||
19 | res.status(status) | ||
20 | res.setHeader('Content-Type', 'application/problem+json') | ||
21 | res.json(new ProblemDocument({ | ||
22 | status, | ||
23 | title, | ||
24 | instance, | ||
25 | |||
26 | detail: message, | ||
27 | |||
28 | type: type | ||
29 | ? `https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/${type}` | ||
30 | : undefined | ||
31 | }, extension)) | ||
32 | } | ||
33 | |||
34 | if (next) next() | ||
35 | } | ||
36 | |||
37 | export { | ||
38 | apiFailMiddleware | ||
39 | } | ||
diff --git a/server/middlewares/index.ts b/server/middlewares/index.ts index 3e280e16f..413653dac 100644 --- a/server/middlewares/index.ts +++ b/server/middlewares/index.ts | |||
@@ -7,4 +7,6 @@ export * from './servers' | |||
7 | export * from './sort' | 7 | export * from './sort' |
8 | export * from './user-right' | 8 | export * from './user-right' |
9 | export * from './dnt' | 9 | export * from './dnt' |
10 | export * from './error' | ||
11 | export * from './doc' | ||
10 | export * from './csp' | 12 | export * from './csp' |
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 64e09234e..b7a9bcbe3 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -73,7 +73,6 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([ | |||
73 | .custom(isIdValid).withMessage('Should have correct video channel id'), | 73 | .custom(isIdValid).withMessage('Should have correct video channel id'), |
74 | 74 | ||
75 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 75 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
76 | res.docs = "https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadLegacy" | ||
77 | logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files }) | 76 | logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files }) |
78 | 77 | ||
79 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | 78 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) |
@@ -108,7 +107,6 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([ | |||
108 | */ | 107 | */ |
109 | const videosAddResumableValidator = [ | 108 | const videosAddResumableValidator = [ |
110 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 109 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
111 | res.docs = "https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumable" | ||
112 | const user = res.locals.oauth.token.User | 110 | const user = res.locals.oauth.token.User |
113 | 111 | ||
114 | const body: express.CustomUploadXFile<express.UploadXFileMetadata> = req.body | 112 | const body: express.CustomUploadXFile<express.UploadXFileMetadata> = req.body |
@@ -170,7 +168,6 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([ | |||
170 | .withMessage('Should specify the file mimetype'), | 168 | .withMessage('Should specify the file mimetype'), |
171 | 169 | ||
172 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 170 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
173 | res.docs = "https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumableInit" | ||
174 | const videoFileMetadata = { | 171 | const videoFileMetadata = { |
175 | mimetype: req.headers['x-upload-content-type'] as string, | 172 | mimetype: req.headers['x-upload-content-type'] as string, |
176 | size: +req.headers['x-upload-content-length'], | 173 | size: +req.headers['x-upload-content-length'], |
@@ -214,7 +211,6 @@ const videosUpdateValidator = getCommonVideoEditAttributes().concat([ | |||
214 | .custom(isIdValid).withMessage('Should have correct video channel id'), | 211 | .custom(isIdValid).withMessage('Should have correct video channel id'), |
215 | 212 | ||
216 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 213 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
217 | res.docs = 'https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo' | ||
218 | logger.debug('Checking videosUpdate parameters', { parameters: req.body }) | 214 | logger.debug('Checking videosUpdate parameters', { parameters: req.body }) |
219 | 215 | ||
220 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | 216 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) |
@@ -268,7 +264,6 @@ const videosCustomGetValidator = ( | |||
268 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 264 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
269 | 265 | ||
270 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 266 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
271 | res.docs = 'https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo' | ||
272 | logger.debug('Checking videosGet parameters', { parameters: req.params }) | 267 | logger.debug('Checking videosGet parameters', { parameters: req.params }) |
273 | 268 | ||
274 | if (areValidationErrors(req, res)) return | 269 | if (areValidationErrors(req, res)) return |
@@ -334,7 +329,6 @@ const videosRemoveValidator = [ | |||
334 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 329 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
335 | 330 | ||
336 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 331 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
337 | res.docs = "https://docs.joinpeertube.org/api-rest-reference.html#operation/delVideo" | ||
338 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) | 332 | logger.debug('Checking videosRemove parameters', { parameters: req.params }) |
339 | 333 | ||
340 | if (areValidationErrors(req, res)) return | 334 | if (areValidationErrors(req, res)) return |
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index c970c4a15..a6eecb13a 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts | |||
@@ -4,6 +4,8 @@ import 'mocha' | |||
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
6 | import { join } from 'path' | 6 | import { join } from 'path' |
7 | import { randomInt } from '@shared/core-utils' | ||
8 | import { PeerTubeProblemDocument } from '@shared/models' | ||
7 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' | 9 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' |
8 | import { | 10 | import { |
9 | checkUploadVideoParam, | 11 | checkUploadVideoParam, |
@@ -30,7 +32,6 @@ import { | |||
30 | checkBadStartPagination | 32 | checkBadStartPagination |
31 | } from '../../../../shared/extra-utils/requests/check-api-params' | 33 | } from '../../../../shared/extra-utils/requests/check-api-params' |
32 | import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' | 34 | import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' |
33 | import { randomInt } from '@shared/core-utils' | ||
34 | 35 | ||
35 | const expect = chai.expect | 36 | const expect = chai.expect |
36 | 37 | ||
@@ -411,6 +412,31 @@ describe('Test videos API validator', function () { | |||
411 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) | 412 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
412 | }) | 413 | }) |
413 | 414 | ||
415 | it('Should report the appropriate error', async function () { | ||
416 | const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) }) | ||
417 | const attaches = baseCorrectAttaches | ||
418 | |||
419 | const attributes = { ...fields, ...attaches } | ||
420 | const res = await checkUploadVideoParam(server.url, server.accessToken, attributes, HttpStatusCode.BAD_REQUEST_400, mode) | ||
421 | |||
422 | const error = res.body as PeerTubeProblemDocument | ||
423 | |||
424 | if (mode === 'legacy') { | ||
425 | expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadLegacy') | ||
426 | } else { | ||
427 | expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumableInit') | ||
428 | } | ||
429 | |||
430 | expect(error.type).to.equal('about:blank') | ||
431 | expect(error.title).to.equal('Bad Request') | ||
432 | |||
433 | expect(error.detail).to.equal('Incorrect request parameters: language') | ||
434 | expect(error.error).to.equal('Incorrect request parameters: language') | ||
435 | |||
436 | expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400) | ||
437 | expect(error['invalid-params'].language).to.exist | ||
438 | }) | ||
439 | |||
414 | it('Should succeed with the correct parameters', async function () { | 440 | it('Should succeed with the correct parameters', async function () { |
415 | this.timeout(10000) | 441 | this.timeout(10000) |
416 | 442 | ||
@@ -645,6 +671,24 @@ describe('Test videos API validator', function () { | |||
645 | 671 | ||
646 | it('Should fail with a video of another server') | 672 | it('Should fail with a video of another server') |
647 | 673 | ||
674 | it('Shoud report the appropriate error', async function () { | ||
675 | const fields = immutableAssign(baseCorrectParams, { licence: 125 }) | ||
676 | |||
677 | const res = await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) | ||
678 | const error = res.body as PeerTubeProblemDocument | ||
679 | |||
680 | expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo') | ||
681 | |||
682 | expect(error.type).to.equal('about:blank') | ||
683 | expect(error.title).to.equal('Bad Request') | ||
684 | |||
685 | expect(error.detail).to.equal('Incorrect request parameters: licence') | ||
686 | expect(error.error).to.equal('Incorrect request parameters: licence') | ||
687 | |||
688 | expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400) | ||
689 | expect(error['invalid-params'].licence).to.exist | ||
690 | }) | ||
691 | |||
648 | it('Should succeed with the correct parameters', async function () { | 692 | it('Should succeed with the correct parameters', async function () { |
649 | const fields = baseCorrectParams | 693 | const fields = baseCorrectParams |
650 | 694 | ||
@@ -678,6 +722,22 @@ describe('Test videos API validator', function () { | |||
678 | await getVideo(server.url, '4da6fde3-88f7-4d16-b119-108df5630b06', HttpStatusCode.NOT_FOUND_404) | 722 | await getVideo(server.url, '4da6fde3-88f7-4d16-b119-108df5630b06', HttpStatusCode.NOT_FOUND_404) |
679 | }) | 723 | }) |
680 | 724 | ||
725 | it('Shoud report the appropriate error', async function () { | ||
726 | const res = await getVideo(server.url, 'hi', HttpStatusCode.BAD_REQUEST_400) | ||
727 | const error = res.body as PeerTubeProblemDocument | ||
728 | |||
729 | expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo') | ||
730 | |||
731 | expect(error.type).to.equal('about:blank') | ||
732 | expect(error.title).to.equal('Bad Request') | ||
733 | |||
734 | expect(error.detail).to.equal('Incorrect request parameters: id') | ||
735 | expect(error.error).to.equal('Incorrect request parameters: id') | ||
736 | |||
737 | expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400) | ||
738 | expect(error['invalid-params'].id).to.exist | ||
739 | }) | ||
740 | |||
681 | it('Should succeed with the correct parameters', async function () { | 741 | it('Should succeed with the correct parameters', async function () { |
682 | await getVideo(server.url, videoId) | 742 | await getVideo(server.url, videoId) |
683 | }) | 743 | }) |
@@ -755,6 +815,22 @@ describe('Test videos API validator', function () { | |||
755 | 815 | ||
756 | it('Should fail with a video of another server') | 816 | it('Should fail with a video of another server') |
757 | 817 | ||
818 | it('Shoud report the appropriate error', async function () { | ||
819 | const res = await removeVideo(server.url, server.accessToken, 'hello', HttpStatusCode.BAD_REQUEST_400) | ||
820 | const error = res.body as PeerTubeProblemDocument | ||
821 | |||
822 | expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/delVideo') | ||
823 | |||
824 | expect(error.type).to.equal('about:blank') | ||
825 | expect(error.title).to.equal('Bad Request') | ||
826 | |||
827 | expect(error.detail).to.equal('Incorrect request parameters: id') | ||
828 | expect(error.error).to.equal('Incorrect request parameters: id') | ||
829 | |||
830 | expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400) | ||
831 | expect(error['invalid-params'].id).to.exist | ||
832 | }) | ||
833 | |||
758 | it('Should succeed with the correct parameters', async function () { | 834 | it('Should succeed with the correct parameters', async function () { |
759 | await removeVideo(server.url, server.accessToken, videoId) | 835 | await removeVideo(server.url, server.accessToken, videoId) |
760 | }) | 836 | }) |
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts index 8a91fbba3..3f2f71f46 100644 --- a/server/tests/api/server/follow-constraints.ts +++ b/server/tests/api/server/follow-constraints.ts | |||
@@ -18,6 +18,7 @@ import { unfollow } from '../../../../shared/extra-utils/server/follows' | |||
18 | import { userLogin } from '../../../../shared/extra-utils/users/login' | 18 | import { userLogin } from '../../../../shared/extra-utils/users/login' |
19 | import { createUser } from '../../../../shared/extra-utils/users/users' | 19 | import { createUser } from '../../../../shared/extra-utils/users/users' |
20 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' | 20 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' |
21 | import { PeerTubeProblemDocument, ServerErrorCode } from '@shared/models' | ||
21 | 22 | ||
22 | const expect = chai.expect | 23 | const expect = chai.expect |
23 | 24 | ||
@@ -153,7 +154,20 @@ describe('Test follow constraints', function () { | |||
153 | }) | 154 | }) |
154 | 155 | ||
155 | it('Should not get the remote video', async function () { | 156 | it('Should not get the remote video', async function () { |
156 | await getVideo(servers[0].url, video2UUID, HttpStatusCode.FORBIDDEN_403) | 157 | const res = await getVideo(servers[0].url, video2UUID, HttpStatusCode.FORBIDDEN_403) |
158 | |||
159 | const error = res.body as PeerTubeProblemDocument | ||
160 | |||
161 | const doc = 'https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/does_not_respect_follow_constraints' | ||
162 | expect(error.type).to.equal(doc) | ||
163 | expect(error.code).to.equal(ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS) | ||
164 | |||
165 | expect(error.detail).to.equal('Cannot get this video regarding follow constraints') | ||
166 | expect(error.error).to.equal(error.detail) | ||
167 | |||
168 | expect(error.status).to.equal(HttpStatusCode.FORBIDDEN_403) | ||
169 | |||
170 | expect(error.originUrl).to.contains(servers[1].url) | ||
157 | }) | 171 | }) |
158 | 172 | ||
159 | it('Should list local account videos', async function () { | 173 | it('Should list local account videos', async function () { |
diff --git a/server/typings/express/index.d.ts b/server/typings/express/index.d.ts index f58436ce1..cbbf40a78 100644 --- a/server/typings/express/index.d.ts +++ b/server/typings/express/index.d.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | |||
1 | import { RegisterServerAuthExternalOptions } from '@server/types' | 2 | import { RegisterServerAuthExternalOptions } from '@server/types' |
2 | import { | 3 | import { |
3 | MAbuseMessage, | 4 | MAbuseMessage, |
@@ -20,9 +21,8 @@ import { MVideoImportDefault } from '@server/types/models/video/video-import' | |||
20 | import { MVideoPlaylistElement, MVideoPlaylistElementVideoUrlPlaylistPrivacy } from '@server/types/models/video/video-playlist-element' | 21 | import { MVideoPlaylistElement, MVideoPlaylistElementVideoUrlPlaylistPrivacy } from '@server/types/models/video/video-playlist-element' |
21 | import { MAccountVideoRateAccountVideo } from '@server/types/models/video/video-rate' | 22 | import { MAccountVideoRateAccountVideo } from '@server/types/models/video/video-rate' |
22 | import { HttpMethod } from '@shared/core-utils/miscs/http-methods' | 23 | import { HttpMethod } from '@shared/core-utils/miscs/http-methods' |
23 | import { VideoCreate } from '@shared/models' | 24 | import { PeerTubeProblemDocumentData, ServerErrorCode, VideoCreate } from '@shared/models' |
24 | import { File as UploadXFile, Metadata } from '@uploadx/core' | 25 | import { File as UploadXFile, Metadata } from '@uploadx/core' |
25 | import { ProblemDocumentOptions } from 'http-problem-details/dist/ProblemDocument' | ||
26 | import { RegisteredPlugin } from '../../lib/plugins/plugin-manager' | 26 | import { RegisteredPlugin } from '../../lib/plugins/plugin-manager' |
27 | import { | 27 | import { |
28 | MAccountDefault, | 28 | MAccountDefault, |
@@ -41,6 +41,7 @@ import { | |||
41 | MVideoThumbnail, | 41 | MVideoThumbnail, |
42 | MVideoWithRights | 42 | MVideoWithRights |
43 | } from '../../types/models' | 43 | } from '../../types/models' |
44 | |||
44 | declare module 'express' { | 45 | declare module 'express' { |
45 | export interface Request { | 46 | export interface Request { |
46 | query: any | 47 | query: any |
@@ -86,14 +87,20 @@ declare module 'express' { | |||
86 | 87 | ||
87 | // Extends Response with added functions and potential variables passed by middlewares | 88 | // Extends Response with added functions and potential variables passed by middlewares |
88 | interface Response { | 89 | interface Response { |
89 | docs?: string | ||
90 | fail: (options: { | 90 | fail: (options: { |
91 | data?: Record<string, Object> | ||
92 | docs?: string | ||
93 | message: string | 91 | message: string |
94 | } & ProblemDocumentOptions) => void | 92 | |
93 | title?: string | ||
94 | status?: number | ||
95 | type?: ServerErrorCode | ||
96 | instance?: string | ||
97 | |||
98 | data?: PeerTubeProblemDocumentData | ||
99 | }) => void | ||
95 | 100 | ||
96 | locals: { | 101 | locals: { |
102 | docUrl?: string | ||
103 | |||
97 | videoAll?: MVideoFullLight | 104 | videoAll?: MVideoFullLight |
98 | onlyImmutableVideo?: MVideoImmutable | 105 | onlyImmutableVideo?: MVideoImmutable |
99 | onlyVideo?: MVideoThumbnail | 106 | onlyVideo?: MVideoThumbnail |
diff --git a/shared/models/server/index.ts b/shared/models/server/index.ts index b5163954a..06bf5c599 100644 --- a/shared/models/server/index.ts +++ b/shared/models/server/index.ts | |||
@@ -6,6 +6,7 @@ export * from './debug.model' | |||
6 | export * from './emailer.model' | 6 | export * from './emailer.model' |
7 | export * from './job.model' | 7 | export * from './job.model' |
8 | export * from './log-level.type' | 8 | export * from './log-level.type' |
9 | export * from './peertube-problem-document.model' | ||
9 | export * from './server-config.model' | 10 | export * from './server-config.model' |
10 | export * from './server-debug.model' | 11 | export * from './server-debug.model' |
11 | export * from './server-error-code.enum' | 12 | export * from './server-error-code.enum' |
diff --git a/shared/models/server/peertube-problem-document.model.ts b/shared/models/server/peertube-problem-document.model.ts new file mode 100644 index 000000000..5e1c320f3 --- /dev/null +++ b/shared/models/server/peertube-problem-document.model.ts | |||
@@ -0,0 +1,32 @@ | |||
1 | import { HttpStatusCode } from '@shared/core-utils' | ||
2 | import { OAuth2ErrorCode, ServerErrorCode } from './server-error-code.enum' | ||
3 | |||
4 | export interface PeerTubeProblemDocumentData { | ||
5 | 'invalid-params'?: Record<string, Object> | ||
6 | |||
7 | originUrl?: string | ||
8 | |||
9 | keyId?: string | ||
10 | |||
11 | targetUrl?: string | ||
12 | |||
13 | actorUrl?: string | ||
14 | |||
15 | // Feeds | ||
16 | format?: string | ||
17 | url?: string | ||
18 | } | ||
19 | |||
20 | export interface PeerTubeProblemDocument extends PeerTubeProblemDocumentData { | ||
21 | type: string | ||
22 | title: string | ||
23 | |||
24 | detail: string | ||
25 | // Compat PeerTube <= 3.2 | ||
26 | error: string | ||
27 | |||
28 | status: HttpStatusCode | ||
29 | |||
30 | docs?: string | ||
31 | code?: ServerErrorCode | OAuth2ErrorCode | ||
32 | } | ||
diff --git a/shared/models/server/server-error-code.enum.ts b/shared/models/server/server-error-code.enum.ts index 93b9ce20d..43996e7aa 100644 --- a/shared/models/server/server-error-code.enum.ts +++ b/shared/models/server/server-error-code.enum.ts | |||
@@ -48,5 +48,13 @@ export const enum OAuth2ErrorCode { | |||
48 | * | 48 | * |
49 | * @see https://github.com/oauthjs/node-oauth2-server/blob/master/lib/errors/invalid-client-error.js | 49 | * @see https://github.com/oauthjs/node-oauth2-server/blob/master/lib/errors/invalid-client-error.js |
50 | */ | 50 | */ |
51 | INVALID_CLIENT = 'invalid_client' | 51 | INVALID_CLIENT = 'invalid_client', |
52 | |||
53 | |||
54 | /** | ||
55 | * The access token provided is expired, revoked, malformed, or invalid for other reasons | ||
56 | * | ||
57 | * @see https://github.com/oauthjs/node-oauth2-server/blob/master/lib/errors/invalid-token-error.js | ||
58 | */ | ||
59 | INVALID_TOKEN = 'invalid_token', | ||
52 | } | 60 | } |