diff --git a/.gitignore b/.gitignore index 279cbd3..1efba0b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,7 @@ # folders -node_modules/ packages/ -# ide specific -.idea -.vscode + # config files productionSettings.json @@ -135,4 +132,3 @@ SemikolonPlus* # meteor package specific .meteor/local .meteor/meteorite -.npm diff --git a/.versions b/.versions index 85b1308..07a1e40 100644 --- a/.versions +++ b/.versions @@ -1,70 +1,70 @@ -accounts-base@2.2.3 -accounts-password@2.3.1 +accounts-base@2.2.10 +accounts-password@2.4.0 allow-deny@1.1.1 -babel-compiler@7.9.0 +babel-compiler@7.10.5 babel-runtime@1.5.1 base64@1.0.12 binary-heap@1.0.11 -boilerplate-generator@1.7.1 +boilerplate-generator@1.7.2 caching-compiler@1.2.2 -callback-hook@1.4.0 -check@1.3.1 +callback-hook@1.5.1 +check@1.3.2 coffeescript@1.0.17 dburles:mongo-collection-instances@0.1.3 -ddp@1.4.0 -ddp-client@2.5.0 +ddp@1.4.1 +ddp-client@2.6.1 ddp-common@1.4.0 -ddp-rate-limiter@1.1.0 -ddp-server@2.5.0 -diff-sequence@1.1.1 -dynamic-import@0.7.2 -ecmascript@0.16.2 -ecmascript-runtime@0.8.0 +ddp-rate-limiter@1.2.1 +ddp-server@2.7.0 +diff-sequence@1.1.2 +dynamic-import@0.7.3 +ecmascript@0.16.8 +ecmascript-runtime@0.8.1 ecmascript-runtime-client@0.12.1 ecmascript-runtime-server@0.11.0 -ejson@1.1.2 -email@2.2.1 -fetch@0.1.1 -geojson-utils@1.0.10 +ejson@1.1.3 +email@2.2.5 +fetch@0.1.4 +geojson-utils@1.0.11 http@1.4.4 id-map@1.1.1 inter-process-messaging@0.1.1 jkuester:http@2.1.0 -leaonline:oauth2-server@4.2.1 +leaonline:oauth2-server@5.0.0 lmieulet:meteor-coverage@3.2.0 lmieulet:meteor-legacy-coverage@0.1.0 lmieulet:meteor-packages-coverage@0.1.0 -local-test:leaonline:oauth2-server@4.2.1 +local-test:leaonline:oauth2-server@5.0.0 localstorage@1.2.0 -logging@1.3.1 -meteor@1.10.0 +logging@1.3.3 +meteor@1.11.5 meteortesting:browser-tests@1.3.5 meteortesting:mocha@2.0.3 meteortesting:mocha-core@8.0.1 -minimongo@1.8.0 -modern-browsers@0.1.8 -modules@0.18.0 -modules-runtime@0.13.0 -mongo@1.15.0 +minimongo@1.9.3 +modern-browsers@0.1.10 +modules@0.20.0 +modules-runtime@0.13.1 +mongo@1.16.8 mongo-decimal@0.1.3 mongo-dev-server@1.1.0 mongo-id@1.0.8 -npm-mongo@4.3.1 +npm-mongo@4.17.2 ordered-dict@1.1.0 practicalmeteor:chai@1.9.2_3 -promise@0.12.0 -random@1.2.0 -rate-limit@1.0.9 -react-fast-refresh@0.2.3 -reactive-var@1.0.11 +promise@0.12.2 +random@1.2.1 +rate-limit@1.1.1 +react-fast-refresh@0.2.8 +reactive-var@1.0.12 reload@1.3.1 retry@1.1.0 routepolicy@1.1.1 -service-configuration@1.3.0 sha@1.0.9 -socket-stream-client@0.5.0 -tracker@1.2.0 -underscore@1.0.10 +socket-stream-client@0.5.2 +tracker@1.3.3 +typescript@4.9.5 +underscore@1.6.0 url@1.3.2 -webapp@1.13.1 -webapp-hashing@1.1.0 +webapp@1.13.8 +webapp-hashing@1.1.1 diff --git a/lib/oauth.js b/lib/oauth.js index 2eb65a4..39d5bfc 100644 --- a/lib/oauth.js +++ b/lib/oauth.js @@ -63,7 +63,10 @@ export class OAuth2Server { */ constructor ({ serverOptions = {}, model, routes, debug } = {}) { check(serverOptions, OptionsSchema.serverOptions) - + if (debug) { + console.debug('[OAuth2Server]: create new instance') + console.debug('[OAuth2Server]: serveroptions', serverOptions) + } this.instanceId = Random.id() this.config = { serverOptions: Object.assign({}, OAuth2ServerDefaults.serverOptions, serverOptions), @@ -120,9 +123,8 @@ export class OAuth2Server { * @param secret * @returns {} */ - registerClient ({ title, homepage, description, privacyLink, redirectUris, grants, clientId, secret }) { - const self = this - return Promise.await(self.model.createClient({ + async registerClient ({ title, homepage, description, privacyLink, redirectUris, grants, clientId, secret }) { + return this.model.createClient({ title, homepage, description, @@ -131,45 +133,44 @@ export class OAuth2Server { grants, clientId, secret - })) + }) } authorizeHandler (options) { const self = this - return function (req, res, next) { + return async function (req, res, next) { const request = new Request(req) const response = new Response(res) - return self.oauth.authorize(request, response, options) - .then(function (code) { - res.locals.oauth = { code: code } - next() - }) - .catch(function (err) { - // handle error condition - res.writeHead(500) - res.end(err) - }) + + try { + const code = await self.oauth.authorize(request, response, options) + res.locals.oauth = { code: code } + next() + } catch (err) { + res.writeHead(500) + res.end(err) + } } } authenticateHandler (options) { const self = this - return function (req, res, next) { + return async function (req, res, next) { const request = new Request(req) const response = new Response(res) - return self.oauth.authenticate(request, response, options) - .then(function (token) { - req.data = Object.assign({}, req.data, token) - next() - }) - .catch(function (err) { - return errorHandler(res, { - status: err.status, - error: err.name, - description: err.message, - debug: self.debug - }) + + try { + const token = await self.oauth.authenticate(request, response, options) + req.data = Object.assign({}, req.data, token) + next() + } catch (err) { + return errorHandler(res, { + status: err.status, + error: err.name, + description: err.message, + debug: self.debug }) + } } } @@ -214,10 +215,11 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa return true } - const getValidatedClient = (req, res) => { + const getValidatedClient = async (req, res) => { const clientId = req.method.toLowerCase() === 'get' ? req.query.client_id : req.body.client_id const secret = req.method.toLowerCase() === 'get' ? req.query.client_secret : req.body.client_secret - const client = Promise.await(self.model.getClient(clientId, secret)) + const client = await self.model.getClient(clientId, secret) + if (!client) { // unauthorized_client - The client is not authorized to request an authorization code using this method. return errorHandler(res, { @@ -228,6 +230,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa debug: self.debug }) } + return client } @@ -279,7 +282,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa // If there is something wrong with the syntax of the request, such as the redirect_uri or client_id is invalid, // then it’s important not to redirect the user and instead you should show the error message directly. // This is to avoid letting your authorization server be used as an open redirector. - route('get', authorizeUrl, function (req, res, next) { + route('get', authorizeUrl, async function (req, res, next) { if (!validateParams(req.query, requiredAuthorizeGetParams, self.debug)) { return errorHandler(res, { status: 400, @@ -293,7 +296,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa const validResponseType = validateResponseType(req, res) if (!validResponseType) return - const client = getValidatedClient(req, res) + const client = await getValidatedClient(req, res) if (!client) return const redirectUri = getValidatedRedirectUri(req, res, client) @@ -305,7 +308,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa // STEP 2: ADD USER TO THE REQUEST // validate all inputs again, since all inputs // could have been manipulated within form - route('post', authorizeUrl, function (req, res, next) { + route('post', authorizeUrl, async function (req, res, next) { if (!validateParams(req.body, requiredAuthorizePostParams, self.debug)) { return errorHandler(res, { error: 'invalid_request', @@ -316,7 +319,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa }) } - const client = getValidatedClient(req, res) + const client = await getValidatedClient(req, res) if (!client) return const validRedirectUri = getValidatedRedirectUri(req, res, client) @@ -366,7 +369,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa // - on allow, assign the client_id to the user's authorized clients // - on deny, ...? // - construct the redirect query and redirect to the redirect_uri - route('post', authorizeUrl, function (req, res /*, next */) { + route('post', authorizeUrl, async function (req, res /*, next */) { const request = new Request(req) const response = new Response(res) const authorizeOptions = { @@ -377,37 +380,36 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa } } - return self.oauth.authorize(request, response, authorizeOptions) - .then(bind(function (code) { - const query = new URLSearchParams({ - code: code.authorizationCode, - user: req.user.id, - state: req.body.state - }) - - const finalRedirectUri = `${req.body.redirect_uri}?${query}` + try { + const code = await self.oauth.authorize(request, response, authorizeOptions) + const query = new URLSearchParams({ + code: code.authorizationCode, + user: req.user.id, + state: req.body.state + }) - res.statusCode = 302 - res.setHeader('Location', finalRedirectUri) - res.end() - })) - .catch(function (err) { - errorHandler(res, { - originalError: err, - error: err.name, - description: err.message, - status: err.statusCode, - state: req.body.state, - debug: self.debug - }) + const finalRedirectUri = `${req.body.redirect_uri}?${query}` + + res.statusCode = 302 + res.setHeader('Location', finalRedirectUri) + res.end() + } catch (err) { + errorHandler(res, { + originalError: err, + error: err.name, + description: err.message, + status: err.statusCode, + state: req.body.state, + debug: self.debug }) + } }) // STEP 4: GENERATE ACCESS TOKEN RESPONSE // - validate params // - validate authorization code // - issue accessToken and refreshToken - route('post', accessTokenUrl, function (req, res, next) { + route('post', accessTokenUrl, async function (req, res, /* next */) { if (!validateParams(req.body, requiredAccessTokenPostParams, self.debug)) { return errorHandler(res, { status: 400, @@ -421,30 +423,29 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa const request = new Request(req) const response = new Response(res) - return self.oauth.token(request, response) - .then(function (token) { - res.writeHead(200, { - 'Content-Type': 'application/json', - 'Cache-Control': 'no-store', - Pragma: 'no-cache' - }) - const body = JSON.stringify({ - access_token: token.accessToken, - token_type: 'bearer', - expires_in: token.accessTokenExpiresAt, - refresh_token: token.refreshToken - }) - res.end(body) + try { + const token = await self.oauth.token(request, response) + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-store', + Pragma: 'no-cache' }) - .catch(function (err) { - return errorHandler(res, { - error: 'unauthorized_client', - description: err.message, - state: req.body.state, - debug: self.debug, - status: err.statusCode - }) + const body = JSON.stringify({ + access_token: token.accessToken, + token_type: 'bearer', + expires_in: token.accessTokenExpiresAt, + refresh_token: token.refreshToken + }) + res.end(body) + } catch (err) { + return errorHandler(res, { + error: 'unauthorized_client', + description: err.message, + state: req.body.state, + debug: self.debug, + status: err.statusCode }) + } }) route('use', fallbackUrl, function (req, res, next) { diff --git a/package.js b/package.js index ee56d44..1a84597 100644 --- a/package.js +++ b/package.js @@ -1,7 +1,7 @@ /* eslint-env meteor */ Package.describe({ name: 'leaonline:oauth2-server', - version: '4.2.1', + version: '5.0.0', summary: 'Node OAuth2 Server (v4) with Meteor bindings', git: 'https://github.com/leaonline/oauth2-server.git' }) @@ -13,7 +13,7 @@ Package.onUse(function (api) { }) Npm.depends({ - '@node-oauth/oauth2-server': '4.2.0', + '@node-oauth/oauth2-server': '5.0.0', 'body-parser': '1.20.0' }) diff --git a/test-proxy/.coverage/defaults.js.html b/test-proxy/.coverage/defaults.js.html index e37d924..231c373 100644 --- a/test-proxy/.coverage/defaults.js.html +++ b/test-proxy/.coverage/defaults.js.html @@ -3,12 +3,12 @@