Skip to content

Commit

Permalink
rework OAuth, Accounts.oauth
Browse files Browse the repository at this point in the history
  • Loading branch information
nathan-muir committed Oct 16, 2023
1 parent c86decb commit 35b09e7
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 136 deletions.
1 change: 0 additions & 1 deletion _prototype/meteor-runtime/meteor-runtime-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export {
} from './src/browser/minimongo/minimongo_client.js';
export { Mongo } from './src/browser/mongo/client_main.js';
export { MongoID } from './src/browser/mongo-id/id.js';
export { OAuth } from './src/browser/oauth/oauth_client.js';
// export { Promise } from './src/browser/promise/client.js';
export { Random } from './src/browser/random/main_client.js';
export { ReactiveDict } from './src/browser/reactive-dict/reactive-dict-client.js';
Expand Down
2 changes: 1 addition & 1 deletion _prototype/meteor-runtime/meteor-runtime-node.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { Accounts } from './src/node/accounts-base/server_main.js';
import './src/node/accounts-password/password_server.js';
import './src/node/accounts-oauth/oauth_server.js';
import './src/node/accounts-google/google_server.js';
export { check, Match } from './src/node/check/match.js';
export { DDP } from './src/node/ddp-client/server/server.js';
export { DDPRateLimiter } from './src/node/ddp-rate-limiter/ddp-rate-limiter.js';
Expand All @@ -16,7 +17,6 @@ export {
} from './src/node/minimongo/minimongo_server.js';
export { Mongo } from './src/node/mongo/server_main.js';
export { MongoID } from './src/node/mongo-id/id.js';
export { OAuth } from './src/node/oauth/oauth_server.js';
import './src/node/oauth2/oauth2_server.js';
export { Promise } from './src/node/promise/server.js';
export { Random } from './src/node/random/main_server.js';
Expand Down
10 changes: 5 additions & 5 deletions packages/accounts-oauth/oauth_client.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import './oauth_common.js';
export * from './oauth_common.js'
// Documentation for Meteor.loginWithExternalService

/**
Expand Down Expand Up @@ -72,7 +72,7 @@ Meteor.startup(() => {
// Send an OAuth login method to the server. If the user authorized
// access in the popup this should log the user in, otherwise
// nothing should happen.
Accounts.oauth.tryLoginAfterPopupClosed = (
export const tryLoginAfterPopupClosed = (
credentialToken,
callback,
shouldRetry = true
Expand All @@ -89,7 +89,7 @@ Accounts.oauth.tryLoginAfterPopupClosed = (
}
Meteor.setTimeout(
() =>
Accounts.oauth.tryLoginAfterPopupClosed(
tryLoginAfterPopupClosed(
credentialToken,
callback,
false
Expand All @@ -105,12 +105,12 @@ Accounts.oauth.tryLoginAfterPopupClosed = (
});
};

Accounts.oauth.credentialRequestCompleteHandler = callback =>
export const credentialRequestCompleteHandler = callback =>
credentialTokenOrError => {
if(credentialTokenOrError && credentialTokenOrError instanceof Error) {
callback && callback(credentialTokenOrError);
} else {
Accounts.oauth.tryLoginAfterPopupClosed(credentialTokenOrError, callback);
tryLoginAfterPopupClosed(credentialTokenOrError, callback);
}
}

8 changes: 3 additions & 5 deletions packages/accounts-oauth/oauth_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ const VALID_CONFIG_KEYS = [
'tokenSequenceLength',
];

Accounts.oauth = {};

const services = {};
const hasOwn = Object.prototype.hasOwnProperty;

// Helper for registering OAuth based accounts packages.
// On the server, adds an index to the user collection.
Accounts.oauth.registerService = name => {
export const registerService = name => {
if (hasOwn.call(services, name))
throw new Error(`Duplicate service: ${name}`);
services[name] = true;
Expand All @@ -43,13 +41,13 @@ Accounts.oauth.registerService = name => {
// contain it.
// It's worth noting that already logged in users will remain logged in unless
// you manually expire their sessions.
Accounts.oauth.unregisterService = name => {
export const unregisterService = name => {
if (!hasOwn.call(services, name))
throw new Error(`Service not found: ${name}`);
delete services[name];
};

Accounts.oauth.serviceNames = () => Object.keys(services);
export const serviceNames = () => Object.keys(services);

// loginServiceConfiguration and ConfigError are maintained for backwards compatibility
/*Meteor.startup(() => {
Expand Down
6 changes: 4 additions & 2 deletions packages/accounts-oauth/oauth_server.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import './oauth_common.js';
import { serviceNames } from './oauth_common.js';

export * from './oauth_common.js';
// Listen to calls to `login` with an oauth option set. This is where
// users actually get logged in to meteor via oauth.
Accounts.registerLoginHandler(options => {
Expand Down Expand Up @@ -43,7 +45,7 @@ Accounts.registerLoginHandler(options => {
// to the user.
throw result;
else {
if (! Accounts.oauth.serviceNames().includes(result.serviceName)) {
if (! serviceNames().includes(result.serviceName)) {
// serviceName was not found in the registered services list.
// This could happen because the service never registered itself or
// unregisterService was called on it.
Expand Down
4 changes: 2 additions & 2 deletions packages/oauth/oauth_browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// arguments.
// @param dimensions {optional Object(width, height)} The dimensions of
// the popup. If not passed defaults to something sane.
OAuth.showPopup = (url, callback, dimensions) => {
export const OAuth$showPopup = (url, callback, dimensions) => {
// default dimensions that worked well for facebook and google
const popup = openCenteredPopup(
url,
Expand Down Expand Up @@ -68,6 +68,6 @@ const openCenteredPopup = function(url, width, height) {

if (newwindow.focus)
newwindow.focus();

return newwindow;
};
44 changes: 27 additions & 17 deletions packages/oauth/oauth_client.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import { OAuth$showPopup } from "./oauth_browser.js";
import { OAuth$_storageTokenPrefix, OAuth$_redirectUri } from "./oauth_common.js";

// credentialToken -> credentialSecret. You must provide both the
// credentialToken and the credentialSecret to retrieve an access token from
// the _pendingCredentials collection.
const credentialSecrets = {};

export const OAuth = {};

OAuth.showPopup = (url, callback, dimensions) => {
throw new Error("OAuth.showPopup must be implemented on this arch.");
};

// Determine the login style (popup or redirect) for this login flow.
//
//
OAuth._loginStyle = (service, config, options) => {
const OAuth$_loginStyle = (service, config, options) => {

if (Meteor.isCordova) {
return "popup";
Expand All @@ -38,7 +35,7 @@ OAuth._loginStyle = (service, config, options) => {
return loginStyle;
};

OAuth._stateParam = (loginStyle, credentialToken, redirectUrl) => {
const OAuth$_stateParam = (loginStyle, credentialToken, redirectUrl) => {
const state = {
loginStyle,
credentialToken,
Expand All @@ -62,7 +59,7 @@ OAuth._stateParam = (loginStyle, credentialToken, redirectUrl) => {
// the login service, save the credential token for this login attempt
// in the reload migration data.
//
OAuth.saveDataForRedirect = (loginService, credentialToken) => {
const OAuth$saveDataForRedirect = (loginService, credentialToken) => {
Reload._onMigrate('oauth', () => [true, { loginService, credentialToken }]);
Reload._migrate(null, {immediateMigration: true});
};
Expand All @@ -75,14 +72,14 @@ OAuth.saveDataForRedirect = (loginService, credentialToken) => {
// application startup and we weren't just redirected at the end of
// the login flow.
//
OAuth.getDataAfterRedirect = () => {
const OAuth$getDataAfterRedirect = () => {
const migrationData = Reload._migrationData('oauth');

if (! (migrationData && migrationData.credentialToken))
return null;

const { credentialToken } = migrationData;
const key = OAuth._storageTokenPrefix + credentialToken;
const key = OAuth$_storageTokenPrefix + credentialToken;
let credentialSecret;
try {
credentialSecret = sessionStorage.getItem(key);
Expand Down Expand Up @@ -110,16 +107,16 @@ OAuth.getDataAfterRedirect = () => {
// is closed and we have the credential from the login service.
// credentialToken: our identifier for this login flow.
//
OAuth.launchLogin = options => {
const OAuth$launchLogin = options => {
if (! options.loginService)
throw new Error('loginService required');
if (options.loginStyle === 'popup') {
OAuth.showPopup(
OAuth$showPopup(
options.loginUrl,
options.credentialRequestCompleteCallback.bind(null, options.credentialToken),
options.popupOptions);
} else if (options.loginStyle === 'redirect') {
OAuth.saveDataForRedirect(options.loginService, options.credentialToken);
OAuth$saveDataForRedirect(options.loginService, options.credentialToken);
window.location = options.loginUrl;
} else {
throw new Error('invalid login style');
Expand All @@ -128,7 +125,7 @@ OAuth.launchLogin = options => {

// Called by the popup when the OAuth flow is completed, right before
// the popup closes.
OAuth._handleCredentialSecret = (credentialToken, secret) => {
const OAuth$_handleCredentialSecret = (credentialToken, secret) => {
check(credentialToken, String);
check(secret, String);
if (! Object.prototype.hasOwnProperty.call(credentialSecrets, credentialToken)) {
Expand All @@ -140,17 +137,30 @@ OAuth._handleCredentialSecret = (credentialToken, secret) => {

// Used by accounts-oauth, which needs both a credentialToken and the
// corresponding to credential secret to call the `login` method over DDP.
OAuth._retrieveCredentialSecret = credentialToken => {
const OAuth$_retrieveCredentialSecret = credentialToken => {
// First check the secrets collected by OAuth._handleCredentialSecret,
// then check localStorage. This matches what we do in
// end_of_login_response.html.
let secret = credentialSecrets[credentialToken];
if (! secret) {
const localStorageKey = OAuth._storageTokenPrefix + credentialToken;
const localStorageKey = OAuth$_storageTokenPrefix + credentialToken;
secret = Meteor._localStorage.getItem(localStorageKey);
Meteor._localStorage.removeItem(localStorageKey);
} else {
delete credentialSecrets[credentialToken];
}
return secret;
};

export {
OAuth$showPopup as showPopup,
OAuth$_loginStyle as _loginStyle,
OAuth$_stateParam as _stateParam,
OAuth$saveDataForRedirect as saveDataForRedirect,
OAuth$getDataAfterRedirect as getDataAfterRedirect,
OAuth$launchLogin as launchLogin,
OAuth$_handleCredentialSecret as _handleCredentialSecret,
OAuth$_retrieveCredentialSecret as _retrieveCredentialSecret,
OAuth$_storageTokenPrefix as _storageTokenPrefix,
OAuth$_redirectUri as _redirectUri,
}
4 changes: 2 additions & 2 deletions packages/oauth/oauth_common.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { constructUrl } from 'meteor/url';

OAuth._storageTokenPrefix = "Meteor.oauth.credentialSecret-";
export const OAuth$_storageTokenPrefix = "Meteor.oauth.credentialSecret-";

OAuth._redirectUri = (serviceName, config, params, absoluteUrlOptions) => {
export const OAuth$_redirectUri = (serviceName, config, params, absoluteUrlOptions) => {
// Clone because we're going to mutate 'params'. The 'cordova' and
// 'android' parameters are only used for picking the host of the
// redirect URL, and not actually included in the redirect URL itself.
Expand Down
Loading

0 comments on commit 35b09e7

Please sign in to comment.