mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-03-06 13:03:10 +08:00
Stop syncing email account credentials to the cloud
This commit is contained in:
parent
30885be8e4
commit
44b00cbbf5
9 changed files with 45 additions and 52 deletions
|
@ -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', {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 = ' '
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
2
mailsync
2
mailsync
|
@ -1 +1 @@
|
|||
Subproject commit e3aa42eadbf0ae6606ee28167f0505d4715731fa
|
||||
Subproject commit 542475dcecd4b8ef0e873b855460f71f0f82127c
|
Loading…
Reference in a new issue