From f369eb7ea95ed9f88efbf605950861b0d261151d Mon Sep 17 00:00:00 2001 From: HappyZombies Date: Tue, 30 May 2023 13:53:15 -0400 Subject: [PATCH 1/4] javascript: refactored project to ES6 standards --- index.js | 263 +++++++++++++++++++++------------------------- package-lock.json | 10 +- package.json | 5 +- 3 files changed, 126 insertions(+), 152 deletions(-) diff --git a/index.js b/index.js index dbd7dd5..bba2e66 100644 --- a/index.js +++ b/index.js @@ -1,173 +1,144 @@ -'use strict'; - /** * Module dependencies. */ +const NodeOAuthServer = require('@node-oauth/oauth2-server'); +const { Request, Response } = require('@node-oauth/oauth2-server'); +const InvalidArgumentError = require('@node-oauth/oauth2-server/lib/errors/invalid-argument-error'); +const UnauthorizedRequestError = require('@node-oauth/oauth2-server/lib/errors/unauthorized-request-error'); -var InvalidArgumentError = require('@node-oauth/oauth2-server/lib/errors/invalid-argument-error'); -var NodeOAuthServer = require('@node-oauth/oauth2-server'); -var Promise = require('bluebird'); -var Request = require('@node-oauth/oauth2-server').Request; -var Response = require('@node-oauth/oauth2-server').Response; -var UnauthorizedRequestError = require('@node-oauth/oauth2-server/lib/errors/unauthorized-request-error'); +class ExpressOAuthServer { + constructor(options) { + this.options = options || {}; -/** - * Constructor. - */ + if (!this.options.model) { + throw new InvalidArgumentError('Missing parameter: `model`'); + } + this.useErrorHandler = this.options.useErrorHandler === true; + this.continueMiddleware = this.options.continueMiddleware === true; -function ExpressOAuthServer(options) { - options = options || {}; + delete this.options.useErrorHandler; + delete this.options.continueMiddleware; - if (!options.model) { - throw new InvalidArgumentError('Missing parameter: `model`'); + this.server = new NodeOAuthServer(this.options); } - this.useErrorHandler = options.useErrorHandler ? true : false; - delete options.useErrorHandler; - - this.continueMiddleware = options.continueMiddleware ? true : false; - delete options.continueMiddleware; - - this.server = new NodeOAuthServer(options); -} - -/** - * Authentication Middleware. - * - * Returns a middleware that will validate a token. - * - * (See: https://tools.ietf.org/html/rfc6749#section-7) - */ + /** + * Authentication Middleware. + * + * Returns a middleware that will validate a token. + * + * (See: https://tools.ietf.org/html/rfc6749#section-7) + */ + authenticate(options) { + return async (req, res, next) => { + const request = new Request(req); + const response = new Response(res); + let token; + try { + token = await this.server.authenticate(request, response, options); + } catch (err) { + this._handleError(res, null, err, next); + return; + } + res.locals.oauth = { token }; + return next(); + } + } -ExpressOAuthServer.prototype.authenticate = function(options) { - var that = this; - - return function(req, res, next) { - var request = new Request(req); - var response = new Response(res); - return Promise.bind(that) - .then(function() { - return this.server.authenticate(request, response, options); - }) - .tap(function(token) { - res.locals.oauth = { token: token }; + /** + * Authorization Middleware. + * + * Returns a middleware that will authorize a client to request tokens. + * + * (See: https://tools.ietf.org/html/rfc6749#section-3.1) + */ + authorize(options) { + return async (req, res, next) => { + const request = new Request(req); + const response = new Response(res); + let code; + try { + code = await this.server.authorize(request, response, options); + } catch (err) { + this._handleError(res, response, err, next); + return; + } + res.locals.oauth = { code }; + if (this.continueMiddleware) { next(); - }) - .catch(function(e) { - return handleError.call(this, e, req, res, null, next); - }); - }; -}; - -/** - * Authorization Middleware. - * - * Returns a middleware that will authorize a client to request tokens. - * - * (See: https://tools.ietf.org/html/rfc6749#section-3.1) - */ - -ExpressOAuthServer.prototype.authorize = function(options) { - var that = this; - - return function(req, res, next) { - var request = new Request(req); - var response = new Response(res); - - return Promise.bind(that) - .then(function() { - return this.server.authorize(request, response, options); - }) - .tap(function(code) { - res.locals.oauth = { code: code }; - if (this.continueMiddleware) { - next(); - } - }) - .then(function() { - return handleResponse.call(this, req, res, response); - }) - .catch(function(e) { - return handleError.call(this, e, req, res, response, next); - }); - }; -}; - -/** - * Grant Middleware. - * - * Returns middleware that will grant tokens to valid requests. - * - * (See: https://tools.ietf.org/html/rfc6749#section-3.2) - */ + } + return this._handleResponse(req, res, response); + } + } -ExpressOAuthServer.prototype.token = function(options) { - var that = this; - - return function(req, res, next) { - var request = new Request(req); - var response = new Response(res); - - return Promise.bind(that) - .then(function() { - return this.server.token(request, response, options); - }) - .tap(function(token) { - res.locals.oauth = { token: token }; - if (this.continueMiddleware) { - next(); - } - }) - .then(function() { - return handleResponse.call(this, req, res, response); - }) - .catch(function(e) { - return handleError.call(this, e, req, res, response, next); - }); - }; -}; -/** - * Handle response. - */ -var handleResponse = function(req, res, response) { - - if (response.status === 302) { - var location = response.headers.location; - delete response.headers.location; - res.set(response.headers); - res.redirect(location); - } else { - res.set(response.headers); - res.status(response.status).send(response.body); + /** + * Authorization Middleware. + * + * Returns a middleware that will authorize a client to request tokens. + * + * (See: https://tools.ietf.org/html/rfc6749#section-3.1) + */ + token(options) { + return async (req, res, next) => { + const request = new Request(req); + const response = new Response(res); + let token; + try { + token = await this.server.token(request, response, options); + } catch (err) { + this._handleError(res, response, err, next); + return; + } + res.locals.oauth = { token }; + if (this.continueMiddleware) { + next(); + } + return this._handleResponse(req, res, response); + } } -}; -/** - * Handle error. - */ + /** + * Grant Middleware. + * + * Returns middleware that will grant tokens to valid requests. + * + * (See: https://tools.ietf.org/html/rfc6749#section-3.2) + */ + _handleResponse(req, res, oauthResponse) { + if (oauthResponse.status === 302) { + const location = oauthResponse.headers.location; + delete oauthResponse.headers.location; + res.set(oauthResponse.headers); + res.redirect(location); + return; + } + res.set(oauthResponse.headers); + res.status(oauthResponse.status).send(oauthResponse.body); + } -var handleError = function(e, req, res, response, next) { + /** + * Handles errors depending on the options of `this.useErrorHandler`. + * Either calls `next()` with the error (so the application can handle it), or returns immediately a response with the error. + */ + _handleError(res, oauthResponse, error, next) { + if (this.useErrorHandler) { + return next(error); + } - if (this.useErrorHandler === true) { - next(e); - } else { - if (response) { - res.set(response.headers); + if (oauthResponse) { + res.set(oauthResponse.headers); } - res.status(e.code); + res.status(error.code); - if (e instanceof UnauthorizedRequestError) { + if (error instanceof UnauthorizedRequestError) { return res.send(); } - res.send({ error: e.name, error_description: e.message }); + return res.send({ error: error.name, error_description: error.message }); } -}; +} -/** - * Export constructor. - */ module.exports = ExpressOAuthServer; diff --git a/package-lock.json b/package-lock.json index d414095..dfb972f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@node-oauth/express-oauth-server", - "version": "3.0.0", + "version": "3.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -785,7 +785,8 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "basic-auth": { "version": "2.0.1", @@ -838,6 +839,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1029,7 +1031,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "content-disposition": { "version": "0.5.4", @@ -2203,6 +2206,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } diff --git a/package.json b/package.json index 13ba732..b85e63c 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "3.0.1", "description": "OAuth provider for express", "main": "index.js", - "typings": "index.d.ts", + "types": "index.d.ts", "scripts": { "lint": "npx eslint .", "lint:fix": "npx eslint . --fix", @@ -32,7 +32,6 @@ "license": "MIT", "dependencies": { "@node-oauth/oauth2-server": "^4.3.0", - "bluebird": "^3.7.2", "express": "^4.18.2" }, "devDependencies": { @@ -45,6 +44,6 @@ "supertest": "^6.3.3" }, "engines": { - "node": ">=0.11" + "node": ">=14.0.0" } } From 5478ec79d2d5b6ca819a76025d1c63e2f2628d1e Mon Sep 17 00:00:00 2001 From: Dylan Marsh Date: Wed, 21 Jun 2023 10:15:54 -0400 Subject: [PATCH 2/4] Fixed possible invalid status code range error If `error.code` is undefined this can result in a RangeError where the HTTP status code is invalid. This will cause the application to crash swallowing the actual error. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index bba2e66..1cfc604 100644 --- a/index.js +++ b/index.js @@ -130,7 +130,7 @@ class ExpressOAuthServer { res.set(oauthResponse.headers); } - res.status(error.code); + res.status(error.code || 500); if (error instanceof UnauthorizedRequestError) { return res.send(); From a61bd4014cc4bcce5c624b8ccbc50fcc0330dff8 Mon Sep 17 00:00:00 2001 From: Wilco Bakker Date: Tue, 21 Nov 2023 11:53:35 +0100 Subject: [PATCH 3/4] Fixed unit test. --- test/integration/index_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/index_test.js b/test/integration/index_test.js index 2cdd668..aa4c685 100644 --- a/test/integration/index_test.js +++ b/test/integration/index_test.js @@ -208,7 +208,7 @@ describe('ExpressOAuthServer', function() { app.use(oauth.authorize()); - request(app) + request(app.listen()) .post('/') .expect({ error: 'invalid_argument', error_description: 'Invalid argument: model does not implement `getClient()`' }) .end(done); From 8cb072fcd4ceff621d04e91ccd48c731d3efe121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=BCster?= Date: Tue, 21 Nov 2023 13:28:36 +0100 Subject: [PATCH 4/4] Update tests.yml --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 672342d..f1ed7d6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14, 16, 18] + node: [16, 18, 20] steps: - name: Checkout ${{ matrix.node }} uses: actions/checkout@v3