mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-20 23:36:21 +08:00
Switch to a “Desktop” Google Client ID to satisfy new security rules
This commit is contained in:
parent
e24c433b55
commit
ad30bcf641
|
@ -6,7 +6,7 @@ import http from 'http';
|
|||
import url from 'url';
|
||||
|
||||
import FormErrorMessage from './form-error-message';
|
||||
import { LOCAL_SERVER_PORT } from './onboarding-helpers';
|
||||
import { LOCAL_SERVER_PORT } from './onboarding-constants';
|
||||
import AccountProviders from './account-providers';
|
||||
|
||||
interface OAuthSignInPageProps {
|
||||
|
@ -14,7 +14,7 @@ interface OAuthSignInPageProps {
|
|||
buildAccountFromAuthResponse: (rep: any) => Account | Promise<Account>;
|
||||
onSuccess: (account: Account) => void;
|
||||
onTryAgain: () => void;
|
||||
providerConfig: (typeof AccountProviders)[0];
|
||||
providerConfig: typeof AccountProviders[0];
|
||||
serviceName: string;
|
||||
}
|
||||
|
||||
|
|
66
app/internal_packages/onboarding/lib/onboarding-constants.ts
Normal file
66
app/internal_packages/onboarding/lib/onboarding-constants.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import crypto from 'crypto';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
|
||||
export const LOCAL_SERVER_PORT = 12141;
|
||||
|
||||
export const GMAIL_CLIENT_ID =
|
||||
process.env.MS_GMAIL_CLIENT_ID ||
|
||||
'662287800555-pdiq3r3puob8a44locitndbocua7c30f.apps.googleusercontent.com';
|
||||
|
||||
// per https://stackoverflow.com/questions/59416326/safely-distribute-oauth-2-0-client-secret-in-desktop-applications-in-python,
|
||||
// we really do need to embed this in the application and it's more an extension of the Client ID than a proper Client Secret.
|
||||
//
|
||||
// We could run a small web app that receives the code and exchanges it for the refresh token (storing this on the server), but
|
||||
// that web flow would still hand the resulting client secret to the desktop app, whose authenticity it can't verify.
|
||||
// (It can verify the connection is secure, but not that the receiving party is /this/ copy of Mailspring.)
|
||||
//
|
||||
// Note: This is not a security risk for the end-user -- it just means someone could "fork" Mailspring and re-use it's
|
||||
// Client ID and Secret. For now, it seems we're on the honor code - Please don't do this.
|
||||
//
|
||||
export const GMAIL_CLIENT_SECRET = crypto
|
||||
.createDecipheriv(
|
||||
'aes-256-ctr',
|
||||
"don't-be-ev1l-thanks--mailspring",
|
||||
Buffer.from('wgvAx+N05nHqhFxJ9I07jw==', 'base64')
|
||||
)
|
||||
.update(Buffer.from('1EyEGYVh3NBNIbYEdpdMvOzCH7+vrSciGeYZ1F+W6W+yShk=', 'base64'))
|
||||
.toString('utf8');
|
||||
|
||||
export const GMAIL_SCOPES = [
|
||||
'https://mail.google.com/', // email
|
||||
'https://www.googleapis.com/auth/userinfo.email', // email address
|
||||
'https://www.googleapis.com/auth/userinfo.profile', // G+ profile
|
||||
'https://www.googleapis.com/auth/contacts', // contacts
|
||||
'https://www.googleapis.com/auth/calendar', // calendar
|
||||
];
|
||||
|
||||
export const O365_CLIENT_ID =
|
||||
process.env.MS_O365_CLIENT_ID || '8787a430-6eee-41e1-b914-681d90d35625';
|
||||
|
||||
export const O365_SCOPES = [
|
||||
'user.read', // email address
|
||||
'offline_access',
|
||||
'Contacts.ReadWrite', // contacts
|
||||
'Contacts.ReadWrite.Shared', // contacts
|
||||
'Calendars.ReadWrite', // calendar
|
||||
'Calendars.ReadWrite.Shared', // calendar
|
||||
|
||||
// Future note: When you exchange the refresh token for an access token, you may
|
||||
// request these two OR the above set but NOT BOTH, because Microsoft has mapped
|
||||
// two underlying systems with different tokens onto the single flow and you
|
||||
// need to get an outlook token and not a Micrsosoft Graph token to use these APIs.
|
||||
// https://stackoverflow.com/questions/61597263/
|
||||
'https://outlook.office.com/IMAP.AccessAsUser.All', // email
|
||||
'https://outlook.office.com/SMTP.Send', // email
|
||||
];
|
||||
|
||||
// Re-created only at onboarding page load / auth session start because storing
|
||||
// verifier would require additional state refactoring
|
||||
export const CODE_VERIFIER = uuidv4();
|
||||
export const CODE_CHALLENGE = crypto
|
||||
.createHash('sha256')
|
||||
.update(CODE_VERIFIER, 'utf8')
|
||||
.digest('base64')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=/g, '');
|
|
@ -2,56 +2,27 @@
|
|||
|
||||
import qs from 'querystring';
|
||||
import crypto from 'crypto';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
import { Account, AccountStore, IdentityStore, MailsyncProcess, localized } from 'mailspring-exports';
|
||||
import {
|
||||
Account,
|
||||
AccountStore,
|
||||
IdentityStore,
|
||||
MailsyncProcess,
|
||||
localized,
|
||||
} from 'mailspring-exports';
|
||||
import MailspringProviderSettings from './mailspring-provider-settings.json';
|
||||
import MailcoreProviderSettings from './mailcore-provider-settings.json';
|
||||
import dns from 'dns';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
export const LOCAL_SERVER_PORT = 12141;
|
||||
|
||||
const GMAIL_CLIENT_ID =
|
||||
process.env.MS_GMAIL_CLIENT_ID ||
|
||||
'662287800555-0a5h4ii0e9hsbpq0mqtul7fja0jhf9uf.apps.googleusercontent.com';
|
||||
|
||||
const O365_CLIENT_ID = process.env.MS_O365_CLIENT_ID || '8787a430-6eee-41e1-b914-681d90d35625';
|
||||
|
||||
const GMAIL_SCOPES = [
|
||||
'https://mail.google.com/', // email
|
||||
'https://www.googleapis.com/auth/userinfo.email', // email address
|
||||
'https://www.googleapis.com/auth/userinfo.profile', // G+ profile
|
||||
'https://www.googleapis.com/auth/contacts', // contacts
|
||||
'https://www.googleapis.com/auth/calendar', // calendar
|
||||
];
|
||||
|
||||
const O365_SCOPES = [
|
||||
'user.read', // email address
|
||||
'offline_access',
|
||||
'Contacts.ReadWrite', // contacts
|
||||
'Contacts.ReadWrite.Shared', // contacts
|
||||
'Calendars.ReadWrite', // calendar
|
||||
'Calendars.ReadWrite.Shared', // calendar
|
||||
|
||||
// Future note: When you exchange the refresh token for an access token, you may
|
||||
// request these two OR the above set but NOT BOTH, because Microsoft has mapped
|
||||
// two underlying systems with different tokens onto the single flow and you
|
||||
// need to get an outlook token and not a Micrsosoft Graph token to use these APIs.
|
||||
// https://stackoverflow.com/questions/61597263/
|
||||
'https://outlook.office.com/IMAP.AccessAsUser.All', // email
|
||||
'https://outlook.office.com/SMTP.Send', // email
|
||||
];
|
||||
|
||||
// Re-created only at onboarding page load / auth session start because storing
|
||||
// verifier would require additional state refactoring
|
||||
const CODE_VERIFIER = uuidv4();
|
||||
const CODE_CHALLENGE = crypto
|
||||
.createHash('sha256')
|
||||
.update(CODE_VERIFIER, 'utf8')
|
||||
.digest('base64')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=/g, '');
|
||||
import {
|
||||
GMAIL_CLIENT_ID,
|
||||
GMAIL_CLIENT_SECRET,
|
||||
LOCAL_SERVER_PORT,
|
||||
O365_SCOPES,
|
||||
O365_CLIENT_ID,
|
||||
CODE_VERIFIER,
|
||||
GMAIL_SCOPES,
|
||||
CODE_CHALLENGE,
|
||||
} from './onboarding-constants';
|
||||
|
||||
interface TokenResponse {
|
||||
access_token: string;
|
||||
|
@ -206,7 +177,11 @@ export async function expandAccountWithCommonSettings(account: Account) {
|
|||
// https://protonmail.com/support/knowledge-base/creating-folders/#comment-10460
|
||||
// on protonmail by default Folders set as container folder
|
||||
const containerFolderDefault = AccountStore.containerFolderDefaultGetter();
|
||||
if (containerFolderDefault !== 'Mailspring' && (populated.settings.container_folder === '' || populated.settings.container_folder === undefined)) {
|
||||
if (
|
||||
containerFolderDefault !== 'Mailspring' &&
|
||||
(populated.settings.container_folder === '' ||
|
||||
populated.settings.container_folder === undefined)
|
||||
) {
|
||||
populated.settings.container_folder = containerFolderDefault;
|
||||
}
|
||||
return populated;
|
||||
|
@ -219,6 +194,7 @@ export async function buildGmailAccountFromAuthResponse(code: string) {
|
|||
{
|
||||
code: code,
|
||||
client_id: GMAIL_CLIENT_ID,
|
||||
client_secret: GMAIL_CLIENT_SECRET,
|
||||
redirect_uri: `http://127.0.0.1:${LOCAL_SERVER_PORT}`,
|
||||
grant_type: 'authorization_code',
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ import fs from 'fs';
|
|||
import { localized } from './intl';
|
||||
import { IIdentity, Account } from 'mailspring-exports';
|
||||
|
||||
import {
|
||||
GMAIL_CLIENT_ID,
|
||||
GMAIL_CLIENT_SECRET,
|
||||
} from '../internal_packages/onboarding/lib/onboarding-constants';
|
||||
|
||||
let Utils = null;
|
||||
|
||||
export interface MailsyncProcessExit {
|
||||
|
@ -137,6 +142,8 @@ export class MailsyncProcess extends EventEmitter {
|
|||
_spawnProcess(mode) {
|
||||
const env = {
|
||||
CONFIG_DIR_PATH: this.configDirPath,
|
||||
GMAIL_CLIENT_ID: GMAIL_CLIENT_ID,
|
||||
GMAIL_CLIENT_SECRET: GMAIL_CLIENT_SECRET,
|
||||
IDENTITY_SERVER: 'unknown',
|
||||
};
|
||||
if (process.type === 'renderer') {
|
||||
|
|
|
@ -61,7 +61,8 @@ global.finishWithWindowCapture = (previewPath, startedAt = Date.now()) => {
|
|||
window.requestAnimationFrame(() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
const win = const { BrowserWindow } = require('@electron/remote').getCurrentWindow();
|
||||
const { BrowserWindow } = require('@electron/remote');
|
||||
const win = BrowserWindow.getCurrentWindow();
|
||||
win.capturePage(img => {
|
||||
fs.writeFileSync(previewPath, img.toPNG());
|
||||
document.title = 'Finished';
|
||||
|
|
2
mailsync
2
mailsync
|
@ -1 +1 @@
|
|||
Subproject commit 59366b938347b0ce67a43237cd164eb6e6e68d3a
|
||||
Subproject commit fb0bcb32decaf523ab8547dc7546b32d6d1962c0
|
Loading…
Reference in a new issue