Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IMPROVE] Support for Google OAuth for mobile app #22014

Merged
merged 2 commits into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions app/google-oauth/server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Meteor } from 'meteor/meteor';
import { OAuth } from 'meteor/oauth';

// The code on this file was copied directly from Meteor and modified to support mobile google oauth
// https://github.com/meteor/meteor/blob/ffcfa5062cf1bf8a64ea64fef681ffcd99fe7939/packages/oauth/oauth_server.js

Meteor.startup(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any special reason to have this in a Meteor.startup? Otherwise I'd remove it.

const appRedirectUrl = 'rocketchat://auth';

const renderEndOfLoginResponse = (options) => {
const escape = (s) => {
if (!s) {
return s;
}

return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\'/g, '&quot;').replace(/\'/g, '&#x27;').replace(/\//g, '&#x2F;');
};

const config = {
setCredentialToken: !! options.setCredentialToken,
credentialToken: escape(options.credentialToken),
credentialSecret: escape(options.credentialSecret),
storagePrefix: escape(OAuth._storageTokenPrefix),
redirectUrl: escape(options.redirectUrl),
isCordova: !! options.isCordova,
};

let template;
if (options.loginStyle === 'popup') {
template = OAuth._endOfPopupResponseTemplate;
} else if (options.loginStyle === 'redirect') {
template = OAuth._endOfRedirectResponseTemplate;
} else {
throw new Error(`invalid loginStyle: ${ options.loginStyle }`);
}

const result = template.replace(/##CONFIG##/, JSON.stringify(config)).replace(/##ROOT_URL_PATH_PREFIX##/, __meteor_runtime_config__.ROOT_URL_PATH_PREFIX);

return `<!DOCTYPE html>\n${ result }`;
};

OAuth._endOfLoginResponse = (res, details) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
let redirectUrl;

if (details.loginStyle === 'redirect') {
redirectUrl = OAuth._stateFromQuery(details.query).redirectUrl;
const appHost = Meteor.absoluteUrl();

if (redirectUrl.startsWith(appRedirectUrl)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might need to think a way to have this custom code easier to spot and maintain. Let's say on next Meteor version this code changes and we need to copy the new code over here, it might be not that easy to spot our changes and keep them.

redirectUrl = `${ appRedirectUrl }?host=${ appHost }&type=oauth`;

if (details.error) {
const error = encodeURIComponent(details.error.toString());
redirectUrl = `${ redirectUrl }&error=${ error }`;
}

if (details.credentials) {
const { token, secret } = details.credentials;
redirectUrl = `${ redirectUrl }&credentialToken=${ token }&credentialSecret=${ secret }`;
}
} else if (!Meteor.settings?.packages?.oauth?.disableCheckRedirectUrlOrigin && OAuth._checkRedirectUrlOrigin(redirectUrl)) {
details.error = `redirectUrl (${ redirectUrl }) is not on the same host as the app (${ appHost })`;
redirectUrl = appHost;
}
}

const isCordova = OAuth._isCordovaFromQuery(details.query);

if (details.error) {
res.end(renderEndOfLoginResponse({
loginStyle: details.loginStyle,
setCredentialToken: false,
redirectUrl,
isCordova,
}), 'utf-8');
return;
}

// If we have a credentialSecret, report it back to the parent
// window, with the corresponding credentialToken. The parent window
// uses the credentialToken and credentialSecret to log in over DDP.
res.end(renderEndOfLoginResponse({
loginStyle: details.loginStyle,
setCredentialToken: true,
credentialToken: details.credentials.token,
credentialSecret: details.credentials.secret,
redirectUrl,
isCordova,
}), 'utf-8');
};
});
1 change: 1 addition & 0 deletions server/importPackages.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import '../app/file';
import '../app/file-upload';
import '../app/github-enterprise/server';
import '../app/gitlab/server';
import '../app/google-oauth/server';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not create new things inside /app folder. we need to think where this file would fit in a new folder structure.

since this is overwriting Meteor's internal functions, maybe we could make that explicit making it easier to spot possible issues when updating Meteor.. maybe something like /server/overwrites/meteor/oauth.js .. idk, didn't like "overwrites" 🙈 wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about /server/custom/...

import '../app/google-vision/server';
import '../app/iframe-login/server';
import '../app/importer/server';
Expand Down