diff --git a/app/internal_packages/onboarding/lib/decorators/create-page-for-form.jsx b/app/internal_packages/onboarding/lib/decorators/create-page-for-form.jsx index 9d174c166..85bd6b2e0 100644 --- a/app/internal_packages/onboarding/lib/decorators/create-page-for-form.jsx +++ b/app/internal_packages/onboarding/lib/decorators/create-page-for-form.jsx @@ -5,7 +5,7 @@ import {RetinaImg} from 'nylas-component-kit'; import {NylasAPIRequest, Actions} from 'nylas-exports'; import OnboardingActions from '../onboarding-actions'; -import {runAuthValidation} from '../onboarding-helpers'; +import {buildAndValidateAccount} from '../onboarding-helpers'; import FormErrorMessage from '../form-error-message'; import AccountTypes from '../account-types' @@ -99,10 +99,10 @@ const CreatePageForForm = (FormComponent) => { this.setState({submitting: true}); - runAuthValidation(accountInfo) - .then(({account, cloudToken}) => { + buildAndValidateAccount(accountInfo) + .then(({account}) => { OnboardingActions.moveToPage('account-onboarding-success') - OnboardingActions.accountJSONReceived(account, cloudToken) + OnboardingActions.accountJSONReceived(account) }) .catch((err) => { Actions.recordUserEvent('Email Account Auth Failed', { diff --git a/app/internal_packages/onboarding/lib/onboarding-helpers.es6 b/app/internal_packages/onboarding/lib/onboarding-helpers.es6 index a28173003..291b43c87 100644 --- a/app/internal_packages/onboarding/lib/onboarding-helpers.es6 +++ b/app/internal_packages/onboarding/lib/onboarding-helpers.es6 @@ -40,6 +40,21 @@ function base64url(inBuffer) { .replace(/\//g, '_'); // Convert '/' to '_' } +function idForAccount(emailAddress, connectionSettings) { + // changing your connection security settings / ports shouldn't blow + // away everything and trash your metadata. Just look at critiical fields. + // (Me adding more connection settings fields shouldn't break account Ids either!) + const settingsThatCouldChangeMailContents = { + imap_username: connectionSettings.imap_username, + imap_host: connectionSettings.imap_host, + smtp_username: connectionSettings.smtp_username, + smtp_host: connectionSettings.smtp_host, + } + + const idString = `${emailAddress}${JSON.stringify(settingsThatCouldChangeMailContents)}`; + return crypto.createHash('sha256').update(idString, 'utf8').digest('hex'); +} + export function makeGmailOAuthRequest(sessionKey) { return makeRequest({ server: 'accounts', @@ -54,20 +69,15 @@ export async function authIMAPForGmail(serverTokenResponse) { // created an account object in the database and tested it. All we // need to do is save it locally, since we're confident Gmail will be // accessible from the local sync worker. - const {id, email_address, provider, connection_settings, account_token, xoauth_refresh_token, name} = serverTokenResponse; + const {emailAddress, refreshToken} = serverTokenResponse; + const settings = expandAccountInfoWithCommonSettings({email: emailAddress, refreshToken, type: 'gmail'}); - // Todo: clean up the serialization so this translation from K2 JSON isn't necessary. return { - account: { - id, - provider, - name, - emailAddress: email_address, - settings: Object.assign({}, connection_settings, { - xoauth_refresh_token, - }), - }, - cloudToken: account_token, + id: idForAccount(emailAddress, settings), + provider: 'gmail', + name, + settings, + emailAddress, }; } @@ -79,11 +89,11 @@ export function buildGmailAuthURL(sessionKey) { return `${rootURLForServer('accounts')}/auth/gmail?state=${sessionKey}`; } -export async function runAuthValidation(accountInfo) { +export async function buildAndValidateAccount(accountInfo) { const {username, type, email, name} = accountInfo; const data = { - id: 'temp', + id: idForAccount(email, accountInfo), provider: type, name: name, emailAddress: email, @@ -114,21 +124,7 @@ export async function runAuthValidation(accountInfo) { const proc = new MailsyncProcess(NylasEnv.getLoadSettings(), IdentityStore.identity(), data); const {account} = await proc.test(); - delete data.id; - - const {id, account_token} = await makeRequest({ - server: 'accounts', - path: `/auth`, - method: 'POST', - timeout: 1000 * 180, // Same timeout as server timeout (most requests are faster than 90s, but server validation can be slow in some cases) - body: data, - auth: false, - }) - - return { - account: Object.assign({}, account, {id}), - cloudToken: account_token, - }; + return account; } export function isValidHost(value) { diff --git a/app/internal_packages/onboarding/lib/onboarding-store.es6 b/app/internal_packages/onboarding/lib/onboarding-store.es6 index 009ce5513..be8729e7b 100644 --- a/app/internal_packages/onboarding/lib/onboarding-store.es6 +++ b/app/internal_packages/onboarding/lib/onboarding-store.es6 @@ -139,10 +139,10 @@ class OnboardingStore extends NylasStore { }, 1000); } - _onAccountJSONReceived = async (json, cloudToken) => { + _onAccountJSONReceived = async (json) => { try { const isFirstAccount = AccountStore.accounts().length === 0; - AccountStore.addAccountFromJSON(json, cloudToken); + AccountStore.addAccountFromJSON(json); Actions.recordUserEvent('Email Account Auth Succeeded', { provider: json.provider, diff --git a/app/internal_packages/onboarding/lib/page-account-settings-gmail.jsx b/app/internal_packages/onboarding/lib/page-account-settings-gmail.jsx index 804dedfed..f5ecf3048 100644 --- a/app/internal_packages/onboarding/lib/page-account-settings-gmail.jsx +++ b/app/internal_packages/onboarding/lib/page-account-settings-gmail.jsx @@ -25,8 +25,8 @@ export default class AccountSettingsPageGmail extends React.Component { this._gmailAuthUrl = buildGmailAuthURL(this._sessionKey) } - onSuccess({account, cloudToken}) { - OnboardingActions.accountJSONReceived(account, cloudToken); + onSuccess(account) { + OnboardingActions.accountJSONReceived(account); } render() { diff --git a/app/src/components/webview.jsx b/app/src/components/webview.jsx index a42a57c79..f37b56646 100644 --- a/app/src/components/webview.jsx +++ b/app/src/components/webview.jsx @@ -5,6 +5,7 @@ import ReactDOM from 'react-dom' import classnames from 'classnames'; import networkErrors from 'chromium-net-errors'; +import {rootURLForServer} from '../flux/nylas-api-request'; import RetinaImg from './retina-img' class InitialLoadingCover extends React.Component { @@ -42,7 +43,7 @@ class InitialLoadingCover extends React.Component { if (this.props.error) { message = this.props.error; } else if (this.state.slow) { - message = "Still trying to reach id.getmailspring.com…"; + message = `Still trying to reach ${rootURLForServer('identity')}…`; } else { message = ' ' } diff --git a/app/src/flux/mailsync-bridge.es6 b/app/src/flux/mailsync-bridge.es6 index b37ba8d37..76fc87fde 100644 --- a/app/src/flux/mailsync-bridge.es6 +++ b/app/src/flux/mailsync-bridge.es6 @@ -85,8 +85,8 @@ class CrashTracker { }); } - _keyFor({id, settings, cloudToken}) { - return JSON.stringify({id, settings, cloudToken}); + _keyFor({id, settings}) { + return JSON.stringify({id, settings}); } _appendCrashToHistory(fullAccountJSON) { diff --git a/app/src/flux/stores/account-store.es6 b/app/src/flux/stores/account-store.es6 index 7cc4ad8e3..677d5d237 100644 --- a/app/src/flux/stores/account-store.es6 +++ b/app/src/flux/stores/account-store.es6 @@ -137,8 +137,7 @@ class AccountStore extends NylasStore { // the account is added, but we want to be on the safe side. delete a.settings.imap_password; delete a.settings.smtp_password; - delete a.settings.xoauth_refresh_token; - delete a.cloudToken; + delete a.settings.refresh_token; }); NylasEnv.config.set(configAccountsKey, configAccounts); NylasEnv.config.set(configVersionKey, this._version); @@ -204,14 +203,14 @@ class AccountStore extends NylasStore { this._save() } - addAccountFromJSON = (json, cloudToken) => { + addAccountFromJSON = (json) => { if (!json.emailAddress || !json.provider) { throw new Error(`Returned account data is invalid: ${JSON.stringify(json)}`) } // send the account JSON and cloud token to the KeyManager, // which gives us back a version with no secrets. - const cleanJSON = KeyManager.extractAccountSecrets(json, cloudToken); + const cleanJSON = KeyManager.extractAccountSecrets(json); this._loadAccounts(); diff --git a/app/src/key-manager.es6 b/app/src/key-manager.es6 index afad7e383..151cc014b 100644 --- a/app/src/key-manager.es6 +++ b/app/src/key-manager.es6 @@ -29,12 +29,11 @@ class KeyManager { delete keys[`${account.emailAddress}-imap`]; delete keys[`${account.emailAddress}-smtp`]; delete keys[`${account.emailAddress}-refresh-token`]; - delete keys[`${account.emailAddress}-cloud`]; return this._writeKeyHash(keys); }); } - extractAccountSecrets(accountJSON, cloudToken) { + extractAccountSecrets(accountJSON) { const next = Object.assign({}, accountJSON); this._try(() => { const keys = this._getKeyHash(); @@ -42,9 +41,8 @@ class KeyManager { delete next.settings.imap_password; keys[`${accountJSON.emailAddress}-smtp`] = next.settings.smtp_password; delete next.settings.smtp_password; - keys[`${accountJSON.emailAddress}-refresh-token`] = next.settings.xoauth_refresh_token; - delete next.settings.xoauth_refresh_token; - keys[`${accountJSON.emailAddress}-cloud`] = cloudToken; + keys[`${accountJSON.emailAddress}-refresh-token`] = next.settings.refresh_token; + delete next.settings.refresh_token; return this._writeKeyHash(keys); }); return next; @@ -55,8 +53,7 @@ class KeyManager { const keys = this._getKeyHash(); next.settings.imap_password = keys[`${accountJSON.emailAddress}-imap`]; next.settings.smtp_password = keys[`${accountJSON.emailAddress}-smtp`]; - next.settings.xoauth_refresh_token = keys[`${accountJSON.emailAddress}-refresh-token`]; - next.cloudToken = keys[`${accountJSON.emailAddress}-cloud`]; + next.settings.refresh_token = keys[`${accountJSON.emailAddress}-refresh-token`]; return next; } diff --git a/mailsync b/mailsync index e3aa42ead..542475dce 160000 --- a/mailsync +++ b/mailsync @@ -1 +1 @@ -Subproject commit e3aa42eadbf0ae6606ee28167f0505d4715731fa +Subproject commit 542475dcecd4b8ef0e873b855460f71f0f82127c