From 7aa4d104afb75d2b92c6871710852ed01d5b8d5d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 13 Oct 2020 14:22:00 -0400 Subject: [PATCH 1/4] fix: testing openapi write tests --- public/openapi/write.yaml | 261 +------------------ public/openapi/write/users/uid.yaml | 60 +++++ public/openapi/write/users/uid/ban.yaml | 59 +++++ public/openapi/write/users/uid/follow.yaml | 46 ++++ public/openapi/write/users/uid/password.yaml | 39 +++ public/openapi/write/users/uid/tokens.yaml | 40 +++ 6 files changed, 255 insertions(+), 250 deletions(-) create mode 100644 public/openapi/write/users/uid.yaml create mode 100644 public/openapi/write/users/uid/ban.yaml create mode 100644 public/openapi/write/users/uid/follow.yaml create mode 100644 public/openapi/write/users/uid/password.yaml create mode 100644 public/openapi/write/users/uid/tokens.yaml diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index f084ea10b1..bb1c34cd98 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -21,262 +21,23 @@ info: license: name: GPL-3.0 servers: - - url: /api/v1 + - url: /write/v1 tags: - name: users description: 'Account related calls (create, modify, delete, etc.)' - name: categories description: Administrative calls to manage categories paths: - '/users/{uid}': - delete: - tags: - - users - summary: delete a single user account - parameters: - - in: path - name: uid - schema: - type: integer - required: true - description: uid of the user to delete - responses: - '200': - description: user account deleted - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - type: object - put: - tags: - - users - summary: update a user account - parameters: - - in: path - name: uid - schema: - type: integer - required: true - description: uid of the user to update - requestBody: - required: true - content: - application/json: - schema: - $ref: components/schemas/UserRequest.yaml#/UserRequest - responses: - '200': - description: user profile updated - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - $ref: components/schemas/UserObj.yaml#/UserObj - '401': - $ref: components/responses/401.yaml#/401 - '403': - $ref: components/responses/403.yaml#/403 - '426': - $ref: components/responses/426.yaml#/426 - '500': - $ref: components/responses/500.yaml#/500 - '/users/{uid}/password': - put: - tags: - - users - summary: change a user's password - parameters: - - in: path - name: uid - schema: - type: integer - required: true - description: uid of the user to update - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - currentPassword: - type: string - description: test - example: oldp455word - newPassword: - type: string - example: s3cre7password - required: - - newPassword - responses: - '200': - description: user profile updated - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - type: object - '/users/{uid}/follow': - post: - tags: - - users - summary: follow a user - parameters: - - in: path - name: uid - schema: - type: integer - required: true - description: uid of the user to follow - responses: - '200': - description: successfully followed user - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - type: object - delete: - tags: - - users - summary: unfollows a user - parameters: - - in: path - name: uid - schema: - type: integer - required: true - description: uid of the user to unfollow - responses: - '200': - description: successfully unfollowed user - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - type: object - '/users/{uid}/ban': - put: - tags: - - users - summary: ban a user - parameters: - - in: path - name: uid - schema: - type: integer - required: true - description: uid of the user to ban - requestBody: - content: - application/json: - schema: - type: object - properties: - until: - type: number - description: UNIX timestamp of the ban expiry - example: 1585775608076 - reason: - type: string - example: the reason for the ban - responses: - '200': - description: successfully banned user - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - type: object - delete: - tags: - - users - summary: unbans a user - parameters: - - in: path - name: uid - schema: - type: integer - required: true - description: uid of the user to unban - responses: - '200': - description: successfully unbanned user - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - type: object - '/users/{uid}/tokens': - post: - tags: - - users - summary: generate a user token - description: This route can only be used to generate tokens for the same user. In other words, you cannot use this route to generate a token for a different user than the one you are authenticated as. - responses: - '200': - description: successfully generated a user token - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - type: object - delete: - tags: - - users - summary: delete user token - parameters: - - in: path - name: token - schema: - type: string - required: true - description: a valid API token - responses: - '200': - description: successfully deleted user token - content: - application/json: - schema: - type: object - properties: - status: - $ref: components/schemas/Status.yaml#/Status - response: - type: object + /users/{uid}: + $ref: 'write/users/uid.yaml' + /users/{uid}/password: + $ref: 'write/users/uid/password.yaml' + /users/{uid}/follow: + $ref: 'write/users/uid/follow.yaml' + /users/{uid}/ban: + $ref: 'write/users/uid/ban.yaml' + /users/{uid}/tokens: + $ref: 'write/users/uid/tokens.yaml' /categories/: $ref: 'write/categories.yaml' /groups/: diff --git a/public/openapi/write/users/uid.yaml b/public/openapi/write/users/uid.yaml new file mode 100644 index 0000000000..48230dd245 --- /dev/null +++ b/public/openapi/write/users/uid.yaml @@ -0,0 +1,60 @@ +delete: + tags: + - users + summary: delete a single user account + parameters: + - in: path + name: uid + schema: + type: integer + required: true + description: uid of the user to delete + responses: + '200': + description: user account deleted + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../components/schemas/Status.yaml#/Status + response: + type: object +put: + tags: + - users + summary: update a user account + parameters: + - in: path + name: uid + schema: + type: integer + required: true + description: uid of the user to update + requestBody: + required: true + content: + application/json: + schema: + $ref: ../../components/schemas/UserRequest.yaml#/UserRequest + responses: + '200': + description: user profile updated + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../components/schemas/Status.yaml#/Status + response: + $ref: ../../components/schemas/UserObj.yaml#/UserObj + '401': + $ref: ../../components/responses/401.yaml#/401 + '403': + $ref: ../../components/responses/403.yaml#/403 + '426': + $ref: ../../components/responses/426.yaml#/426 + '500': + $ref: ../../components/responses/500.yaml#/500 \ No newline at end of file diff --git a/public/openapi/write/users/uid/ban.yaml b/public/openapi/write/users/uid/ban.yaml new file mode 100644 index 0000000000..82ae1d023b --- /dev/null +++ b/public/openapi/write/users/uid/ban.yaml @@ -0,0 +1,59 @@ +put: + tags: + - users + summary: ban a user + parameters: + - in: path + name: uid + schema: + type: integer + required: true + description: uid of the user to ban + requestBody: + content: + application/json: + schema: + type: object + properties: + until: + type: number + description: UNIX timestamp of the ban expiry + example: 1585775608076 + reason: + type: string + example: the reason for the ban + responses: + '200': + description: successfully banned user + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object +delete: + tags: + - users + summary: unbans a user + parameters: + - in: path + name: uid + schema: + type: integer + required: true + description: uid of the user to unban + responses: + '200': + description: successfully unbanned user + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object \ No newline at end of file diff --git a/public/openapi/write/users/uid/follow.yaml b/public/openapi/write/users/uid/follow.yaml new file mode 100644 index 0000000000..f275af46d7 --- /dev/null +++ b/public/openapi/write/users/uid/follow.yaml @@ -0,0 +1,46 @@ +post: + tags: + - users + summary: follow a user + parameters: + - in: path + name: uid + schema: + type: integer + required: true + description: uid of the user to follow + responses: + '200': + description: successfully followed user + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object +delete: + tags: + - users + summary: unfollows a user + parameters: + - in: path + name: uid + schema: + type: integer + required: true + description: uid of the user to unfollow + responses: + '200': + description: successfully unfollowed user + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object \ No newline at end of file diff --git a/public/openapi/write/users/uid/password.yaml b/public/openapi/write/users/uid/password.yaml new file mode 100644 index 0000000000..e127437420 --- /dev/null +++ b/public/openapi/write/users/uid/password.yaml @@ -0,0 +1,39 @@ +put: + tags: + - users + summary: change a user's password + parameters: + - in: path + name: uid + schema: + type: integer + required: true + description: uid of the user to update + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + currentPassword: + type: string + description: test + example: oldp455word + newPassword: + type: string + example: s3cre7password + required: + - newPassword + responses: + '200': + description: user profile updated + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object \ No newline at end of file diff --git a/public/openapi/write/users/uid/tokens.yaml b/public/openapi/write/users/uid/tokens.yaml new file mode 100644 index 0000000000..9400a17b18 --- /dev/null +++ b/public/openapi/write/users/uid/tokens.yaml @@ -0,0 +1,40 @@ +post: + tags: + - users + summary: generate a user token + description: This route can only be used to generate tokens for the same user. In other words, you cannot use this route to generate a token for a different user than the one you are authenticated as. + responses: + '200': + description: successfully generated a user token + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object +delete: + tags: + - users + summary: delete user token + parameters: + - in: path + name: token + schema: + type: string + required: true + description: a valid API token + responses: + '200': + description: successfully deleted user token + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object \ No newline at end of file From c68653d035a8e05323bcc6b91d1f02a06d0795e4 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 13 Oct 2020 14:26:25 -0400 Subject: [PATCH 2/4] fix: typo --- public/openapi/write.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index bb1c34cd98..07e06cf4c5 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -21,7 +21,7 @@ info: license: name: GPL-3.0 servers: - - url: /write/v1 + - url: /api/v1 tags: - name: users description: 'Account related calls (create, modify, delete, etc.)' From 0e0f1506d29d960da8bf3795cb78dcebdbb1549f Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 13 Oct 2020 15:06:14 -0400 Subject: [PATCH 3/4] fix: update server param to /api/v3 --- public/openapi/write.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index 07e06cf4c5..75cc5a2ad0 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -21,7 +21,7 @@ info: license: name: GPL-3.0 servers: - - url: /api/v1 + - url: /api/v3 tags: - name: users description: 'Account related calls (create, modify, delete, etc.)' From 1e07886f30b8b458c2dbe15e14bbd6b4df499d7f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 13 Oct 2020 16:58:44 -0400 Subject: [PATCH 4/4] feat: require csrf token if not using bearer token --- public/src/modules/api.js | 6 +++++- src/middleware/index.js | 1 + src/middleware/user.js | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/public/src/modules/api.js b/public/src/modules/api.js index 374c36b95c..26796c07df 100644 --- a/public/src/modules/api.js +++ b/public/src/modules/api.js @@ -5,7 +5,11 @@ define('api', () => { const baseUrl = config.relative_path + '/api/v3'; function call(options, onSuccess, onError) { - $.ajax(options) + $.ajax(Object.assign({ + headers: { + 'x-csrf-token': config.csrf_token, + }, + }, options)) .done((res) => { if (onSuccess) { onSuccess(res.response); diff --git a/src/middleware/index.js b/src/middleware/index.js index ee01b0b30c..98eb224e33 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -48,6 +48,7 @@ middleware.applyCSRF = function (req, res, next) { next(); } }; +middleware.applyCSRFasync = util.promisify(middleware.applyCSRF); middleware.ensureLoggedIn = ensureLoggedIn.ensureLoggedIn(nconf.get('relative_path') + '/login'); diff --git a/src/middleware/user.js b/src/middleware/user.js index 8babf6007f..5c8d9caa76 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -34,6 +34,10 @@ module.exports = function (middleware) { const loginAsync = util.promisify(req.login).bind(req); if (req.loggedIn) { + if (res.locals.isAPI) { + await middleware.applyCSRFasync(req, res); + } + return true; } else if (req.headers.hasOwnProperty('authorization')) { const user = await passportAuthenticateAsync(req, res);