diff --git a/CHANGELOG.md b/CHANGELOG.md index fe4720b1e5..667c729366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,6 +123,7 @@ ___ - Added centralized feature deprecation with standardized warning logs (Manuel Trezza) [#7303](https://github.com/parse-community/parse-server/pull/7303) - Use Node.js 15.13.0 in CI (Olle Jonsson) [#7312](https://github.com/parse-community/parse-server/pull/7312) - Fix file upload issue for S3 compatible storage (Linode, DigitalOcean) by avoiding empty tags property when creating a file (Ali Oguzhan Yildiz) [#7300](https://github.com/parse-community/parse-server/pull/7300) +- Use jwks-rsa 2.x (Olle Jonsson) [#7305](https://github.com/parse-community/parse-server/pull/7305) ___ ## 4.5.0 [Full Changelog](https://github.com/parse-community/parse-server/compare/4.4.0...4.5.0) diff --git a/package-lock.json b/package-lock.json index 17a8584283..d1e039ff1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1581,6 +1581,11 @@ } } }, + "@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==" + }, "@parse/fs-files-adapter": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@parse/fs-files-adapter/-/fs-files-adapter-1.2.0.tgz", @@ -1806,11 +1811,6 @@ "defer-to-connect": "^2.0.0" } }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" - }, "@types/accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", @@ -2919,14 +2919,6 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, - "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "requires": { - "follow-redirects": "^1.10.0" - } - }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -7343,6 +7335,14 @@ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" }, + "jose": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.4.tgz", + "integrity": "sha512-EArN9f6aq1LT/fIGGsfghOnNXn4noD+3dG5lL/ljY3LcRjw1u9w+4ahu/4ahsN6N0kRLyyW6zqdoYk7LNx3+YQ==", + "requires": { + "@panva/asn1.js": "^1.0.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7541,68 +7541,29 @@ } }, "jwks-rsa": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.12.3.tgz", - "integrity": "sha512-cFipFDeYYaO9FhhYJcZWX/IyZgc0+g316rcHnDpT2dNRNIE/lMOmWKKqp09TkJoYlNFzrEVODsR4GgXJMgWhnA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.0.2.tgz", + "integrity": "sha512-oRnlZvmP21LxqEgEFiPycLn3jyw/QuynyaERe7GMxR4TlTg7BRGBgEyEN+rRN4xGHMekXur1RY/MSt8UJBiSgA==", "requires": { "@types/express-jwt": "0.0.42", - "axios": "^0.21.1", "debug": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "jsonwebtoken": "^8.5.1", + "jose": "^2.0.2", "limiter": "^1.1.5", - "lru-memoizer": "^2.1.2", - "ms": "^2.1.2", - "proxy-from-env": "^1.1.0" + "lru-memoizer": "^2.1.2" }, "dependencies": { - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } - }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "requires": { "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" } }, "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, diff --git a/package.json b/package.json index acd5df25d5..771813d9c5 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "graphql-upload": "11.0.0", "intersect": "1.0.1", "jsonwebtoken": "8.5.1", - "jwks-rsa": "1.12.3", + "jwks-rsa": "2.0.2", "ldapjs": "2.2.4", "lodash": "4.17.21", "lru-cache": "5.1.1", @@ -125,7 +125,7 @@ "postinstall": "node -p 'require(\"./postinstall.js\")()'" }, "engines": { - "node": ">= 8" + "node": ">= 10" }, "bin": { "parse-server": "bin/parse-server" diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 9c6cfc6351..1a29527da4 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -1327,7 +1327,7 @@ describe('oauth2 auth adapter', () => { describe('apple signin auth adapter', () => { const apple = require('../lib/Adapters/Auth/apple'); const jwt = require('jsonwebtoken'); - const util = require('util'); + const jwksClient = require('jwks-rsa'); it('(using client id as string) should throw error with missing id_token', async () => { try { @@ -1389,7 +1389,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); const result = await apple.validateAuthData( { id: 'the_user_id', token: 'the_token' }, @@ -1405,7 +1405,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); try { await apple.validateAuthData( @@ -1442,7 +1442,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await apple.validateAuthData( @@ -1464,7 +1464,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await apple.validateAuthData( @@ -1486,7 +1486,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await apple.validateAuthData( @@ -1506,7 +1506,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -1534,7 +1534,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -1563,7 +1563,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -1635,7 +1635,7 @@ describe('apple signin auth adapter', () => { const fakeGetSigningKeyAsyncFunction = () => { return { kid: '123', rsaPublicKey: 'the_rsa_public_key' }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -1760,7 +1760,7 @@ describe('microsoft graph auth adapter', () => { describe('facebook limited auth adapter', () => { const facebook = require('../lib/Adapters/Auth/facebook'); const jwt = require('jsonwebtoken'); - const util = require('util'); + const jwksClient = require('jwks-rsa'); // TODO: figure out a way to run this test alongside facebook classic tests xit('(using client id as string) should throw error with missing id_token', async () => { @@ -1831,7 +1831,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); const result = await facebook.validateAuthData( { id: 'the_user_id', token: 'the_token' }, @@ -1852,7 +1852,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); try { await facebook.validateAuthData( @@ -1894,7 +1894,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await facebook.validateAuthData( @@ -1921,7 +1921,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await facebook.validateAuthData( @@ -1948,7 +1948,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); const result = await facebook.validateAuthData( @@ -1973,7 +1973,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -2006,7 +2006,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -2040,7 +2040,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { @@ -2126,7 +2126,7 @@ describe('facebook limited auth adapter', () => { rsaPublicKey: 'the_rsa_public_key', }; }; - spyOn(util, 'promisify').and.callFake(() => fakeGetSigningKeyAsyncFunction); + spyOn(jwksClient, 'getSigningKey').and.callFake(() => fakeGetSigningKeyAsyncFunction); spyOn(jwt, 'verify').and.callFake(() => fakeClaim); try { diff --git a/src/Adapters/Auth/apple.js b/src/Adapters/Auth/apple.js index 18989a4529..5914a2a3c4 100644 --- a/src/Adapters/Auth/apple.js +++ b/src/Adapters/Auth/apple.js @@ -3,7 +3,6 @@ const Parse = require('parse/node').Parse; const jwksClient = require('jwks-rsa'); -const util = require('util'); const jwt = require('jsonwebtoken'); const TOKEN_ISSUER = 'https://appleid.apple.com'; @@ -16,11 +15,9 @@ const getAppleKeyByKeyId = async (keyId, cacheMaxEntries, cacheMaxAge) => { cacheMaxAge, }); - const asyncGetSigningKeyFunction = util.promisify(client.getSigningKey); - let key; try { - key = await asyncGetSigningKeyFunction(keyId); + key = await client.getSigningKey(keyId); } catch (error) { throw new Parse.Error( Parse.Error.OBJECT_NOT_FOUND, diff --git a/src/Adapters/Auth/facebook.js b/src/Adapters/Auth/facebook.js index 95fba0b3e7..c2fb69102a 100644 --- a/src/Adapters/Auth/facebook.js +++ b/src/Adapters/Auth/facebook.js @@ -2,7 +2,6 @@ const Parse = require('parse/node').Parse; const crypto = require('crypto'); const jwksClient = require('jwks-rsa'); -const util = require('util'); const jwt = require('jsonwebtoken'); const httpsRequest = require('./httpsRequest'); @@ -58,11 +57,9 @@ const getFacebookKeyByKeyId = async (keyId, cacheMaxEntries, cacheMaxAge) => { cacheMaxAge, }); - const asyncGetSigningKeyFunction = util.promisify(client.getSigningKey); - let key; try { - key = await asyncGetSigningKeyFunction(keyId); + key = await client.getSigningKey(keyId); } catch (error) { throw new Parse.Error( Parse.Error.OBJECT_NOT_FOUND,