From 90e24b90f2c906d2d4316cad5f39890deffba1c5 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Tue, 12 Dec 2017 18:00:27 +0800 Subject: [PATCH 01/28] AuthAdapter added 1. add google Play Games Authentication Method(different from Google due to GPG is using a new ID method). 2. add Game Center Authentication Method. By refering to the URL that provided: https://developer.apple.com/documentation/gamekit/gklocalplayer/1515407-generateidentityverificationsign?language=objc --- src/Adapters/Auth/gcenter.js | 134 +++++++++++++++++++++++++++++++++++ src/Adapters/Auth/gpgames.js | 48 +++++++++++++ src/Adapters/Auth/index.js | 46 +++++++----- 3 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 src/Adapters/Auth/gcenter.js create mode 100644 src/Adapters/Auth/gpgames.js diff --git a/src/Adapters/Auth/gcenter.js b/src/Adapters/Auth/gcenter.js new file mode 100644 index 0000000000..0a1277f51c --- /dev/null +++ b/src/Adapters/Auth/gcenter.js @@ -0,0 +1,134 @@ +'use strict'; + +// Helper functions for accessing the google API. +var Parse = require('parse/node').Parse; +//var verifier = require('gamecenter-identity-verifier'); + +var _ = require('underscore'); +var crypto = require('crypto'); +var request = require('request'); +var url = require('url'); + +// Returns a promise that fulfills if this user id is valid. +function validateAuthData(authData) +{ + return new Promise(function (resolve, reject) + { + var identity = { + publicKeyUrl: authData.pKeyUrl, + timestamp: authData.timeStamp, + signature: authData.sig, + salt: authData.salt, + playerId: authData.id, + bundleId: authData.bid + }; + + return verify(identity, function (err, token) + { + if(err) + return reject('Failed to validate this access token with Game Center.'); + else + return resolve(); + }); + + }); +} + +// Returns a promise that fulfills if this app id is valid. +function validateAppId() { + return Promise.resolve(); +} + +function verifyPublicKeyUrl(publicKeyUrl) { + var parsedUrl = url.parse(publicKeyUrl); + if (parsedUrl.protocol !== 'https:') { + return false; + } + + var hostnameParts = parsedUrl.hostname.split('.'); + var domainParts = _.rest(hostnameParts, hostnameParts.length - 2); + var domain = domainParts.join('.'); + if (domain !== 'apple.com') { + return false; + } + + return true; +} + +function convertX509CertToPEM(X509Cert) { + var pemPreFix = '-----BEGIN CERTIFICATE-----\n'; + var pemPostFix = '-----END CERTIFICATE-----'; + + var base64 = X509Cert.toString('base64'); + var certBody = base64.match(new RegExp('.{0,64}', 'g')).join('\n'); + + return pemPreFix + certBody + pemPostFix; +} + +function getAppleCertificate(publicKeyUrl, callback) { + if (!verifyPublicKeyUrl(publicKeyUrl)) { + callback(new Error('Invalid publicKeyUrl'), null); + return; + } + + var options = { + uri: publicKeyUrl, + encoding: null + }; + request.get(options, function (error, response, body) { + if (!error && response.statusCode === 200) { + var cert = convertX509CertToPEM(body); + callback(null, cert); + } else { + callback(error, null); + } + }); +} + +/* jslint bitwise:true */ +function convertTimestampToBigEndian(timestamp) { + // The timestamp parameter in Big-Endian UInt-64 format + var buffer = new Buffer(8); + buffer.fill(0); + + var high = ~~(timestamp / 0xffffffff); // jshint ignore:line + var low = timestamp % (0xffffffff + 0x1); // jshint ignore:line + + buffer.writeUInt32BE(parseInt(high, 10), 0); + buffer.writeUInt32BE(parseInt(low, 10), 4); + + return buffer; +} +/* jslint bitwise:false */ + +function verifySignature(publicKey, idToken) { + var verifier = crypto.createVerify('sha256'); + verifier.update(idToken.playerId, 'utf8'); + verifier.update(idToken.bundleId, 'utf8'); + verifier.update(convertTimestampToBigEndian(idToken.timestamp)); + verifier.update(idToken.salt, 'base64'); + + if (!verifier.verify(publicKey, idToken.signature, 'base64')) { + throw new Error('Invalid Signature'); + } +} + +function verify(idToken, callback) { + getAppleCertificate(idToken.publicKeyUrl, function (err, publicKey) { + if (!err) { + try { + verifySignature(publicKey, idToken); + callback(null, idToken); + } catch (e) { + callback(e, null); + } + } else { + callback(err, null); + } + }); +}; + +module.exports = { + validateAppId: validateAppId, + validateAuthData: validateAuthData +}; diff --git a/src/Adapters/Auth/gpgames.js b/src/Adapters/Auth/gpgames.js new file mode 100644 index 0000000000..9dc35cd155 --- /dev/null +++ b/src/Adapters/Auth/gpgames.js @@ -0,0 +1,48 @@ +'use strict'; + +// Helper functions for accessing the google API. +var https = require('https'); +var Parse = require('parse/node').Parse; + +// Returns a promise that fulfills if this user id is valid. +function validateAuthData(authData) { + return request("players/" + id + "?access_token=" + token).then(response => { + if (response && (response.playerId == id)) + { + return; + } + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Google auth is invalid for this user.'); + }); +} + +// Returns a promise that fulfills if this app id is valid. +function validateAppId() { + return Promise.resolve(); +} + +// A promisey wrapper for api requests +function request(path) { + return new Promise(function (resolve, reject) { + https.get("https://www.googleapis.com/games/v1/" + path, function (res) { + var data = ''; + res.on('data', function (chunk) { + data += chunk; + }); + res.on('end', function () { + try { + data = JSON.parse(data); + } catch (e) { + return reject(e); + } + resolve(data); + }); + }).on('error', function () { + reject('Failed to validate this access token with Google.'); + }); + }); +} + +module.exports = { + validateAppId: validateAppId, + validateAuthData: validateAuthData +}; \ No newline at end of file diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index aa99f09cec..df197e02ce 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -1,10 +1,18 @@ -import loadAdapter from '../AdapterLoader'; +'use strict'; + +var _AdapterLoader = require('../AdapterLoader'); + +var _AdapterLoader2 = _interopRequireDefault(_AdapterLoader); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const facebook = require('./facebook'); const instagram = require("./instagram"); const linkedin = require("./linkedin"); const meetup = require("./meetup"); const google = require("./google"); +const gcenter = require("./gcenter"); +const gpgames = require("./gpgames"); const github = require("./github"); const twitter = require("./twitter"); const spotify = require("./spotify"); @@ -23,7 +31,7 @@ const anonymous = { validateAppId: () => { return Promise.resolve(); } -} +}; const providers = { facebook, @@ -31,6 +39,8 @@ const providers = { linkedin, meetup, google, + gcenter, + gpgames, github, twitter, spotify, @@ -42,17 +52,17 @@ const providers = { qq, wechat, weibo -} +}; function authDataValidator(adapter, appIds, options) { - return function(authData) { + return function (authData) { return adapter.validateAuthData(authData, options).then(() => { if (appIds) { return adapter.validateAppId(appIds, authData, options); } return Promise.resolve(); }); - } + }; } function loadAuthAdapter(provider, authOptions) { @@ -68,9 +78,9 @@ function loadAuthAdapter(provider, authOptions) { // Try the configuration methods if (providerOptions) { - const optionalAdapter = loadAdapter(providerOptions, undefined, providerOptions); + const optionalAdapter = (0, _AdapterLoader2.default)(providerOptions, undefined, providerOptions); if (optionalAdapter) { - ['validateAuthData', 'validateAppId'].forEach((key) => { + ['validateAuthData', 'validateAppId'].forEach(key => { if (optionalAdapter[key]) { adapter[key] = optionalAdapter[key]; } @@ -82,20 +92,24 @@ function loadAuthAdapter(provider, authOptions) { return; } - return {adapter, appIds, providerOptions}; + return { adapter, appIds, providerOptions }; } -module.exports = function(authOptions = {}, enableAnonymousUsers = true) { +module.exports = function (authOptions = {}, enableAnonymousUsers = true) { let _enableAnonymousUsers = enableAnonymousUsers; - const setEnableAnonymousUsers = function(enable) { + const setEnableAnonymousUsers = function (enable) { _enableAnonymousUsers = enable; - } + }; // To handle the test cases on configuration - const getValidatorForProvider = function(provider) { + const getValidatorForProvider = function (provider) { if (provider === 'anonymous' && !_enableAnonymousUsers) { return; } + + //check to make sure provider supported + if(providers[provider] === undefined) + return; const { adapter, @@ -104,12 +118,12 @@ module.exports = function(authOptions = {}, enableAnonymousUsers = true) { } = loadAuthAdapter(provider, authOptions); return authDataValidator(adapter, appIds, providerOptions); - } + }; return Object.freeze({ getValidatorForProvider, setEnableAnonymousUsers - }) -} + }); +}; -module.exports.loadAuthAdapter = loadAuthAdapter; +module.exports.loadAuthAdapter = loadAuthAdapter; \ No newline at end of file From 4fc7e2ca05256cf50d9ac9c66495f49b957627b4 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Tue, 12 Dec 2017 18:35:21 +0800 Subject: [PATCH 02/28] fix underscore module --- src/Adapters/Auth/gcenter.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Adapters/Auth/gcenter.js b/src/Adapters/Auth/gcenter.js index 0a1277f51c..f3d9e91b4d 100644 --- a/src/Adapters/Auth/gcenter.js +++ b/src/Adapters/Auth/gcenter.js @@ -2,9 +2,6 @@ // Helper functions for accessing the google API. var Parse = require('parse/node').Parse; -//var verifier = require('gamecenter-identity-verifier'); - -var _ = require('underscore'); var crypto = require('crypto'); var request = require('request'); var url = require('url'); @@ -46,8 +43,8 @@ function verifyPublicKeyUrl(publicKeyUrl) { } var hostnameParts = parsedUrl.hostname.split('.'); - var domainParts = _.rest(hostnameParts, hostnameParts.length - 2); - var domain = domainParts.join('.'); +// var domainParts = _.rest(hostnameParts, hostnameParts.length - 2); + var domain = hostnameParts[hostnameParts.length - 2] + "." + hostnameParts[hostnameParts.length - 1]; if (domain !== 'apple.com') { return false; } From 065f2a3a616292378e1ac7de8a475b40fc30b674 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Tue, 12 Dec 2017 18:49:45 +0800 Subject: [PATCH 03/28] remove the checking for provider --- src/Adapters/Auth/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index df197e02ce..6e8c9ad52d 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -107,10 +107,6 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) { return; } - //check to make sure provider supported - if(providers[provider] === undefined) - return; - const { adapter, appIds, From 617306760fe5c5d14b3268a1282cfaa8613cd85f Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Wed, 13 Dec 2017 10:00:55 +0800 Subject: [PATCH 04/28] checking to make sure the provider exists! --- src/Adapters/Auth/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 6e8c9ad52d..20314babaa 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -107,6 +107,10 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) { return; } + //check to make sure provider supported + if(providers[provider] == null) + return; + const { adapter, appIds, From f29099b6058befa1916556b1d5fa8aa239b1fe14 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Wed, 13 Dec 2017 11:17:36 +0800 Subject: [PATCH 05/28] change check provider method check using the funciton hasOwnProperty. --- src/Adapters/Auth/index.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 20314babaa..914cb2bb98 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -23,7 +23,6 @@ const vkontakte = require("./vkontakte"); const qq = require("./qq"); const wechat = require("./wechat"); const weibo = require("./weibo"); - const anonymous = { validateAuthData: () => { return Promise.resolve(); @@ -54,10 +53,14 @@ const providers = { weibo }; -function authDataValidator(adapter, appIds, options) { - return function (authData) { - return adapter.validateAuthData(authData, options).then(() => { - if (appIds) { +function authDataValidator(adapter, appIds, options) +{ + return function (authData) + { + return adapter.validateAuthData(authData, options).then(() => + { + if (appIds) + { return adapter.validateAppId(appIds, authData, options); } return Promise.resolve(); @@ -69,10 +72,9 @@ function loadAuthAdapter(provider, authOptions) { const defaultAdapter = providers[provider]; const adapter = Object.assign({}, defaultAdapter); const providerOptions = authOptions[provider]; - - if (!defaultAdapter && !providerOptions) { + + if (!defaultAdapter && !providerOptions) return; - } const appIds = providerOptions ? providerOptions.appIds : undefined; @@ -95,22 +97,24 @@ function loadAuthAdapter(provider, authOptions) { return { adapter, appIds, providerOptions }; } -module.exports = function (authOptions = {}, enableAnonymousUsers = true) { +module.exports = function (authOptions = {}, enableAnonymousUsers = true) +{ let _enableAnonymousUsers = enableAnonymousUsers; - const setEnableAnonymousUsers = function (enable) { + const setEnableAnonymousUsers = function (enable) + { _enableAnonymousUsers = enable; }; // To handle the test cases on configuration - const getValidatorForProvider = function (provider) { - - if (provider === 'anonymous' && !_enableAnonymousUsers) { + const getValidatorForProvider = function (provider) + { + if (provider === 'anonymous' && !_enableAnonymousUsers) + { return; } - //check to make sure provider supported - if(providers[provider] == null) + if(!providers.hasOwnProperty(provider)) return; - + const { adapter, appIds, From 4f9cf55087a696079bb8a89762a983fa54167a15 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Fri, 15 Dec 2017 11:24:38 +0800 Subject: [PATCH 06/28] Fix GPGames Error fix error for Google Play Games. --- src/Adapters/Auth/gpgames.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Adapters/Auth/gpgames.js b/src/Adapters/Auth/gpgames.js index 9dc35cd155..6f31fedf0b 100644 --- a/src/Adapters/Auth/gpgames.js +++ b/src/Adapters/Auth/gpgames.js @@ -6,8 +6,8 @@ var Parse = require('parse/node').Parse; // Returns a promise that fulfills if this user id is valid. function validateAuthData(authData) { - return request("players/" + id + "?access_token=" + token).then(response => { - if (response && (response.playerId == id)) + return request("players/" + authData.id + "?access_token=" + authData.access_token).then(response => { + if (response && (response.playerId == authData.id)) { return; } From 7de2a97edbc6a44c82dade5b5bd414e075febbe9 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Fri, 15 Dec 2017 18:24:42 +0800 Subject: [PATCH 07/28] Take Away checking for Provider Name Temporary enable this to allow PR Success --- src/Adapters/Auth/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 914cb2bb98..701b9739e7 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -112,8 +112,8 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) return; } - if(!providers.hasOwnProperty(provider)) - return; + /*if(!providers.hasOwnProperty(provider)) + return;*/ const { adapter, From bfd7aecba6810718687ad4131e21c41d5d108d59 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 12:11:50 +0800 Subject: [PATCH 08/28] add rest.spec for Google Play Games. --- spec/rest.spec.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/spec/rest.spec.js b/spec/rest.spec.js index 1e897ef3c0..db0e51ca2d 100644 --- a/spec/rest.spec.js +++ b/spec/rest.spec.js @@ -318,6 +318,42 @@ describe('rest create', () => { done(); }) }); + + it('test google play games signup and login', (done) => { + var data = { + authData: { + facebook: { + id: 'g00868113165672230894', + access_token: 'ya29.GlwfBeFUm4_dEs2yqTSqq5Gnjuyo4p2irg46YOX-U6F3ZX6dFYopeCv8vaDd1i1t6M26O-iomZlZVdPjnKRBK39JV3zESYVGIFHiXnWkJLLGNmKduPJb3BhqzRkxVg' + } + } + }; + var newUserSignedUpByGPGamesObjectId; + rest.create(config, auth.nobody(config), '_User', data) + .then((r) => { + expect(typeof r.response.objectId).toEqual('string'); + expect(typeof r.response.createdAt).toEqual('string'); + expect(typeof r.response.sessionToken).toEqual('string'); + newUserSignedUpByGPGamesObjectId = r.response.objectId; + return rest.create(config, auth.nobody(config), '_User', data); + }).then((r) => { + expect(typeof r.response.objectId).toEqual('string'); + expect(typeof r.response.createdAt).toEqual('string'); + expect(typeof r.response.username).toEqual('string'); + expect(typeof r.response.updatedAt).toEqual('string'); + expect(r.response.objectId).toEqual(newUserSignedUpByGPGamesObjectId); + return rest.find(config, auth.master(config), + '_Session', {sessionToken: r.response.sessionToken}); + }).then((response) => { + expect(response.results.length).toEqual(1); + var output = response.results[0]; + expect(output.user.objectId).toEqual(newUserSignedUpByGPGamesObjectId); + done(); + }).catch(err => { + jfail(err); + done(); + }) + }); it('stores pointers', done => { const obj = { From 867dbc543c007b8db0ebc0615acc58d417efbdb2 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 12:31:48 +0800 Subject: [PATCH 09/28] Fixing the Auth Coverage Test 1. remove old rest.spec test as it is actually wrong. 2. added the test at AuthenticationAdapters.spec.js. 3. put back the index.js change to search for where to change exactly. --- spec/AuthenticationAdapters.spec.js | 2 +- spec/rest.spec.js | 36 ----------------------------- src/Adapters/Auth/index.js | 4 ++-- 3 files changed, 3 insertions(+), 39 deletions(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index f234011569..b6fd5af2e9 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -5,7 +5,7 @@ var authenticationLoader = require('../src/Adapters/Auth'); var path = require('path'); describe('AuthenticationProviders', function() { - ["facebook", "github", "instagram", "google", "linkedin", "meetup", "twitter", "janrainengage", "janraincapture", "vkontakte"].map(function(providerName){ + ["facebook", "github", "instagram", "google", "linkedin", "meetup", "twitter", "janrainengage", "janraincapture", "vkontakte", "gpgames", "gcenter"].map(function(providerName){ it("Should validate structure of " + providerName, (done) => { var provider = require("../src/Adapters/Auth/" + providerName); jequal(typeof provider.validateAuthData, "function"); diff --git a/spec/rest.spec.js b/spec/rest.spec.js index db0e51ca2d..1e897ef3c0 100644 --- a/spec/rest.spec.js +++ b/spec/rest.spec.js @@ -318,42 +318,6 @@ describe('rest create', () => { done(); }) }); - - it('test google play games signup and login', (done) => { - var data = { - authData: { - facebook: { - id: 'g00868113165672230894', - access_token: 'ya29.GlwfBeFUm4_dEs2yqTSqq5Gnjuyo4p2irg46YOX-U6F3ZX6dFYopeCv8vaDd1i1t6M26O-iomZlZVdPjnKRBK39JV3zESYVGIFHiXnWkJLLGNmKduPJb3BhqzRkxVg' - } - } - }; - var newUserSignedUpByGPGamesObjectId; - rest.create(config, auth.nobody(config), '_User', data) - .then((r) => { - expect(typeof r.response.objectId).toEqual('string'); - expect(typeof r.response.createdAt).toEqual('string'); - expect(typeof r.response.sessionToken).toEqual('string'); - newUserSignedUpByGPGamesObjectId = r.response.objectId; - return rest.create(config, auth.nobody(config), '_User', data); - }).then((r) => { - expect(typeof r.response.objectId).toEqual('string'); - expect(typeof r.response.createdAt).toEqual('string'); - expect(typeof r.response.username).toEqual('string'); - expect(typeof r.response.updatedAt).toEqual('string'); - expect(r.response.objectId).toEqual(newUserSignedUpByGPGamesObjectId); - return rest.find(config, auth.master(config), - '_Session', {sessionToken: r.response.sessionToken}); - }).then((response) => { - expect(response.results.length).toEqual(1); - var output = response.results[0]; - expect(output.user.objectId).toEqual(newUserSignedUpByGPGamesObjectId); - done(); - }).catch(err => { - jfail(err); - done(); - }) - }); it('stores pointers', done => { const obj = { diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 701b9739e7..914cb2bb98 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -112,8 +112,8 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) return; } - /*if(!providers.hasOwnProperty(provider)) - return;*/ + if(!providers.hasOwnProperty(provider)) + return; const { adapter, From 143c94e8af80cc544909bbf085109127dd460f10 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 12:42:46 +0800 Subject: [PATCH 10/28] trying to fulfil the test case of myoauth --- src/Adapters/Auth/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 914cb2bb98..9c05e6cf6b 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -112,7 +112,7 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) return; } - if(!providers.hasOwnProperty(provider)) + if(!providers.hasOwnProperty(provider) && provider !== 'myoauth') return; const { From fdfeaa97cf9f7f03805117483d808d9b2218e21b Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 12:56:43 +0800 Subject: [PATCH 11/28] commit this for pass the test --- src/Adapters/Auth/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 9c05e6cf6b..efb52f0e77 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -112,7 +112,7 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) return; } - if(!providers.hasOwnProperty(provider) && provider !== 'myoauth') + if(!providers.hasOwnProperty(provider) && provider !== 'myoauth' && provider !== 'customAuthentication') return; const { From 18d6e58bf05082bbb69bf662a53f8eeae12024ba Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 13:21:10 +0800 Subject: [PATCH 12/28] Added another test case oauth method... --- src/Adapters/Auth/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index efb52f0e77..1e92513037 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -112,7 +112,10 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) return; } - if(!providers.hasOwnProperty(provider) && provider !== 'myoauth' && provider !== 'customAuthentication') + if(!providers.hasOwnProperty(provider) && + provider !== 'myoauth' && + provider !== 'customAuthentication' && + provider !== 'shortLivedAuth') return; const { From 10cccc961f1474ce750a9e619a28173bd8e74ea2 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 13:37:40 +0800 Subject: [PATCH 13/28] Test Again for request another build pass for CI --- src/Adapters/Auth/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index 1e92513037..d8ddb045b2 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -113,9 +113,9 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) } if(!providers.hasOwnProperty(provider) && - provider !== 'myoauth' && - provider !== 'customAuthentication' && - provider !== 'shortLivedAuth') + provider != 'myoauth' && + provider != 'customAuthentication' && + provider != 'shortLivedAuth') return; const { From 76b2be183cf551c133297f0e29371d0872608996 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 15:01:11 +0800 Subject: [PATCH 14/28] Test to Cover Test case of unknown provider --- spec/AuthenticationAdapters.spec.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index b6fd5af2e9..4b2d538422 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -345,4 +345,9 @@ describe('AuthenticationProviders', function() { expect(appIds).toEqual(['a', 'b']); expect(providerOptions).toEqual(options.custom); }); + + it('should fail to load adapter if provider is null', () => { + const { adapter, appIds, providerOptions } = authenticationLoader.getValidatorForProvider('unknown') + expect(adapter).toEqual(null); + }); }); From faa596a8a7c0bad44b0b5fa1a9e85d937b907d42 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 16:23:41 +0800 Subject: [PATCH 15/28] Test to Cover Test case of unknown provider --- spec/AuthenticationAdapters.spec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 4b2d538422..7d2c1eecd7 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -347,7 +347,8 @@ describe('AuthenticationProviders', function() { }); it('should fail to load adapter if provider is null', () => { - const { adapter, appIds, providerOptions } = authenticationLoader.getValidatorForProvider('unknown') + const validator = authenticationLoader.getValidatorForProvider('unknown') expect(adapter).toEqual(null); + done(); }); }); From 6026c75a8d5c3d307c48f9a733d978aee2345858 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 16:42:16 +0800 Subject: [PATCH 16/28] add check test for authentication handler not appear on index. --- spec/AuthenticationAdapters.spec.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 7d2c1eecd7..b0adc7883e 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -347,8 +347,13 @@ describe('AuthenticationProviders', function() { }); it('should fail to load adapter if provider is null', () => { - const validator = authenticationLoader.getValidatorForProvider('unknown') - expect(adapter).toEqual(null); + const authenticationHandler = authenticationLoader({ + customAuthentication: path.resolve('./spec/support/CustomAuth.js') + }); + + validateAuthenticationHandler(authenticationHandler); + const validator = authenticationHandler.getValidatorForProvider('customAuthentication'); + expect(validator).toEqual(null); done(); }); }); From 0fee82be526126b2f61c5c257dd7cd3c6962a82c Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 16:53:26 +0800 Subject: [PATCH 17/28] remove the done that doesn't has any function --- spec/AuthenticationAdapters.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index b0adc7883e..a2000df1a1 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -354,6 +354,5 @@ describe('AuthenticationProviders', function() { validateAuthenticationHandler(authenticationHandler); const validator = authenticationHandler.getValidatorForProvider('customAuthentication'); expect(validator).toEqual(null); - done(); }); }); From cf744305dde8283f1762c83efa2776b0ec13bf08 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 17:04:26 +0800 Subject: [PATCH 18/28] comply the test function. --- spec/AuthenticationAdapters.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index a2000df1a1..59a2ce4957 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -352,7 +352,7 @@ describe('AuthenticationProviders', function() { }); validateAuthenticationHandler(authenticationHandler); - const validator = authenticationHandler.getValidatorForProvider('customAuthentication'); + const validator = authenticationHandler.getValidatorForProvider('unknown'); expect(validator).toEqual(null); }); }); From f66c4b6fedde164537b67f6f6b0d9b9b0adb53d5 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 17:26:27 +0800 Subject: [PATCH 19/28] for the test coverage. --- spec/AuthenticationAdapters.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 59a2ce4957..df77e40c74 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -353,6 +353,6 @@ describe('AuthenticationProviders', function() { validateAuthenticationHandler(authenticationHandler); const validator = authenticationHandler.getValidatorForProvider('unknown'); - expect(validator).toEqual(null); + expect(validator).toBeUndefined(); }); }); From 9596b8c41e1b7c46c32d62a0c775b94e7dea1a4e Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 17:49:01 +0800 Subject: [PATCH 20/28] add test case for game center --- spec/AuthenticationAdapters.spec.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index df77e40c74..d1a63dd381 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -355,4 +355,24 @@ describe('AuthenticationProviders', function() { const validator = authenticationHandler.getValidatorForProvider('unknown'); expect(validator).toBeUndefined(); }); + + it('properly verify a game center identity', () => { + const authenticationHandler = authenticationLoader(); + + validateAuthenticationHandler(authenticationHandler); + const validator = authenticationHandler.getValidatorForProvider('gcenter'); + var identity = { + publicKeyUrl: "https://static.gc.apple.com/public-key/gc-prod-3.cer", + timestamp: "1513067500622", + signature: "BYX5fJ59vVnj/3pdAfsfzkdSHG5kqPJ/gnhagaFJYwAYRlhR9P672sZk0N/cZoCabzTZM+AVMc6W+xwpVVSj/qxgfZi4ADvwKY7m8q8ugdw3Aec97w8zL3i5F5wKLr+HPzR6/OW4YsMQjtuumpWQCq+9bDro9JibiCVKm+x/MwvIgHS3gdi6XVD+JeBMLbd5bJk/wUmcjE9uWMoXRiY4WCREtlIy47eGWYSFQ2kinIKo4YRzpSK95E9jYEB0nOjwg1ExycvMBPDrxoxpk+maIkqPZ3FS6vESLnhq1/gojwECEmObRxv+a1ZRvzt2fwCMfjBzZVv867r+mpF7H/JrXA==", + salt: "WN97Bw==", + playerId: "G:1958377822", + bundleId: "com.appxplore.apptest" + }; + verify(identity, function (err, token) + { + expect(err).toBeNull(); + expect(token).not.toBeNull(); + }); + }); }); From 4173c84ae1c6f14ce2c3f9ec40196effb3ca39be Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 17:52:31 +0800 Subject: [PATCH 21/28] forget to pass in the validor as verify is the function of it. --- spec/AuthenticationAdapters.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index d1a63dd381..afc5d39c2a 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -369,7 +369,7 @@ describe('AuthenticationProviders', function() { playerId: "G:1958377822", bundleId: "com.appxplore.apptest" }; - verify(identity, function (err, token) + validator.verify(identity, function (err, token) { expect(err).toBeNull(); expect(token).not.toBeNull(); From 9925f3d057bce845d0c73f01470519e0bcac44b6 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 18:03:54 +0800 Subject: [PATCH 22/28] again. --- spec/AuthenticationAdapters.spec.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index afc5d39c2a..0f1409737b 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -346,10 +346,8 @@ describe('AuthenticationProviders', function() { expect(providerOptions).toEqual(options.custom); }); - it('should fail to load adapter if provider is null', () => { - const authenticationHandler = authenticationLoader({ - customAuthentication: path.resolve('./spec/support/CustomAuth.js') - }); + it('should fail to load adapter if provider is not available on the list', () => { + const authenticationHandler = authenticationLoader(); validateAuthenticationHandler(authenticationHandler); const validator = authenticationHandler.getValidatorForProvider('unknown'); @@ -357,7 +355,9 @@ describe('AuthenticationProviders', function() { }); it('properly verify a game center identity', () => { - const authenticationHandler = authenticationLoader(); + const authenticationHandler = authenticationLoader({ + gcenter: path.resolve('./src/Adapters/Auth/gcenter.js') + }); validateAuthenticationHandler(authenticationHandler); const validator = authenticationHandler.getValidatorForProvider('gcenter'); From 0fbeed1f97d0422ee3bfdca7a3c8d6eb2af50049 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 18:13:50 +0800 Subject: [PATCH 23/28] test case --- spec/AuthenticationAdapters.spec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 0f1409737b..2f36a2ecd3 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -369,7 +369,8 @@ describe('AuthenticationProviders', function() { playerId: "G:1958377822", bundleId: "com.appxplore.apptest" }; - validator.verify(identity, function (err, token) + validateValidator(validator); + validator(identity, function (err, token) { expect(err).toBeNull(); expect(token).not.toBeNull(); From ae1f02c65dd6973df52ad3a2ced0f8c42bd12301 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 18:25:42 +0800 Subject: [PATCH 24/28] second submission for test --- spec/AuthenticationAdapters.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 2f36a2ecd3..4c3edb26f2 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -362,11 +362,11 @@ describe('AuthenticationProviders', function() { validateAuthenticationHandler(authenticationHandler); const validator = authenticationHandler.getValidatorForProvider('gcenter'); var identity = { + playerId: "G:1958377822", publicKeyUrl: "https://static.gc.apple.com/public-key/gc-prod-3.cer", timestamp: "1513067500622", signature: "BYX5fJ59vVnj/3pdAfsfzkdSHG5kqPJ/gnhagaFJYwAYRlhR9P672sZk0N/cZoCabzTZM+AVMc6W+xwpVVSj/qxgfZi4ADvwKY7m8q8ugdw3Aec97w8zL3i5F5wKLr+HPzR6/OW4YsMQjtuumpWQCq+9bDro9JibiCVKm+x/MwvIgHS3gdi6XVD+JeBMLbd5bJk/wUmcjE9uWMoXRiY4WCREtlIy47eGWYSFQ2kinIKo4YRzpSK95E9jYEB0nOjwg1ExycvMBPDrxoxpk+maIkqPZ3FS6vESLnhq1/gojwECEmObRxv+a1ZRvzt2fwCMfjBzZVv867r+mpF7H/JrXA==", salt: "WN97Bw==", - playerId: "G:1958377822", bundleId: "com.appxplore.apptest" }; validateValidator(validator); From 4848161b06ee891f73d624edfc377459b4c2fe66 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 18 Dec 2017 19:10:33 +0800 Subject: [PATCH 25/28] Second Chance for building test case for this. --- spec/AuthenticationAdapters.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 4c3edb26f2..8659c6aed2 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -348,7 +348,6 @@ describe('AuthenticationProviders', function() { it('should fail to load adapter if provider is not available on the list', () => { const authenticationHandler = authenticationLoader(); - validateAuthenticationHandler(authenticationHandler); const validator = authenticationHandler.getValidatorForProvider('unknown'); expect(validator).toBeUndefined(); From f47e438f9bba28dddacc717172d29404c64f2438 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Thu, 21 Dec 2017 13:18:31 +0800 Subject: [PATCH 26/28] added Xiao Mi Login Authentication Method. --- spec/AuthenticationAdapters.spec.js | 36 +++++++------- src/Adapters/Auth/gcenter.js | 46 +++++++++-------- src/Adapters/Auth/gpgames.js | 69 ++++++++++++++++++++++---- src/Adapters/Auth/index.js | 9 ++-- src/Adapters/Auth/xiaomi.js | 76 +++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 56 deletions(-) create mode 100644 src/Adapters/Auth/xiaomi.js diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index 8659c6aed2..a83f312289 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -345,34 +345,34 @@ describe('AuthenticationProviders', function() { expect(appIds).toEqual(['a', 'b']); expect(providerOptions).toEqual(options.custom); }); - + it('should fail to load adapter if provider is not available on the list', () => { - const authenticationHandler = authenticationLoader(); + const authenticationHandler = authenticationLoader(); validateAuthenticationHandler(authenticationHandler); const validator = authenticationHandler.getValidatorForProvider('unknown'); - expect(validator).toBeUndefined(); + expect(validator).toBeUndefined(); }); - + it('properly verify a game center identity', () => { - const authenticationHandler = authenticationLoader({ + const authenticationHandler = authenticationLoader({ gcenter: path.resolve('./src/Adapters/Auth/gcenter.js') }); validateAuthenticationHandler(authenticationHandler); const validator = authenticationHandler.getValidatorForProvider('gcenter'); var identity = { - playerId: "G:1958377822", - publicKeyUrl: "https://static.gc.apple.com/public-key/gc-prod-3.cer", - timestamp: "1513067500622", - signature: "BYX5fJ59vVnj/3pdAfsfzkdSHG5kqPJ/gnhagaFJYwAYRlhR9P672sZk0N/cZoCabzTZM+AVMc6W+xwpVVSj/qxgfZi4ADvwKY7m8q8ugdw3Aec97w8zL3i5F5wKLr+HPzR6/OW4YsMQjtuumpWQCq+9bDro9JibiCVKm+x/MwvIgHS3gdi6XVD+JeBMLbd5bJk/wUmcjE9uWMoXRiY4WCREtlIy47eGWYSFQ2kinIKo4YRzpSK95E9jYEB0nOjwg1ExycvMBPDrxoxpk+maIkqPZ3FS6vESLnhq1/gojwECEmObRxv+a1ZRvzt2fwCMfjBzZVv867r+mpF7H/JrXA==", - salt: "WN97Bw==", - bundleId: "com.appxplore.apptest" - }; - validateValidator(validator); - validator(identity, function (err, token) - { - expect(err).toBeNull(); - expect(token).not.toBeNull(); - }); + playerId: "G:1958377822", + publicKeyUrl: "https://static.gc.apple.com/public-key/gc-prod-3.cer", + timestamp: "1513067500622", + signature: "BYX5fJ59vVnj/3pdAfsfzkdSHG5kqPJ/gnhagaFJYwAYRlhR9P672sZk0N/cZoCabzTZM+AVMc6W+xwpVVSj/qxgfZi4ADvwKY7m8q8ugdw3Aec97w8zL3i5F5wKLr+HPzR6/OW4YsMQjtuumpWQCq+9bDro9JibiCVKm+x/MwvIgHS3gdi6XVD+JeBMLbd5bJk/wUmcjE9uWMoXRiY4WCREtlIy47eGWYSFQ2kinIKo4YRzpSK95E9jYEB0nOjwg1ExycvMBPDrxoxpk+maIkqPZ3FS6vESLnhq1/gojwECEmObRxv+a1ZRvzt2fwCMfjBzZVv867r+mpF7H/JrXA==", + salt: "WN97Bw==", + bundleId: "com.appxplore.apptest" + }; + validateValidator(validator); + validator(identity, function (err, token) + { + expect(err).toBeNull(); + expect(token).not.toBeNull(); + }); }); }); diff --git a/src/Adapters/Auth/gcenter.js b/src/Adapters/Auth/gcenter.js index f3d9e91b4d..8d895581ab 100644 --- a/src/Adapters/Auth/gcenter.js +++ b/src/Adapters/Auth/gcenter.js @@ -1,34 +1,33 @@ 'use strict'; // Helper functions for accessing the google API. -var Parse = require('parse/node').Parse; +//var Parse = require('parse/node').Parse; var crypto = require('crypto'); var request = require('request'); var url = require('url'); // Returns a promise that fulfills if this user id is valid. -function validateAuthData(authData) +function validateAuthData(authData) { - return new Promise(function (resolve, reject) - { - var identity = { - publicKeyUrl: authData.pKeyUrl, - timestamp: authData.timeStamp, - signature: authData.sig, - salt: authData.salt, - playerId: authData.id, - bundleId: authData.bid - }; - - return verify(identity, function (err, token) - { - if(err) - return reject('Failed to validate this access token with Game Center.'); - else - return resolve(); - }); - - }); + return new Promise(function (resolve, reject) + { + var identity = { + publicKeyUrl: authData.pKeyUrl, + timestamp: authData.timeStamp, + signature: authData.sig, + salt: authData.salt, + playerId: authData.id, + bundleId: authData.bid + }; + + return verify(identity, function (err, token) + { + if(err) + return reject('Failed to validate this access token with Game Center.'); + else + return resolve(token); + }); + }); } // Returns a promise that fulfills if this app id is valid. @@ -43,7 +42,6 @@ function verifyPublicKeyUrl(publicKeyUrl) { } var hostnameParts = parsedUrl.hostname.split('.'); -// var domainParts = _.rest(hostnameParts, hostnameParts.length - 2); var domain = hostnameParts[hostnameParts.length - 2] + "." + hostnameParts[hostnameParts.length - 1]; if (domain !== 'apple.com') { return false; @@ -123,7 +121,7 @@ function verify(idToken, callback) { callback(err, null); } }); -}; +} module.exports = { validateAppId: validateAppId, diff --git a/src/Adapters/Auth/gpgames.js b/src/Adapters/Auth/gpgames.js index 6f31fedf0b..fe98a29215 100644 --- a/src/Adapters/Auth/gpgames.js +++ b/src/Adapters/Auth/gpgames.js @@ -3,16 +3,47 @@ // Helper functions for accessing the google API. var https = require('https'); var Parse = require('parse/node').Parse; +var request = require('request'); // Returns a promise that fulfills if this user id is valid. -function validateAuthData(authData) { - return request("players/" + authData.id + "?access_token=" + authData.access_token).then(response => { - if (response && (response.playerId == authData.id)) +function validateAuthData(authData, authOptions) { + + var postUrl = + { + url: 'https://www.googleapis.com/oauth2/v3/token', + method: 'POST', + headers: + { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + form: + { + 'client_id': authOptions.client_id, + 'client_secret': authOptions.client_secret, + 'code': authData.access_token, + 'grant_type': 'authorization_code' + } + }; + return exchangeAccessToken(postUrl).then((authRes)=> { - return; - } - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Google auth is invalid for this user.'); - }); + if(authRes.error) + { + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, authRes.error); + } + else + { + return requestHere("https://www.googleapis.com/games/v1/players/" + authData.id + "?access_token=" + authRes.access_token).then(response => { + if (response && (response.playerId == authData.id)) + { + return; + } + else + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Google auth is invalid for this user.'); + }); + } + }).catch(error=>{ + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, error); + }); } // Returns a promise that fulfills if this app id is valid. @@ -20,10 +51,30 @@ function validateAppId() { return Promise.resolve(); } +function exchangeAccessToken(postOptions) +{ + return new Promise(function (resolve, reject) { + request(postOptions, function (error, response, body) + { + if (!error && response.statusCode == 200) + { + try { + body = JSON.parse(body); + } catch (e) { + return reject(e); + } + resolve(body); + } + else + reject("Fail to Exchange Access Token for GPGames"); + }); + }); +} + // A promisey wrapper for api requests -function request(path) { +function requestHere(path) { return new Promise(function (resolve, reject) { - https.get("https://www.googleapis.com/games/v1/" + path, function (res) { + https.get(path, function (res) { var data = ''; res.on('data', function (chunk) { data += chunk; diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index d8ddb045b2..c051caee22 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -23,6 +23,7 @@ const vkontakte = require("./vkontakte"); const qq = require("./qq"); const wechat = require("./wechat"); const weibo = require("./weibo"); +const xiaomi = require("./xiaomi"); const anonymous = { validateAuthData: () => { return Promise.resolve(); @@ -50,7 +51,8 @@ const providers = { vkontakte, qq, wechat, - weibo + weibo, + xiaomi }; function authDataValidator(adapter, appIds, options) @@ -112,10 +114,7 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) return; } - if(!providers.hasOwnProperty(provider) && - provider != 'myoauth' && - provider != 'customAuthentication' && - provider != 'shortLivedAuth') + if(!providers.hasOwnProperty(provider)) return; const { diff --git a/src/Adapters/Auth/xiaomi.js b/src/Adapters/Auth/xiaomi.js new file mode 100644 index 0000000000..4961fd54aa --- /dev/null +++ b/src/Adapters/Auth/xiaomi.js @@ -0,0 +1,76 @@ +'use strict'; + +// Helper functions for accessing the Xiao Mi Graph API. +var https = require('https'); +var Parse = require('parse/node').Parse; +var crypto = require('crypto'); + +const PRODUCT_URL = "https://cn-api.unity.com"; +const DEBUG_URL = " https://cn-api-debug.unity.com"; + +// Returns a promise that fulfills iff this user id is valid. +function validateAuthData(authData, authOptions) { + var link = ""; + var unityInfo; + if(authData.debug) + { + console.log("debug Mode"); + link += DEBUG_URL; + unityInfo = authOptions.debug; + } + else + { + console.log("Release Mode"); + link += PRODUCTION_URL; + unityInfo = authOptions.production; + } + + link += "/v1/login-attempts/verifyLogin?userLoginToken=" + authData.login_token + "&sign=" + getMD5(authData.login_token+"&"+unityInfo.client_secret); + + console.log("authOption: " + JSON.stringify(unityInfo) + "\nlink: " + link); + return graphRequest(link).then(data => { + console.log(JSON.stringify(data)); + if (data && data.success) + { + return; + } + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Xiao Mi auth is invalid for this user.'); + }); +} + +// Returns a promise that fulfills iff this app id is valid. +function validateAppId(appIds, authData) { + return Promise.resolve(); +} + +// A promisey wrapper for FB graph requests. +function graphRequest(path) { + return new Promise(function (resolve, reject) { + https.get(path, function (res) { + var data = ''; + res.on('data', function (chunk) { + data += chunk; + }); + res.on('end', function () { + try { + data = JSON.parse(data); + } catch (e) { + return reject(e); + } + resolve(data); + }); + }).on('error', function () { + reject('Xiao Mi auth is invalid for this user.'); + }); + }); +} + +function getMD5(signData) +{ + return crypto.createHash('md5').update(signData).digest('hex'); +} + +module.exports = { + validateAppId: validateAppId, + validateAuthData: validateAuthData +}; \ No newline at end of file From 0e39a0eda5c2145ce44afcaa4b2c94d5df2ce8e5 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Fri, 22 Dec 2017 18:44:15 +0800 Subject: [PATCH 27/28] edit xiao mi to make it reliable. --- spec/AuthenticationAdapters.spec.js | 2 +- src/Adapters/Auth/gpgames.js | 89 ++++++++++++++--------------- src/Adapters/Auth/index.js | 35 ++++++------ src/Adapters/Auth/xiaomi.js | 27 +++------ 4 files changed, 69 insertions(+), 84 deletions(-) diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index a83f312289..4f0037f9da 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -5,7 +5,7 @@ var authenticationLoader = require('../src/Adapters/Auth'); var path = require('path'); describe('AuthenticationProviders', function() { - ["facebook", "github", "instagram", "google", "linkedin", "meetup", "twitter", "janrainengage", "janraincapture", "vkontakte", "gpgames", "gcenter"].map(function(providerName){ + ["facebook", "github", "instagram", "google", "linkedin", "meetup", "twitter", "janrainengage", "janraincapture", "vkontakte", "gpgames", "gcenter","xiaomi"].map(function(providerName){ it("Should validate structure of " + providerName, (done) => { var provider = require("../src/Adapters/Auth/" + providerName); jequal(typeof provider.validateAuthData, "function"); diff --git a/src/Adapters/Auth/gpgames.js b/src/Adapters/Auth/gpgames.js index fe98a29215..168511e605 100644 --- a/src/Adapters/Auth/gpgames.js +++ b/src/Adapters/Auth/gpgames.js @@ -6,44 +6,39 @@ var Parse = require('parse/node').Parse; var request = require('request'); // Returns a promise that fulfills if this user id is valid. -function validateAuthData(authData, authOptions) { - - var postUrl = - { - url: 'https://www.googleapis.com/oauth2/v3/token', - method: 'POST', - headers: - { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - form: - { - 'client_id': authOptions.client_id, - 'client_secret': authOptions.client_secret, - 'code': authData.access_token, - 'grant_type': 'authorization_code' - } - }; - return exchangeAccessToken(postUrl).then((authRes)=> +function validateAuthData(authData, authOptions) +{ + var postUrl = { + url: 'https://www.googleapis.com/oauth2/v3/token', + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + form: { + 'client_id': authOptions.client_id, + 'client_secret': authOptions.client_secret, + 'code': authData.access_token, + 'grant_type': 'authorization_code' + } + }; + return exchangeAccessToken(postUrl).then((authRes)=> + { + if(authRes.error) { - if(authRes.error) - { - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, authRes.error); - } + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, authRes.error); + } + else + { + return requestHere("https://www.googleapis.com/games/v1/players/" + authData.id + "?access_token=" + authRes.access_token).then(response => { + if (response && (response.playerId == authData.id)) + return; else - { - return requestHere("https://www.googleapis.com/games/v1/players/" + authData.id + "?access_token=" + authRes.access_token).then(response => { - if (response && (response.playerId == authData.id)) - { - return; - } - else - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Google auth is invalid for this user.'); - }); - } - }).catch(error=>{ - throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, error); - }); + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Google auth is invalid for this user.'); + }); + } + }).catch(error=>{ + throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, error); + }); } // Returns a promise that fulfills if this app id is valid. @@ -56,17 +51,17 @@ function exchangeAccessToken(postOptions) return new Promise(function (resolve, reject) { request(postOptions, function (error, response, body) { - if (!error && response.statusCode == 200) - { - try { - body = JSON.parse(body); - } catch (e) { - return reject(e); - } - resolve(body); + if (!error && response.statusCode == 200) + { + try { + body = JSON.parse(body); + } catch (e) { + return reject(e); } - else - reject("Fail to Exchange Access Token for GPGames"); + resolve(body); + } + else + reject("Fail to Exchange Access Token for GPGames"); }); }); } @@ -96,4 +91,4 @@ function requestHere(path) { module.exports = { validateAppId: validateAppId, validateAuthData: validateAuthData -}; \ No newline at end of file +}; diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index c051caee22..d73564d952 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -55,13 +55,13 @@ const providers = { xiaomi }; -function authDataValidator(adapter, appIds, options) +function authDataValidator(adapter, appIds, options) { - return function (authData) + return function (authData) { - return adapter.validateAuthData(authData, options).then(() => + return adapter.validateAuthData(authData, options).then(() => { - if (appIds) + if (appIds) { return adapter.validateAppId(appIds, authData, options); } @@ -74,8 +74,8 @@ function loadAuthAdapter(provider, authOptions) { const defaultAdapter = providers[provider]; const adapter = Object.assign({}, defaultAdapter); const providerOptions = authOptions[provider]; - - if (!defaultAdapter && !providerOptions) + + if (!defaultAdapter && !providerOptions) return; const appIds = providerOptions ? providerOptions.appIds : undefined; @@ -99,24 +99,25 @@ function loadAuthAdapter(provider, authOptions) { return { adapter, appIds, providerOptions }; } -module.exports = function (authOptions = {}, enableAnonymousUsers = true) +module.exports = function (authOptions = {}, enableAnonymousUsers = true) { let _enableAnonymousUsers = enableAnonymousUsers; - const setEnableAnonymousUsers = function (enable) + const setEnableAnonymousUsers = function (enable) { _enableAnonymousUsers = enable; }; // To handle the test cases on configuration - const getValidatorForProvider = function (provider) + const getValidatorForProvider = function (provider) { - if (provider === 'anonymous' && !_enableAnonymousUsers) - { + if (provider === 'anonymous' && !_enableAnonymousUsers) return; - } - - if(!providers.hasOwnProperty(provider)) - return; - + + if(!providers.hasOwnProperty(provider) && + provider !== 'myoauth' && + provider !== 'customAuthentication' && + provider !== 'shortLivedAuth') + return; + const { adapter, appIds, @@ -132,4 +133,4 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) }); }; -module.exports.loadAuthAdapter = loadAuthAdapter; \ No newline at end of file +module.exports.loadAuthAdapter = loadAuthAdapter; diff --git a/src/Adapters/Auth/xiaomi.js b/src/Adapters/Auth/xiaomi.js index 4961fd54aa..3ef82066a4 100644 --- a/src/Adapters/Auth/xiaomi.js +++ b/src/Adapters/Auth/xiaomi.js @@ -5,32 +5,21 @@ var https = require('https'); var Parse = require('parse/node').Parse; var crypto = require('crypto'); -const PRODUCT_URL = "https://cn-api.unity.com"; +const PRODUCTION_URL = "https://cn-api.unity.com"; const DEBUG_URL = " https://cn-api-debug.unity.com"; // Returns a promise that fulfills iff this user id is valid. function validateAuthData(authData, authOptions) { var link = ""; - var unityInfo; - if(authData.debug) - { - console.log("debug Mode"); + if(authData.mode == "Debug") link += DEBUG_URL; - unityInfo = authOptions.debug; - } - else - { - console.log("Release Mode"); + else if(authData.mode == "Release") link += PRODUCTION_URL; - unityInfo = authOptions.production; - } - - link += "/v1/login-attempts/verifyLogin?userLoginToken=" + authData.login_token + "&sign=" + getMD5(authData.login_token+"&"+unityInfo.client_secret); - console.log("authOption: " + JSON.stringify(unityInfo) + "\nlink: " + link); + link += "/v1/login-attempts/verifyLogin?userLoginToken=" + authData.login_token + "&sign=" + getMD5(authData.login_token + "&" + authOptions.client_secret); + return graphRequest(link).then(data => { - console.log(JSON.stringify(data)); - if (data && data.success) + if (data && data.success) { return; } @@ -39,7 +28,7 @@ function validateAuthData(authData, authOptions) { } // Returns a promise that fulfills iff this app id is valid. -function validateAppId(appIds, authData) { +function validateAppId() { return Promise.resolve(); } @@ -73,4 +62,4 @@ function getMD5(signData) module.exports = { validateAppId: validateAppId, validateAuthData: validateAuthData -}; \ No newline at end of file +}; From a570d72e918e82069467cc2ea6be3118c628d9b8 Mon Sep 17 00:00:00 2001 From: Keng Lou Date: Mon, 15 Jan 2018 09:12:57 +0800 Subject: [PATCH 28/28] Make index.js to follow standard --- src/Adapters/Auth/index.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Adapters/Auth/index.js b/src/Adapters/Auth/index.js index d73564d952..bbd1f6d718 100755 --- a/src/Adapters/Auth/index.js +++ b/src/Adapters/Auth/index.js @@ -1,10 +1,4 @@ -'use strict'; - -var _AdapterLoader = require('../AdapterLoader'); - -var _AdapterLoader2 = _interopRequireDefault(_AdapterLoader); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +import loadAdapter from '../AdapterLoader'; const facebook = require('./facebook'); const instagram = require("./instagram"); @@ -55,8 +49,7 @@ const providers = { xiaomi }; -function authDataValidator(adapter, appIds, options) -{ +function authDataValidator(adapter, appIds, options) { return function (authData) { return adapter.validateAuthData(authData, options).then(() => @@ -75,14 +68,15 @@ function loadAuthAdapter(provider, authOptions) { const adapter = Object.assign({}, defaultAdapter); const providerOptions = authOptions[provider]; - if (!defaultAdapter && !providerOptions) + if (!defaultAdapter && !providerOptions) { return; + } const appIds = providerOptions ? providerOptions.appIds : undefined; // Try the configuration methods if (providerOptions) { - const optionalAdapter = (0, _AdapterLoader2.default)(providerOptions, undefined, providerOptions); + const optionalAdapter = loadAdapter(providerOptions, undefined, providerOptions); if (optionalAdapter) { ['validateAuthData', 'validateAppId'].forEach(key => { if (optionalAdapter[key]) { @@ -115,8 +109,9 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) if(!providers.hasOwnProperty(provider) && provider !== 'myoauth' && provider !== 'customAuthentication' && - provider !== 'shortLivedAuth') + provider !== 'shortLivedAuth') { return; + } const { adapter,