From e3ceaaff2941384ddcb2925c7d2f4c4274bf90ad Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Sun, 1 May 2022 02:01:40 +0200 Subject: [PATCH] fix --- spec/AuthenticationAdapters.spec.js | 67 ++++++++++++----------------- src/Adapters/Auth/gcenter.js | 32 +++++++++----- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 181ffa04a6..ca2d35363d 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -1665,11 +1665,7 @@ describe('Apple Game Center Auth adapter', () => { bundleId: 'cloud.xtralife.gamecenterauth', }; - try { - await gcenter.validateAuthData(authData); - } catch (e) { - fail(); - } + await gcenter.validateAuthData(authData); }); it('validateAuthData invalid signature id', async () => { @@ -1690,42 +1686,33 @@ describe('Apple Game Center Auth adapter', () => { } }); - it('validateAuthData invalid public key url', async () => { - const authData = { - id: 'G:1965586982', - publicKeyUrl: 'invalid.com', - timestamp: 1565257031287, - signature: '1234', - salt: 'DzqqrQ==', - bundleId: 'cloud.xtralife.gamecenterauth', - }; - - try { - await gcenter.validateAuthData(authData); - fail(); - } catch (e) { - expect(e.message).toBe('Apple Game Center - invalid publicKeyUrl: invalid.com'); - } - }); - it('validateAuthData invalid public key http url', async () => { - const authData = { - id: 'G:1965586982', - publicKeyUrl: 'http://static.gc.apple.com/public-key/gc-prod-4.cer', - timestamp: 1565257031287, - signature: '1234', - salt: 'DzqqrQ==', - bundleId: 'cloud.xtralife.gamecenterauth', - }; - - try { - await gcenter.validateAuthData(authData); - fail(); - } catch (e) { - expect(e.message).toBe( - 'Apple Game Center - invalid publicKeyUrl: http://static.gc.apple.com/public-key/gc-prod-4.cer' - ); - } + const publicKeyUrls = [ + 'example.com', + 'http://static.gc.apple.com/public-key/gc-prod-4.cer', + 'https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg', + 'https://example.com/ \\.apple.com/public_key.cer', + 'https://example.com/ &.apple.com/public_key.cer', + ]; + await Promise.all( + publicKeyUrls.map(publicKeyUrl => + expectAsync( + gcenter.validateAuthData({ + id: 'G:1965586982', + timestamp: 1565257031287, + publicKeyUrl, + signature: '1234', + salt: 'DzqqrQ==', + bundleId: 'com.example.com', + }) + ).toBeRejectedWith( + new Parse.Error( + Parse.Error.SCRIPT_FAILED, + `Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}` + ) + ) + ) + ); }); }); diff --git a/src/Adapters/Auth/gcenter.js b/src/Adapters/Auth/gcenter.js index 26ae6da1ad..5cd8e8affc 100644 --- a/src/Adapters/Auth/gcenter.js +++ b/src/Adapters/Auth/gcenter.js @@ -19,15 +19,8 @@ const cache = {}; // (publicKey -> cert) cache function verifyPublicKeyUrl(publicKeyUrl) { try { - const parsedUrl = new URL(publicKeyUrl); - if (parsedUrl.protocol !== 'https:') { - return false; - } - const hostnameParts = parsedUrl.hostname.split('.'); - const length = hostnameParts.length; - const domainParts = hostnameParts.slice(length - 2, length); - const domain = domainParts.join('.'); - return domain === 'apple.com'; + const regex = /^https:\/\/(?:[-_A-Za-z0-9]+\.){0,}apple\.com\/.*\.cer$/; + return regex.test(publicKeyUrl); } catch (error) { return false; } @@ -43,7 +36,7 @@ function convertX509CertToPEM(X509Cert) { return pemPreFix + certBody + pemPostFix; } -function getAppleCertificate(publicKeyUrl) { +async function getAppleCertificate(publicKeyUrl) { if (!verifyPublicKeyUrl(publicKeyUrl)) { throw new Parse.Error( Parse.Error.OBJECT_NOT_FOUND, @@ -53,6 +46,25 @@ function getAppleCertificate(publicKeyUrl) { if (cache[publicKeyUrl]) { return cache[publicKeyUrl]; } + const url = new URL(publicKeyUrl); + const headOptions = { + hostname: url.hostname, + path: url.pathname, + method: 'HEAD', + }; + const headers = await new Promise((resolve, reject) => + https.get(headOptions, res => resolve(res.headers)).on('error', reject) + ); + if ( + headers['content-type'] !== 'application/pkix-cert' || + headers['content-length'] == null || + headers['content-length'] > 10000 + ) { + throw new Parse.Error( + Parse.Error.OBJECT_NOT_FOUND, + `Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}` + ); + } return new Promise((resolve, reject) => { https .get(publicKeyUrl, res => {