diff --git a/app/src/flux/stores/identity-store.ts b/app/src/flux/stores/identity-store.ts index aecebb65f..d79f0069d 100644 --- a/app/src/flux/stores/identity-store.ts +++ b/app/src/flux/stores/identity-store.ts @@ -10,7 +10,7 @@ import { makeRequest, rootURLForServer } from '../mailspring-api-request'; import { Disposable } from 'event-kit'; // Note this key name is used when migrating to Mailspring Pro accounts from old N1. -const KEYCHAIN_NAME = 'Mailspring Account'; +const PASSWORD_NAME = 'Mailspring Account'; export interface IIdentity { id: string; @@ -41,6 +41,7 @@ export const EMPTY_FEATURE_USAGE = { class _IdentityStore extends MailspringStore { _identity: IIdentity = null; + _displayedPasswordError = false; _disp: Disposable; constructor() { @@ -98,7 +99,7 @@ class _IdentityStore extends MailspringStore { async saveIdentity(identity: IIdentity | null) { if (!identity) { this._identity = null; - await KeyManager.deletePassword(KEYCHAIN_NAME); + await KeyManager.deletePassword(PASSWORD_NAME); AppEnv.config.set('identity', null); return; } @@ -114,7 +115,7 @@ class _IdentityStore extends MailspringStore { // Note: We /must/ await this because calling config.set below // will try to retrieve the password via getPassword. // If this fails, the app may quit here. - await KeyManager.replacePassword(KEYCHAIN_NAME, nextToken); + await KeyManager.replacePassword(PASSWORD_NAME, nextToken); } this._identity = identity; @@ -132,8 +133,20 @@ class _IdentityStore extends MailspringStore { _onIdentityChanged = async () => { const value = AppEnv.config.get('identity'); this._identity = value - ? { ...value, token: await KeyManager.getPassword(KEYCHAIN_NAME) } + ? { ...value, token: await KeyManager.getPassword(PASSWORD_NAME) } : null; + + if (this._identity && !this._identity.token) { + const message = `Your Mailspring ID password could not be loaded from your keychain. Please visit Preferences > Subscription and click "Setup Mailspring ID" to sign in to your Mailspring account again.\n\nYour Mailspring ID email address is ${this._identity.emailAddress}.`; + console.warn(message); + + if (!this._displayedPasswordError) { + this._displayedPasswordError = true; + AppEnv.showErrorDialog({ title: 'Please Sign In', message }); + } + this._identity = null; + } + this.trigger(); }; diff --git a/app/src/key-manager.ts b/app/src/key-manager.ts index f19cba403..4e0926b17 100644 --- a/app/src/key-manager.ts +++ b/app/src/key-manager.ts @@ -5,7 +5,7 @@ interface KeySet { [key: string]: string; } -const { safeStorage } = require("@electron/remote"); +const { safeStorage } = require('@electron/remote'); const configCredentialsKey = 'credentials'; @@ -18,7 +18,6 @@ const configCredentialsKey = 'credentials'; * and every key we want to access. */ class KeyManager { - async deleteAccountSecrets(account: Account) { try { const keys = await this._getKeyHash(); @@ -90,8 +89,17 @@ class KeyManager { let raw = '{}'; const encryptedCredentials = AppEnv.config.get(configCredentialsKey); // Check for different null values to prevent issues if a migration from keytar has failed - if (encryptedCredentials !== undefined && encryptedCredentials !== null && encryptedCredentials !== "null") { - raw = await safeStorage.decryptString(Buffer.from(encryptedCredentials, "utf-8")); + if ( + encryptedCredentials !== undefined && + encryptedCredentials !== null && + encryptedCredentials !== 'null' + ) { + try { + raw = await safeStorage.decryptString(Buffer.from(encryptedCredentials, 'utf-8')); + } catch (err) { + console.error('Mailspring encountered an error reading passwords from the keychain.'); + console.error(err); + } } try { return JSON.parse(raw) as KeySet; @@ -101,7 +109,7 @@ class KeyManager { } async _writeKeyHash(keys: KeySet) { - const enrcyptedCredentials = await safeStorage.encryptString(JSON.stringify(keys)) + const enrcyptedCredentials = await safeStorage.encryptString(JSON.stringify(keys)); AppEnv.config.set(configCredentialsKey, enrcyptedCredentials); } @@ -117,7 +125,7 @@ class KeyManager { if (clickedButton == 0) { const shell = require('electron').shell; - shell.openExternal("https://community.getmailspring.com/t/password-management-error/199") + shell.openExternal('https://community.getmailspring.com/t/password-management-error/199'); } // tell the app to exit and rethrow the error to ensure code relying