Support Google Sign-In in google-oauth package. (#8549)

* Support Google Sign-In in google-oauth package.

Addresses #8253.

* Use Meteor.startup instead of listening for deviceready event.

* Fix mobile-config.js typo.

* Bump accounts-google and google-oauth package versions.

I'm only bumping the patch versions, even though the recent changes to
these packages may seem significant, for two reasons:

1. Bumping the minor versions would force Meteor 1.4.3 developers to
   upgrade to Meteor 1.4.4 if they wanted to use these changes.

2. The accounts-google and google-oauth packages without these changes
   will stop working completely in two weeks, which is much worse than the
   risks of upgrading.
This commit is contained in:
Ben Newman
2017-04-03 17:07:12 -04:00
committed by Ben Newman
parent 0a73a80b4b
commit 954efa7f5a
8 changed files with 140 additions and 6 deletions

View File

@@ -8,6 +8,15 @@ if (Meteor.isClient) {
options = null;
}
if (Meteor.isCordova &&
Google.signIn) {
// After 20 April 2017, Google OAuth login will no longer work from
// a WebView, so Cordova apps must use Google Sign-In instead.
// https://github.com/meteor/meteor/issues/8253
Google.signIn(options, callback);
return;
}
// Use Google's domain-specific login page if we want to restrict creation to
// a particular email domain. (Don't use it if restrictCreationByEmailDomain
// is a function.) Note that all this does is change Google's UI ---

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: "Login service for Google accounts",
version: "1.1.1"
version: "1.1.2"
});
Package.onUse(function(api) {

View File

@@ -1,4 +1,4 @@
Google = {};
var Google = require("./namespace.js");
// Request Google credentials for the user
// @param options {optional}

View File

@@ -1,12 +1,38 @@
Google = {};
var Google = require("./namespace.js");
var Accounts = require("meteor/accounts-base").Accounts;
// https://developers.google.com/accounts/docs/OAuth2Login#userinfocall
Google.whitelistedFields = ['id', 'email', 'verified_email', 'name', 'given_name',
'family_name', 'picture', 'locale', 'timezone', 'gender'];
Accounts.registerLoginHandler(function (request) {
if (request.googleSignIn !== true) {
return;
}
var res = HTTP.get(
"https://www.googleapis.com/oauth2/v3/tokeninfo",
{ headers: { "User-Agent": "Meteor/1.0" },
params: { id_token: request.idToken }}
);
if (res.error) {
throw res.error;
}
if (res.statusCode === 200 &&
res.data.sub === request.userId) {
return Accounts.updateOrCreateUserFromExternalService("google", {
id: request.userId,
idToken: request.idToken,
accessToken: request.accessToken,
email: request.email,
picture: request.imageUrl
});
}
});
OAuth.registerService('google', 2, null, function(query) {
var response = getTokens(query);
var expiresAt = (+new Date) + (1000 * parseInt(response.expiresIn, 10));
var accessToken = response.accessToken;

View File

@@ -0,0 +1,84 @@
var Google = require("./namespace.js");
var gplusPromise = new Promise(function (resolve, reject) {
if (! Meteor.isCordova) {
reject(new Error("plugins.googleplus requires Cordova"));
return;
}
Meteor.startup(function () {
var plugins = global.plugins;
var gplus = plugins && plugins.googleplus;
if (gplus) {
resolve(gplus);
} else {
reject(new Error("plugins.googleplus not defined"));
}
});
});
function tolerateUnhandledRejection() {}
gplusPromise.catch(tolerateUnhandledRejection);
// After 20 April 2017, Google OAuth login will no longer work from a
// WebView, so Cordova apps must use Google Sign-In instead.
// https://github.com/meteor/meteor/issues/8253
exports.signIn = Google.signIn = function (options, callback) {
// support a callback without options
if (! callback && typeof options === "function") {
callback = options;
options = null;
}
gplusPromise.then(function (gplus) {
var config = ServiceConfiguration.configurations.findOne({
service: "google"
});
if (! config) {
throw new ServiceConfiguration.ConfigError();
}
options = Object.assign(Object.create(null), options);
gplus.login({
scopes: getScopes(options).join(" "),
webClientId: config.clientId,
offline: true
}, function (response) {
Accounts.callLoginMethod({
methodArguments: [Object.assign({
googleSignIn: true
}, response)],
userCallback: callback
});
}, callback);
}).catch(callback);
};
function getScopes(options) {
// we need the email scope to get user id from google.
var requiredScopes = ['email'];
var scopes = ['profile'];
if (options && options.requestPermissions) {
scopes = options.requestPermissions;
}
return _.union(scopes, requiredScopes);
}
exports.signOut = Google.signOut = function () {
return gplusPromise.then(function (gplus) {
return new Promise(function (resolve) {
gplus.logout(resolve);
});
});
};
// Make sure we don't stay logged in with Google Sign-In after the client
// calls Meteor.logout().
Meteor.startup(function () {
Accounts.onLogout(function () {
Google.signOut().catch(tolerateUnhandledRejection);
});
});

View File

@@ -0,0 +1,6 @@
// The module.exports object of this module becomes the Google namespace
// for other modules in this package.
Google = module.exports;
// So that api.export finds the "Google" property.
Google.Google = Google;

View File

@@ -1,9 +1,15 @@
Package.describe({
summary: "Google OAuth flow",
version: "1.2.0"
version: "1.2.1"
});
Cordova.depends({
"cordova-plugin-googleplus": "5.1.1"
});
Package.onUse(function(api) {
api.use("modules");
api.use("promise");
api.use('oauth2', ['client', 'server']);
api.use('oauth', ['client', 'server']);
api.use('http', ['server']);
@@ -12,6 +18,9 @@ Package.onUse(function(api) {
api.addFiles('google_server.js', 'server');
api.addFiles('google_client.js', 'client');
api.addFiles('google_sign-in.js', 'web.cordova');
api.mainModule('namespace.js');
api.export('Google');
});

View File

@@ -111,7 +111,7 @@ app bundle (`pluginVersionsFromStarManifest`, a combination of
`.meteor/cordova-plugins` for stand-alone plugin installs and the plugins added
as dependencies of packages through `Cordova.depends`).
The `pluginsConfiguration` comes from `App.configurePlugin` calls in
`meteor-config.js`.
`mobile-config.js`.
Uses methods `CordovaProject#listInstalledPluginVersions()`,
`CordovaProject#addPlugin(name, version, config)`,