Skip to content

Commit

Permalink
drop tutanota support: code
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimiry committed Dec 19, 2019
1 parent 4835ab1 commit 1103391
Show file tree
Hide file tree
Showing 58 changed files with 49 additions and 1,915 deletions.
4 changes: 0 additions & 4 deletions src/e2e/index.spec.ts
Expand Up @@ -40,10 +40,6 @@ test.serial("general actions: app start, master password setup, add accounts, lo
type: "protonmail",
entryUrlValue: `${ACCOUNTS_CONFIG_ENTRY_URL_LOCAL_PREFIX}https://protonirockerxow.onion`,
});
await workflow.addAccount({
type: "tutanota",
entryUrlValue: `${ACCOUNTS_CONFIG_ENTRY_URL_LOCAL_PREFIX}https://mail.tutanota.com`,
});
await workflow.logout();

// login with password saving
Expand Down
16 changes: 2 additions & 14 deletions src/e2e/unread.spec.disabled.ts
Expand Up @@ -5,19 +5,14 @@
// tslint:disable:await-promise

import {AccountTypeAndLoginFieldContainer} from "src/shared/model/container";
import {CI, accountBadgeCssSelector, initApp, test} from "./workflow";
import {ONE_SECOND_MS} from "src/shared/constants";
import {accountBadgeCssSelector, initApp, test} from "./workflow";

// protonmail account to login during e2e tests running
const RUNTIME_ENV_E2E_PROTONMAIL_LOGIN = `ELECTRON_MAIL_E2E_PROTONMAIL_LOGIN`;
const RUNTIME_ENV_E2E_PROTONMAIL_PASSWORD = `ELECTRON_MAIL_E2E_PROTONMAIL_PASSWORD`;
const RUNTIME_ENV_E2E_PROTONMAIL_2FA_CODE = `ELECTRON_MAIL_E2E_PROTONMAIL_2FA_CODE`;
const RUNTIME_ENV_E2E_PROTONMAIL_UNREAD_MIN = `ELECTRON_MAIL_E2E_PROTONMAIL_UNREAD_MIN`;
// tutanota account to login during e2e tests running
const RUNTIME_ENV_E2E_TUTANOTA_LOGIN = `ELECTRON_MAIL_E2E_TUTANOTA_LOGIN`;
const RUNTIME_ENV_E2E_TUTANOTA_PASSWORD = `ELECTRON_MAIL_E2E_TUTANOTA_PASSWORD`;
const RUNTIME_ENV_E2E_TUTANOTA_2FA_CODE = `ELECTRON_MAIL_E2E_TUTANOTA_2FA_CODE`;
const RUNTIME_ENV_E2E_TUTANOTA_UNREAD_MIN = `ELECTRON_MAIL_E2E_TUTANOTA_UNREAD_MIN`;

for (const {type, login, password, twoFactorCode, unread} of ([
{
Expand All @@ -27,21 +22,14 @@ for (const {type, login, password, twoFactorCode, unread} of ([
twoFactorCode: process.env[RUNTIME_ENV_E2E_PROTONMAIL_2FA_CODE],
unread: Number(process.env[RUNTIME_ENV_E2E_PROTONMAIL_UNREAD_MIN]),
},
{
type: "tutanota",
login: process.env[RUNTIME_ENV_E2E_TUTANOTA_LOGIN],
password: process.env[RUNTIME_ENV_E2E_TUTANOTA_PASSWORD],
twoFactorCode: process.env[RUNTIME_ENV_E2E_TUTANOTA_2FA_CODE],
unread: Number(process.env[RUNTIME_ENV_E2E_TUTANOTA_UNREAD_MIN]),
},
] as Array<AccountTypeAndLoginFieldContainer & { password: string, twoFactorCode: string, unread: number }>)) {
if (!login || !password || !unread || isNaN(unread)) {
continue;
}

test.serial(`unread check: ${type}`, async (t) => {
const workflow = await initApp(t, {initial: true});
const pauseMs = ONE_SECOND_MS * (type === "tutanota" ? (CI ? 80 : 40) : 20);
const pauseMs = ONE_SECOND_MS * 20;
const unreadBadgeSelector = accountBadgeCssSelector();
const state: { parsedUnreadText?: string } = {};

Expand Down
10 changes: 1 addition & 9 deletions src/e2e/workflow.ts
Expand Up @@ -279,14 +279,6 @@ function buildWorkflow(t: ExecutionContext<TestContext>) {
await client.waitForVisible(selector = `#goToAccountsSettingsLink`);
await workflow._click(selector);

// required: type
await client.waitForVisible(selector = `#accountEditFormTypeField .ng-select-container`);
await workflow._mousedown(selector);

await client.waitForVisible(selector = `[type-option-value="${account.type}"`);
await workflow._click(selector = `[type-option-value="${account.type}"`);
await client.pause(CONF.timeouts.elementTouched);

// required: entryUrl
await client.waitForVisible(selector = `#accountEditFormEntryUrlField .ng-select-container`);
await workflow._mousedown(selector);
Expand All @@ -313,7 +305,7 @@ function buildWorkflow(t: ExecutionContext<TestContext>) {

// account got added to the settings modal account list
await (async () => {
selector = `.modal-body electron-mail-type-symbol ~ .d-inline-block > span[data-login='${login}']`;
selector = `.modal-body .d-inline-block > span[data-login='${login}']`;
const timeout = CONF.timeouts.encryption;
try {
await t.context.app.client.waitForVisible(selector, timeout);
Expand Down
Expand Up @@ -98,10 +98,6 @@ export const FOLDER_UTILS: {
})();

function resolveAccountConversationNodes<T extends keyof FsDb["accounts"]>(account: FsDbAccount<T>): ConversationEntry[] {
if (account.metadata.type === "tutanota") {
return Object.values(account.conversationEntries);
}

const buildEntry = ({pk, mailPk}: Pick<ConversationEntry, "pk" | "mailPk">) => ({
pk,
id: pk,
Expand Down
18 changes: 3 additions & 15 deletions src/electron-main/api/index.spec.ts
Expand Up @@ -147,7 +147,7 @@ const tests: Record<keyof IpcMainApiEndpoints, (t: ExecutionContext<TestContext>
const {endpoints} = t.context;
const {addAccount, removeAccount} = endpoints;
const addProtonPayload = buildProtonmailAccountData();
const addTutanotaPayload = buildTutanotaAccountData();
const addProtonPayload2 = buildProtonmailAccountData();
const removePayload = {login: addProtonPayload.login};
const removePayload404 = {login: "404 login"};

Expand All @@ -160,7 +160,7 @@ const tests: Record<keyof IpcMainApiEndpoints, (t: ExecutionContext<TestContext>
}

await addAccount(addProtonPayload);
await addAccount(addTutanotaPayload);
await addAccount(addProtonPayload2);

const expectedSettings = produce(await t.context.ctx.settingsStore.readExisting(), (draft) => {
(draft._rev as number)++;
Expand All @@ -181,7 +181,7 @@ const tests: Record<keyof IpcMainApiEndpoints, (t: ExecutionContext<TestContext>

await addAccount(buildProtonmailAccountData());
await addAccount(buildProtonmailAccountData());
let settings = await addAccount(buildTutanotaAccountData());
let settings = await addAccount(buildProtonmailAccountData());

await t.throwsAsync(changeAccountOrder({login: "login.404", index: 0}));
await t.throwsAsync(changeAccountOrder({login: settings.accounts[0].login, index: -1}));
Expand Down Expand Up @@ -729,15 +729,3 @@ function buildProtonmailAccountData(): Readonly<AccountConfigCreatePatch<"proton
},
};
}

function buildTutanotaAccountData(): Readonly<AccountConfigCreatePatch<"tutanota">> {
return {
type: "tutanota",
login: generateRandomString(),
entryUrl: generateRandomString(),
credentials: {
password: generateRandomString(),
twoFactorCode: generateRandomString(),
},
};
}
16 changes: 14 additions & 2 deletions src/electron-main/context.spec.ts
Expand Up @@ -4,6 +4,8 @@ import sinon from "sinon";
import test from "ava";
import {Fs} from "fs-json-store";

import {PACKAGE_NAME, PACKAGE_VERSION} from "src/shared/constants";

const ctxDbProps = [
"db",
"sessionDb",
Expand All @@ -24,7 +26,11 @@ ctxDbProps.forEach((ctxDbProp) => {
() => import("./context"),
(mock) => {
mock(() => import("electron")).with({
app: {getPath: sinon.stub().returns(memFsPath)},
app: {
getPath: sinon.stub().returns(memFsPath),
getName: () => PACKAGE_NAME,
getVersion: () => PACKAGE_VERSION,
},
} as any);
mock(() => import("./constants")).callThrough();
},
Expand Down Expand Up @@ -75,7 +81,11 @@ ctxDbProps.forEach((ctxDbProp) => {
() => import("./context"),
(mock) => {
mock(() => import("electron")).with({
app: {getPath: sinon.stub().returns(memFsPath)},
app: {
getPath: sinon.stub().returns(memFsPath),
getName: () => PACKAGE_NAME,
getVersion: () => PACKAGE_VERSION,
},
} as any);
mock(() => import("./constants")).callThrough().with({
INITIAL_STORES: {
Expand Down Expand Up @@ -105,6 +115,8 @@ ctxDbProps.forEach((ctxDbProp) => {
.callsArg(1)
.withArgs("ready")
.callsArgWith(1, {}, {on: sinon.spy()}),
getName: () => PACKAGE_NAME,
getVersion: () => PACKAGE_VERSION,
},
} as any);
mock(() => import("src/electron-main/api/endpoints-builders")).callThrough().with({
Expand Down
2 changes: 0 additions & 2 deletions src/electron-main/context.ts
Expand Up @@ -184,7 +184,6 @@ function initLocations(
fullTextSearchBrowserWindow: appRelativePath("./electron-preload/database-indexer.js"),
webView: {
protonmail: formatFileUrl(appRelativePath("./electron-preload/webview/protonmail.js")),
tutanota: formatFileUrl(appRelativePath("./electron-preload/webview/tutanota.js")),
},
},
vendorsAppCssLinkHref: (() => {
Expand All @@ -201,7 +200,6 @@ function initLocations(
protocolBundles: [],
webClients: {
protonmail: [],
tutanota: [],
},
};

Expand Down
18 changes: 9 additions & 9 deletions src/electron-main/database/index.spec.ts
Expand Up @@ -47,8 +47,8 @@ test.serial(`save to file call should write through the "EncryptionAdapter.proto
const db = new databaseModule.Database(options, fileFs);

const folderStub = buildFolder();
db.initAccount({type: "tutanota", login: "login1"})
.folders[folderStub.pk] = await validateEntity("folders", folderStub, "tutanota");
db.initAccount({type: "protonmail", login: "login1"})
.folders[folderStub.pk] = await validateEntity("folders", folderStub, "protonmail");

t.false(encryptionAdapterWriteSpy.called);

Expand Down Expand Up @@ -86,8 +86,8 @@ test.serial(`save to file call should write through the "SerializationAdapter.wr
const db = new databaseModule.Database(options, fileFs);

const folderStub = buildFolder();
db.initAccount({type: "tutanota", login: "login1"})
.folders[folderStub.pk] = await validateEntity("folders", folderStub, "tutanota");
db.initAccount({type: "protonmail", login: "login1"})
.folders[folderStub.pk] = await validateEntity("folders", folderStub, "protonmail");

const dump = JSON.parse(JSON.stringify(db.readonlyDbInstance()));

Expand Down Expand Up @@ -117,8 +117,8 @@ test.serial(`save to file call should write through the "SerializationAdapter.wr
test("several sequence save calls should persist the same data", async (t) => {
const db = buildDatabase();
const folderStub = buildFolder();
db.initAccount({type: "tutanota", login: "login1"})
.folders[folderStub.pk] = await validateEntity("folders", folderStub, "tutanota");
db.initAccount({type: "protonmail", login: "login1"})
.folders[folderStub.pk] = await validateEntity("folders", folderStub, "protonmail");

await db.saveToFile();
await db.loadFromFile();
Expand All @@ -138,7 +138,7 @@ test("getting nonexistent account should initialize its content", async (t) => {
const db = buildDatabase();
await db.saveToFile();
const readonlyDbInstanceDump1 = JSON.parse(JSON.stringify(db.readonlyDbInstance()));
db.initAccount({type: "tutanota", login: "login1"});
db.initAccount({type: "protonmail", login: "login1"});
await db.saveToFile();
const readonlyDbInstanceDump12 = JSON.parse(JSON.stringify(db.readonlyDbInstance()));
t.truthy(readonlyDbInstanceDump1);
Expand Down Expand Up @@ -171,8 +171,8 @@ test("reset", async (t) => {

t.deepEqual(JSON.parse(JSON.stringify(db.readonlyDbInstance())), initial);
const folderStub = buildFolder();
db.initAccount({type: "tutanota", login: "login1"})
.folders[folderStub.pk] = await validateEntity("folders", folderStub, "tutanota");
db.initAccount({type: "protonmail", login: "login1"})
.folders[folderStub.pk] = await validateEntity("folders", folderStub, "protonmail");

t.notDeepEqual(JSON.parse(JSON.stringify(db.readonlyDbInstance())), initial);

Expand Down
3 changes: 1 addition & 2 deletions src/electron-main/database/index.ts
Expand Up @@ -18,13 +18,12 @@ export class Database {
static buildEmptyDb(): FsDb {
return {
version: DATABASE_VERSION,
accounts: {tutanota: {}, protonmail: {}},
accounts: {protonmail: {}},
};
}

static buildEmptyAccountMetadata<T extends keyof FsDb["accounts"]>(type: T): FsDbAccount<T>["metadata"] {
const metadata: { [key in keyof FsDb["accounts"]]: FsDbAccount<key>["metadata"] } = {
tutanota: {type: "tutanota", groupEntityEventBatchIds: {}},
protonmail: {type: "protonmail", latestEventId: ""},
};
return metadata[type];
Expand Down
3 changes: 1 addition & 2 deletions src/electron-main/database/util.ts
Expand Up @@ -29,7 +29,6 @@ export const resolveAccountFolders: <T extends keyof FsDb["accounts"]>(account:
name: PROTONMAIL_MAILBOX_IDENTIFIERS._.resolveNameByValue(id as any),
mailFolderId: id,
})),
tutanota: [],
};

const result: typeof resolveAccountFolders = (account) => [
Expand All @@ -44,7 +43,7 @@ export const resolveAccountFolders: <T extends keyof FsDb["accounts"]>(account:
export function patchMetadata(
target: FsDbAccount["metadata"],
// TODO TS: use patch: Arguments<IpcMainApiEndpoints["dbPatch"]>[0]["metadata"],
source: Skip<FsDbAccount<"protonmail">["metadata"], "type"> | Skip<FsDbAccount<"tutanota">["metadata"], "type">,
source: Skip<FsDbAccount<"protonmail">["metadata"], "type">,
sourceType: "dbPatch" | "loadDatabase",
): boolean {
const logPrefix = `patchMetadata() ${sourceType}`;
Expand Down
38 changes: 4 additions & 34 deletions src/electron-main/web-request.ts
Expand Up @@ -43,13 +43,11 @@ export function initWebRequestListeners(ctx: Context, session: Session) {
const resolveProxy: (details: RequestDetails) => RequestProxy | null = (() => {
const origins: { [k in AccountType]: string[] } = {
...resolveLocalWebClientOrigins("protonmail", ctx.locations),
...resolveLocalWebClientOrigins("tutanota", ctx.locations),
};

return (details: RequestDetails) => {
const proxies: { [k in AccountType]: ReturnType<typeof resolveRequestProxy> } = {
protonmail: resolveRequestProxy("protonmail", details, origins),
tutanota: resolveRequestProxy("tutanota", details, origins),
};
const [accountType] = Object.entries(proxies)
.filter((([, value]) => Boolean(value)))
Expand All @@ -73,7 +71,7 @@ export function initWebRequestListeners(ctx: Context, session: Session) {

if (requestProxy) {
const {name} = getHeader(requestHeaders, HEADERS.request.origin) || {name: HEADERS.request.origin};
requestHeaders[name] = resolveFakeOrigin(requestProxy.accountType, requestDetails);
requestHeaders[name] = resolveFakeOrigin(requestDetails);
PROXIES.set(requestDetails.id, requestProxy);
}

Expand All @@ -97,14 +95,8 @@ export function initWebRequestListeners(ctx: Context, session: Session) {
);
}

function resolveFakeOrigin(accountType: AccountType, requestDetails: RequestDetails): string {
if (accountType === "tutanota") {
// WARN: tutanota responds to the specific origins only
// it will not work for example with http://localhost:2015 origin, so they go with a whitelisting
return "http://localhost:9000";
}

// protonmail doesn't care much, so we generate the origin from request
function resolveFakeOrigin(requestDetails: RequestDetails): string {
// protonmail doesn't care much about "origin" value, so we generate the origin from request
return buildOrigin(new URL(requestDetails.url));
}

Expand Down Expand Up @@ -151,7 +143,7 @@ function resolveRequestProxy<T extends AccountType>(
: null;
}

// TODO consider doing initial preflight/OPTIONS call to https://mail.protonmail.com / https://mail.tutanota.com
// TODO consider doing initial preflight/OPTIONS call to https://mail.protonmail.com
// and then pick all the "Access-Control-*" header names as a template instead of hardcoding the default headers
// since over time the server may start giving other headers
const responseHeadersPatchHandlers: {
Expand Down Expand Up @@ -232,28 +224,6 @@ const responseHeadersPatchHandlers: {
},
);

return responseHeaders;
},
tutanota: ({requestProxy, responseDetails}) => {
const {responseHeaders} = responseDetails;

commonPatch({requestProxy, responseDetails});

patchResponseHeader(
responseHeaders,
{
name: HEADERS.response.accessControlAllowHeaders,
values: [
...(requestProxy.headers.accessControlRequestHeaders || {
values: [
"content-type",
"v",
],
}).values,
],
},
);

return responseHeaders;
},
};
Expand Down
2 changes: 0 additions & 2 deletions src/electron-preload/electron-exposure/index.ts
Expand Up @@ -3,15 +3,13 @@ import {IPC_MAIN_API} from "src/shared/api/main";
import {LOGGER} from "./logger";
import {PROTONMAIL_IPC_WEBVIEW_API} from "src/shared/api/webview/protonmail";
import {ROLLING_RATE_LIMITER} from "src/electron-preload/electron-exposure/rolling-rate-limiter";
import {TUTANOTA_IPC_WEBVIEW_API} from "src/shared/api/webview/tutanota";
import {registerDocumentClickEventListener} from "src/electron-preload/events-handling";

export const ELECTRON_WINDOW: Readonly<ElectronWindow> = Object.freeze({
__ELECTRON_EXPOSURE__: Object.freeze({
buildIpcMainClient: IPC_MAIN_API.client.bind(IPC_MAIN_API),
buildIpcWebViewClient: Object.freeze({
protonmail: PROTONMAIL_IPC_WEBVIEW_API.client,
tutanota: TUTANOTA_IPC_WEBVIEW_API.client,
}),
registerDocumentClickEventListener,
rollingRateLimiter: ROLLING_RATE_LIMITER,
Expand Down
1 change: 0 additions & 1 deletion src/electron-preload/webview/constants.ts
Expand Up @@ -7,6 +7,5 @@ export const NOTIFICATION_LOGGED_IN_POLLING_INTERVAL = ONE_SECOND_MS;
export const NOTIFICATION_PAGE_TYPE_POLLING_INTERVAL = ONE_SECOND_MS * 1.5;

export const WEBVIEW_LOGGERS: Record<AccountType, ReturnType<typeof buildLoggerBundle>> = {
tutanota: buildLoggerBundle("[WEBVIEW:tutanota]"),
protonmail: buildLoggerBundle("[WEBVIEW:protonmail]"),
};

0 comments on commit 1103391

Please sign in to comment.