aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/middlewares/validators/videos/videos.ts6
-rw-r--r--server/tests/api/users/users.ts18
-rw-r--r--shared/models/server/server-error-code.enum.ts54
-rw-r--r--support/doc/api/openapi.yaml38
4 files changed, 93 insertions, 23 deletions
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts
index fd0e543f1..64e09234e 100644
--- a/server/middlewares/validators/videos/videos.ts
+++ b/server/middlewares/validators/videos/videos.ts
@@ -252,7 +252,7 @@ async function checkVideoFollowConstraints (req: express.Request, res: express.R
252 252
253 return res.fail({ 253 return res.fail({
254 status: HttpStatusCode.FORBIDDEN_403, 254 status: HttpStatusCode.FORBIDDEN_403,
255 message: 'Cannot get this video regarding follow constraints.', 255 message: 'Cannot get this video regarding follow constraints',
256 type: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS, 256 type: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS,
257 data: { 257 data: {
258 originUrl: video.url 258 originUrl: video.url
@@ -285,11 +285,11 @@ const videosCustomGetValidator = (
285 285
286 const user = res.locals.oauth ? res.locals.oauth.token.User : null 286 const user = res.locals.oauth ? res.locals.oauth.token.User : null
287 287
288 // Only the owner or a user that have blacklist rights can see the video 288 // Only the owner or a user that have blocklist rights can see the video
289 if (!user || !user.canGetVideo(video)) { 289 if (!user || !user.canGetVideo(video)) {
290 return res.fail({ 290 return res.fail({
291 status: HttpStatusCode.FORBIDDEN_403, 291 status: HttpStatusCode.FORBIDDEN_403,
292 message: 'Cannot get this private/internal or blacklisted video.' 292 message: 'Cannot get this private/internal or blocklisted video'
293 }) 293 })
294 } 294 }
295 295
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index 464c11d34..87ba775f6 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -3,7 +3,7 @@
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { AbuseState, AbuseUpdate, MyUser, User, UserRole, Video, VideoPlaylistType } from '@shared/models' 5import { AbuseState, AbuseUpdate, MyUser, User, UserRole, Video, VideoPlaylistType } from '@shared/models'
6import { CustomConfig } from '@shared/models/server' 6import { CustomConfig, OAuth2ErrorCode } from '@shared/models/server'
7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
8import { 8import {
9 addVideoCommentThread, 9 addVideoCommentThread,
@@ -93,20 +93,20 @@ describe('Test users', function () {
93 const client = { id: 'client', secret: server.client.secret } 93 const client = { id: 'client', secret: server.client.secret }
94 const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400) 94 const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400)
95 95
96 expect(res.body.code).to.equal('invalid_client') 96 expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_CLIENT)
97 expect(res.body.error).to.contain('client is invalid') 97 expect(res.body.error).to.contain('client is invalid')
98 expect(res.body.type.startsWith('https://')).to.be.true 98 expect(res.body.type.startsWith('https://')).to.be.true
99 expect(res.body.type).to.contain('invalid_client') 99 expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_CLIENT)
100 }) 100 })
101 101
102 it('Should not login with an invalid client secret', async function () { 102 it('Should not login with an invalid client secret', async function () {
103 const client = { id: server.client.id, secret: 'coucou' } 103 const client = { id: server.client.id, secret: 'coucou' }
104 const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400) 104 const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400)
105 105
106 expect(res.body.code).to.equal('invalid_client') 106 expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_CLIENT)
107 expect(res.body.error).to.contain('client is invalid') 107 expect(res.body.error).to.contain('client is invalid')
108 expect(res.body.type.startsWith('https://')).to.be.true 108 expect(res.body.type.startsWith('https://')).to.be.true
109 expect(res.body.type).to.contain('invalid_client') 109 expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_CLIENT)
110 }) 110 })
111 }) 111 })
112 112
@@ -116,20 +116,20 @@ describe('Test users', function () {
116 const user = { username: 'captain crochet', password: server.user.password } 116 const user = { username: 'captain crochet', password: server.user.password }
117 const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400) 117 const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400)
118 118
119 expect(res.body.code).to.equal('invalid_grant') 119 expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_GRANT)
120 expect(res.body.error).to.contain('credentials are invalid') 120 expect(res.body.error).to.contain('credentials are invalid')
121 expect(res.body.type.startsWith('https://')).to.be.true 121 expect(res.body.type.startsWith('https://')).to.be.true
122 expect(res.body.type).to.contain('invalid_grant') 122 expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_GRANT)
123 }) 123 })
124 124
125 it('Should not login with an invalid password', async function () { 125 it('Should not login with an invalid password', async function () {
126 const user = { username: server.user.username, password: 'mew_three' } 126 const user = { username: server.user.username, password: 'mew_three' }
127 const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400) 127 const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400)
128 128
129 expect(res.body.code).to.equal('invalid_grant') 129 expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_GRANT)
130 expect(res.body.error).to.contain('credentials are invalid') 130 expect(res.body.error).to.contain('credentials are invalid')
131 expect(res.body.type.startsWith('https://')).to.be.true 131 expect(res.body.type.startsWith('https://')).to.be.true
132 expect(res.body.type).to.contain('invalid_grant') 132 expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_GRANT)
133 }) 133 })
134 134
135 it('Should not be able to upload a video', async function () { 135 it('Should not be able to upload a video', async function () {
diff --git a/shared/models/server/server-error-code.enum.ts b/shared/models/server/server-error-code.enum.ts
index f9fe47830..93b9ce20d 100644
--- a/shared/models/server/server-error-code.enum.ts
+++ b/shared/models/server/server-error-code.enum.ts
@@ -1,6 +1,52 @@
1export const enum ServerErrorCode { 1export const enum ServerErrorCode {
2 DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS = 'DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS', 2 /**
3 MAX_INSTANCE_LIVES_LIMIT_REACHED = 'MAX_INSTANCE_LIVES_LIMIT_REACHED', 3 * Error yielded upon trying to access a video that is not federated, nor can
4 MAX_USER_LIVES_LIMIT_REACHED = 'MAX_USER_LIVES_LIMIT_REACHED', 4 * be. This may be due to: remote videos on instances that are not followed by
5 INCORRECT_FILES_IN_TORRENT = 'INCORRECT_FILES_IN_TORRENT' 5 * yours, and with your instance disallowing unknown instances being accessed.
6 */
7 DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS = 'does_not_respect_follow_constraints',
8
9 /**
10 * Pretty self-explanatory: the set maximum number of simultaneous lives was
11 * reached, and this error is typically there to inform the user trying to
12 * broadcast one.
13 */
14 MAX_INSTANCE_LIVES_LIMIT_REACHED = 'max_instance_lives_limit_reached',
15
16 /**
17 * Pretty self-explanatory: the set maximum number of simultaneous lives FOR
18 * THIS USER was reached, and this error is typically there to inform the user
19 * trying to broadcast one.
20 */
21 MAX_USER_LIVES_LIMIT_REACHED = 'max_user_lives_limit_reached',
22
23 /**
24 * A torrent should have at most one correct video file. Any more and we will
25 * not be able to choose automatically.
26 */
27 INCORRECT_FILES_IN_TORRENT = 'incorrect_files_in_torrent'
28}
29
30/**
31 * oauthjs/oauth2-server error codes
32 * @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
33 **/
34export const enum OAuth2ErrorCode {
35 /**
36 * The provided authorization grant (e.g., authorization code, resource owner
37 * credentials) or refresh token is invalid, expired, revoked, does not match
38 * the redirection URI used in the authorization request, or was issued to
39 * another client.
40 *
41 * @see https://github.com/oauthjs/node-oauth2-server/blob/master/lib/errors/invalid-grant-error.js
42 */
43 INVALID_GRANT = 'invalid_grant',
44
45 /**
46 * Client authentication failed (e.g., unknown client, no client authentication
47 * included, or unsupported authentication method).
48 *
49 * @see https://github.com/oauthjs/node-oauth2-server/blob/master/lib/errors/invalid-client-error.js
50 */
51 INVALID_CLIENT = 'invalid_client'
6} 52}
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml
index 9f40d74c6..ae4855878 100644
--- a/support/doc/api/openapi.yaml
+++ b/support/doc/api/openapi.yaml
@@ -53,14 +53,30 @@ info:
53 } 53 }
54 ``` 54 ```
55 55
56 We provide error types for [a growing number of cases](https://github.com/Chocobozzz/PeerTube/blob/develop/shared/models/server/server-error-code.enum.ts), 56 We provide error `type` values for [a growing number of cases](https://github.com/Chocobozzz/PeerTube/blob/develop/shared/models/server/server-error-code.enum.ts),
57 but it is still optional. 57 but it is still optional. Types are used to disambiguate errors that bear the same status code
58 and are non-obvious:
59
60 ```
61 HTTP 1.1 403 Forbidden
62 Content-Type: application/problem+json; charset=utf-8
63
64 {
65 "detail": "Cannot get this video regarding follow constraints",
66 "docs": "https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo",
67 "status": 403,
68 "title": "Forbidden",
69 "type": "https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/does_not_respect_follow_constraints"
70 }
71 ```
72
73 Here a 403 error could otherwise mean that the video is private or blocklisted.
58 74
59 ### Validation errors 75 ### Validation errors
60 76
61 Each parameter is evaluated on its own against a set of rules before the route validator 77 Each parameter is evaluated on its own against a set of rules before the route validator
62 proceeds with potential testing involving parameter combinations. Errors coming from validation 78 proceeds with potential testing involving parameter combinations. Errors coming from validation
63 errors appear earlier and benefit from a more detailed error type: 79 errors appear earlier and benefit from a more detailed error description:
64 80
65 ``` 81 ```
66 HTTP 1.1 400 Bad Request 82 HTTP 1.1 400 Bad Request
@@ -89,6 +105,12 @@ info:
89 `invalid-params.<field>.value` reports the value that didn't pass validation whose `invalid-params.<field>.msg` 105 `invalid-params.<field>.value` reports the value that didn't pass validation whose `invalid-params.<field>.msg`
90 is about. 106 is about.
91 107
108 ### Deprecated error fields
109
110 Some fields could be included with previous versions. They are still included but their use is deprecated:
111 - `error`: superseded by `detail`
112 - `code`: superseded by `type` (which is now an URI)
113
92 # Rate limits 114 # Rate limits
93 115
94 We are rate-limiting all endpoints of PeerTube's API. Custom values can be set by administrators: 116 We are rate-limiting all endpoints of PeerTube's API. Custom values can be set by administrators:
@@ -932,6 +954,12 @@ paths:
932 type: integer 954 type: integer
933 minimum: 0 955 minimum: 0
934 example: 1209600 956 example: 1209600
957 '400':
958 x-summary: client or credentials are invalid
959 description: |
960 Disambiguate via `type`:
961 - `invalid_client` for an unmatched `client_id`
962 - `invalid_grant` for unmatched credentials
935 x-codeSamples: 963 x-codeSamples:
936 - lang: Shell 964 - lang: Shell
937 source: | 965 source: |
@@ -1812,8 +1840,6 @@ paths:
1812 application/json: 1840 application/json:
1813 schema: 1841 schema:
1814 $ref: '#/components/schemas/VideoUploadResponse' 1842 $ref: '#/components/schemas/VideoUploadResponse'
1815 '400':
1816 description: invalid file field, schedule date or parameter
1817 '403': 1843 '403':
1818 description: video didn't pass upload filter 1844 description: video didn't pass upload filter
1819 '408': 1845 '408':
@@ -1918,8 +1944,6 @@ paths:
1918 schema: 1944 schema:
1919 type: number 1945 type: number
1920 example: 0 1946 example: 0
1921 '400':
1922 description: invalid file field, schedule date or parameter
1923 '413': 1947 '413':
1924 description: video file too large, due to quota, absolute max file size or concurrent partial upload limit 1948 description: video file too large, due to quota, absolute max file size or concurrent partial upload limit
1925 '415': 1949 '415':