refactor error code values for URI compatibility

This commit is contained in:
Rigel Kent 2021-06-02 14:28:30 +02:00 committed by Chocobozzz
parent 3866ea02d4
commit 81628e5069
4 changed files with 93 additions and 23 deletions

View File

@ -252,7 +252,7 @@ async function checkVideoFollowConstraints (req: express.Request, res: express.R
return res.fail({ return res.fail({
status: HttpStatusCode.FORBIDDEN_403, status: HttpStatusCode.FORBIDDEN_403,
message: 'Cannot get this video regarding follow constraints.', message: 'Cannot get this video regarding follow constraints',
type: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS, type: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS,
data: { data: {
originUrl: video.url originUrl: video.url
@ -285,11 +285,11 @@ const videosCustomGetValidator = (
const user = res.locals.oauth ? res.locals.oauth.token.User : null const user = res.locals.oauth ? res.locals.oauth.token.User : null
// Only the owner or a user that have blacklist rights can see the video // Only the owner or a user that have blocklist rights can see the video
if (!user || !user.canGetVideo(video)) { if (!user || !user.canGetVideo(video)) {
return res.fail({ return res.fail({
status: HttpStatusCode.FORBIDDEN_403, status: HttpStatusCode.FORBIDDEN_403,
message: 'Cannot get this private/internal or blacklisted video.' message: 'Cannot get this private/internal or blocklisted video'
}) })
} }

View File

@ -3,7 +3,7 @@
import 'mocha' import 'mocha'
import * as chai from 'chai' import * as chai from 'chai'
import { AbuseState, AbuseUpdate, MyUser, User, UserRole, Video, VideoPlaylistType } from '@shared/models' import { AbuseState, AbuseUpdate, MyUser, User, UserRole, Video, VideoPlaylistType } from '@shared/models'
import { CustomConfig } from '@shared/models/server' import { CustomConfig, OAuth2ErrorCode } from '@shared/models/server'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import { import {
addVideoCommentThread, addVideoCommentThread,
@ -93,20 +93,20 @@ describe('Test users', function () {
const client = { id: 'client', secret: server.client.secret } const client = { id: 'client', secret: server.client.secret }
const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400) const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400)
expect(res.body.code).to.equal('invalid_client') expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_CLIENT)
expect(res.body.error).to.contain('client is invalid') expect(res.body.error).to.contain('client is invalid')
expect(res.body.type.startsWith('https://')).to.be.true expect(res.body.type.startsWith('https://')).to.be.true
expect(res.body.type).to.contain('invalid_client') expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_CLIENT)
}) })
it('Should not login with an invalid client secret', async function () { it('Should not login with an invalid client secret', async function () {
const client = { id: server.client.id, secret: 'coucou' } const client = { id: server.client.id, secret: 'coucou' }
const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400) const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400)
expect(res.body.code).to.equal('invalid_client') expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_CLIENT)
expect(res.body.error).to.contain('client is invalid') expect(res.body.error).to.contain('client is invalid')
expect(res.body.type.startsWith('https://')).to.be.true expect(res.body.type.startsWith('https://')).to.be.true
expect(res.body.type).to.contain('invalid_client') expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_CLIENT)
}) })
}) })
@ -116,20 +116,20 @@ describe('Test users', function () {
const user = { username: 'captain crochet', password: server.user.password } const user = { username: 'captain crochet', password: server.user.password }
const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400) const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400)
expect(res.body.code).to.equal('invalid_grant') expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_GRANT)
expect(res.body.error).to.contain('credentials are invalid') expect(res.body.error).to.contain('credentials are invalid')
expect(res.body.type.startsWith('https://')).to.be.true expect(res.body.type.startsWith('https://')).to.be.true
expect(res.body.type).to.contain('invalid_grant') expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_GRANT)
}) })
it('Should not login with an invalid password', async function () { it('Should not login with an invalid password', async function () {
const user = { username: server.user.username, password: 'mew_three' } const user = { username: server.user.username, password: 'mew_three' }
const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400) const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400)
expect(res.body.code).to.equal('invalid_grant') expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_GRANT)
expect(res.body.error).to.contain('credentials are invalid') expect(res.body.error).to.contain('credentials are invalid')
expect(res.body.type.startsWith('https://')).to.be.true expect(res.body.type.startsWith('https://')).to.be.true
expect(res.body.type).to.contain('invalid_grant') expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_GRANT)
}) })
it('Should not be able to upload a video', async function () { it('Should not be able to upload a video', async function () {

View File

@ -1,6 +1,52 @@
export const enum ServerErrorCode { export const enum ServerErrorCode {
DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS = 'DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS', /**
MAX_INSTANCE_LIVES_LIMIT_REACHED = 'MAX_INSTANCE_LIVES_LIMIT_REACHED', * Error yielded upon trying to access a video that is not federated, nor can
MAX_USER_LIVES_LIMIT_REACHED = 'MAX_USER_LIVES_LIMIT_REACHED', * be. This may be due to: remote videos on instances that are not followed by
INCORRECT_FILES_IN_TORRENT = 'INCORRECT_FILES_IN_TORRENT' * yours, and with your instance disallowing unknown instances being accessed.
*/
DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS = 'does_not_respect_follow_constraints',
/**
* Pretty self-explanatory: the set maximum number of simultaneous lives was
* reached, and this error is typically there to inform the user trying to
* broadcast one.
*/
MAX_INSTANCE_LIVES_LIMIT_REACHED = 'max_instance_lives_limit_reached',
/**
* Pretty self-explanatory: the set maximum number of simultaneous lives FOR
* THIS USER was reached, and this error is typically there to inform the user
* trying to broadcast one.
*/
MAX_USER_LIVES_LIMIT_REACHED = 'max_user_lives_limit_reached',
/**
* A torrent should have at most one correct video file. Any more and we will
* not be able to choose automatically.
*/
INCORRECT_FILES_IN_TORRENT = 'incorrect_files_in_torrent'
}
/**
* oauthjs/oauth2-server error codes
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
**/
export const enum OAuth2ErrorCode {
/**
* The provided authorization grant (e.g., authorization code, resource owner
* credentials) or refresh token is invalid, expired, revoked, does not match
* the redirection URI used in the authorization request, or was issued to
* another client.
*
* @see https://github.com/oauthjs/node-oauth2-server/blob/master/lib/errors/invalid-grant-error.js
*/
INVALID_GRANT = 'invalid_grant',
/**
* Client authentication failed (e.g., unknown client, no client authentication
* included, or unsupported authentication method).
*
* @see https://github.com/oauthjs/node-oauth2-server/blob/master/lib/errors/invalid-client-error.js
*/
INVALID_CLIENT = 'invalid_client'
} }

View File

@ -53,14 +53,30 @@ info:
} }
``` ```
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), 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),
but it is still optional. but it is still optional. Types are used to disambiguate errors that bear the same status code
and are non-obvious:
```
HTTP 1.1 403 Forbidden
Content-Type: application/problem+json; charset=utf-8
{
"detail": "Cannot get this video regarding follow constraints",
"docs": "https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo",
"status": 403,
"title": "Forbidden",
"type": "https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/does_not_respect_follow_constraints"
}
```
Here a 403 error could otherwise mean that the video is private or blocklisted.
### Validation errors ### Validation errors
Each parameter is evaluated on its own against a set of rules before the route validator Each parameter is evaluated on its own against a set of rules before the route validator
proceeds with potential testing involving parameter combinations. Errors coming from validation proceeds with potential testing involving parameter combinations. Errors coming from validation
errors appear earlier and benefit from a more detailed error type: errors appear earlier and benefit from a more detailed error description:
``` ```
HTTP 1.1 400 Bad Request HTTP 1.1 400 Bad Request
@ -89,6 +105,12 @@ info:
`invalid-params.<field>.value` reports the value that didn't pass validation whose `invalid-params.<field>.msg` `invalid-params.<field>.value` reports the value that didn't pass validation whose `invalid-params.<field>.msg`
is about. is about.
### Deprecated error fields
Some fields could be included with previous versions. They are still included but their use is deprecated:
- `error`: superseded by `detail`
- `code`: superseded by `type` (which is now an URI)
# Rate limits # Rate limits
We are rate-limiting all endpoints of PeerTube's API. Custom values can be set by administrators: We are rate-limiting all endpoints of PeerTube's API. Custom values can be set by administrators:
@ -932,6 +954,12 @@ paths:
type: integer type: integer
minimum: 0 minimum: 0
example: 1209600 example: 1209600
'400':
x-summary: client or credentials are invalid
description: |
Disambiguate via `type`:
- `invalid_client` for an unmatched `client_id`
- `invalid_grant` for unmatched credentials
x-codeSamples: x-codeSamples:
- lang: Shell - lang: Shell
source: | source: |
@ -1812,8 +1840,6 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/VideoUploadResponse' $ref: '#/components/schemas/VideoUploadResponse'
'400':
description: invalid file field, schedule date or parameter
'403': '403':
description: video didn't pass upload filter description: video didn't pass upload filter
'408': '408':
@ -1918,8 +1944,6 @@ paths:
schema: schema:
type: number type: number
example: 0 example: 0
'400':
description: invalid file field, schedule date or parameter
'413': '413':
description: video file too large, due to quota, absolute max file size or concurrent partial upload limit description: video file too large, due to quota, absolute max file size or concurrent partial upload limit
'415': '415':