Skip to content

Commit

Permalink
issue #5747 refactor content scripts for Thunderbird (#5748)
Browse files Browse the repository at this point in the history
* issue 5747 initial refactor

* removed dated comment

* cleanup

* added a generic folder

* remove unused notifyMurdered parameter

* added comment

* upload debug artifacts

* remove verbose google-mock listening logs
  • Loading branch information
tomholub authored May 29, 2024
1 parent dd2cdb8 commit 6823435
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 245 deletions.
2 changes: 1 addition & 1 deletion .semaphore/semaphore.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
version: v1.0
name: Flowcrypt Node Core Tests
name: FlowCrypt Extension Tests
agent:
machine:
type: e2-standard-4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,37 @@
'use strict';

import Swal from 'sweetalert2';
import { AccountServer } from '../../common/api/account-server.js';
import { KeyManager } from '../../common/api/key-server/key-manager.js';
import { ApiErr, BackendAuthErr } from '../../common/api/shared/api-error.js';
import { BrowserMsgCommonHandlers } from '../../common/browser/browser-msg-common-handlers.js';
import { Bm, BrowserMsg, TabIdRequiredError } from '../../common/browser/browser-msg.js';
import { ContentScriptWindow } from '../../common/browser/browser-window.js';
import { Env, WebMailName } from '../../common/browser/env.js';
import { Time } from '../../common/browser/time.js';
import { CommonHandlers, Ui } from '../../common/browser/ui.js';
import { ClientConfiguration, ClientConfigurationError } from '../../common/client-configuration.js';
import { Str, Url } from '../../common/core/common.js';
import { InMemoryStoreKeys, VERSION } from '../../common/core/const.js';
import { getLocalKeyExpiration, processAndStoreKeysFromEkmLocally } from '../../common/helpers.js';
import { Injector } from '../../common/inject.js';
import { Lang } from '../../common/lang.js';
import { Notifications } from '../../common/notifications.js';
import { Catch } from '../../common/platform/catch.js';
import { AcctStore } from '../../common/platform/store/acct-store.js';
import { GlobalStore } from '../../common/platform/store/global-store.js';
import { InMemoryStore } from '../../common/platform/store/in-memory-store.js';
import { WebmailVariantString, XssSafeFactory } from '../../common/xss-safe-factory.js';
import { RelayManager } from '../../common/relay-manager.js';
import { AccountServer } from '../../../common/api/account-server.js';
import { KeyManager } from '../../../common/api/key-server/key-manager.js';
import { ApiErr, BackendAuthErr } from '../../../common/api/shared/api-error.js';
import { BrowserMsgCommonHandlers } from '../../../common/browser/browser-msg-common-handlers.js';
import { Bm, BrowserMsg, TabIdRequiredError } from '../../../common/browser/browser-msg.js';
import { ContentScriptWindow } from '../../../common/browser/browser-window.js';
import { Env, WebMailName } from '../../../common/browser/env.js';
import { Time } from '../../../common/browser/time.js';
import { CommonHandlers, Ui } from '../../../common/browser/ui.js';
import { ClientConfiguration, ClientConfigurationError } from '../../../common/client-configuration.js';
import { Str, Url } from '../../../common/core/common.js';
import { InMemoryStoreKeys, VERSION } from '../../../common/core/const.js';
import { getLocalKeyExpiration, processAndStoreKeysFromEkmLocally } from '../../../common/helpers.js';
import { Injector } from '../../../common/inject.js';
import { Lang } from '../../../common/lang.js';
import { Notifications } from '../../../common/notifications.js';
import { Catch } from '../../../common/platform/catch.js';
import { AcctStore } from '../../../common/platform/store/acct-store.js';
import { GlobalStore } from '../../../common/platform/store/global-store.js';
import { InMemoryStore } from '../../../common/platform/store/in-memory-store.js';
import { WebmailVariantString, XssSafeFactory } from '../../../common/xss-safe-factory.js';
import { RelayManager } from '../../../common/relay-manager.js';
import { WebmailElementReplacer } from './webmail-element-replacer.js';

export type WebmailVariantObject = {
newDataLayer: undefined | boolean;
newUi: undefined | boolean;
email: undefined | string;
gmailVariant: WebmailVariantString;
};
export type IntervalFunction = { interval: number; handler: () => void };

type WebmailSpecificInfo = {
name: WebMailName;
variant: WebmailVariantString;
Expand All @@ -45,17 +46,9 @@ type WebmailSpecificInfo = {
inject: Injector,
notifications: Notifications,
factory: XssSafeFactory,
notifyMurdered: () => void,
relayManager: RelayManager
) => Promise<void>;
};
export interface WebmailElementReplacer {
getIntervalFunctions: () => IntervalFunction[];
setReplyBoxEditable: () => Promise<void>;
reinsertReplyBox: (replyMsgId: string) => void;
scrollToReplyBox: (replyMsgId: string) => void;
scrollToCursorInReplyBox: (replyMsgId: string, cursorOffsetTop: number) => void;
}

const win = window as unknown as ContentScriptWindow;

Expand Down Expand Up @@ -275,23 +268,6 @@ export const contentScriptSetupIfVacant = async (webmailSpecific: WebmailSpecifi
}
};

const notifyMurdered = () => {
const notifEl = document.getElementsByClassName('webmail_notifications')[0];
const div = document.createElement('div');
div.innerText = 'FlowCrypt has updated, please reload the tab. ';
div.classList.add('webmail_notification');
const a = document.createElement('a');
a.href = '#';
a.onclick = function () {
const parent = (this as HTMLAnchorElement).parentNode as HTMLElement | undefined;
parent?.remove();
};
a.textContent = 'close';
div.appendChild(a);
notifEl.textContent = '';
notifEl.appendChild(div);
};

const showPassphraseDialog = async (factory: XssSafeFactory, { longids, type, initiatorFrameId }: Bm.PassphraseDialog) => {
await factory.showPassphraseDialog(longids, type, initiatorFrameId);
};
Expand Down Expand Up @@ -451,7 +427,7 @@ export const contentScriptSetupIfVacant = async (webmailSpecific: WebmailSpecifi
ppEvent,
Catch.try(() => notifyExpiringKeys(acctEmail, clientConfiguration, notifications))
);
await webmailSpecific.start(acctEmail, clientConfiguration, inject, notifications, factory, notifyMurdered, relayManager);
await webmailSpecific.start(acctEmail, clientConfiguration, inject, notifications, factory, relayManager);
} catch (e) {
if (e instanceof TabIdRequiredError) {
console.error(`FlowCrypt cannot start: ${String(e)}`);
Expand Down Expand Up @@ -527,3 +503,28 @@ export const contentScriptSetupIfVacant = async (webmailSpecific: WebmailSpecifi
}
}
};

/**
* This happens when Firefox (or possibly Thunderbird) just updated FlowCrypt.
*
* Previous (meaning this currently running) instance of FlowCrypt will no longer
* have access to its various classes or global variables, and is left in a
* semi-functioning state. The best we can do is to ask the user to reload
* the tab, which will load the newly updated version of the extension cleanly.
*/
export const notifyMurdered = () => {
const notifEl = document.getElementsByClassName('webmail_notifications')[0];
const div = document.createElement('div');
div.innerText = 'FlowCrypt has updated, please reload the tab. ';
div.classList.add('webmail_notification');
const a = document.createElement('a');
a.href = '#';
a.onclick = function () {
const parent = (this as HTMLAnchorElement).parentNode as HTMLElement | undefined;
parent?.remove();
};
a.textContent = 'close';
div.appendChild(a);
notifEl.textContent = '';
notifEl.appendChild(div);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* ©️ 2016 - present FlowCrypt a.s. Limitations apply. Contact [email protected] */

import { ContentScriptWindow } from '../../../common/browser/browser-window';
import { notifyMurdered } from './setup-webmail-content-script';

export type IntervalFunction = { interval: number; handler: () => void };

export abstract class WebmailElementReplacer {
private replacePgpElsInterval: number;

public abstract getIntervalFunctions: () => IntervalFunction[];
public abstract setReplyBoxEditable: () => Promise<void>;
public abstract reinsertReplyBox: (replyMsgId: string) => void;
public abstract scrollToReplyBox: (replyMsgId: string) => void;
public abstract scrollToCursorInReplyBox: (replyMsgId: string, cursorOffsetTop: number) => void;

public runIntervalFunctionsPeriodically = () => {
const intervalFunctions = this.getIntervalFunctions();
for (const intervalFunction of intervalFunctions) {
intervalFunction.handler();
this.replacePgpElsInterval = (window as unknown as ContentScriptWindow).TrySetDestroyableInterval(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (typeof (window as any).$ === 'function') {
intervalFunction.handler();
} else {
// firefox will unload jquery when extension is restarted or updated
clearInterval(this.replacePgpElsInterval);
notifyMurdered();
}
}, intervalFunction.interval);
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@

'use strict';

import { Dict, Str } from '../../common/core/common.js';
import { FactoryReplyParams, XssSafeFactory } from '../../common/xss-safe-factory.js';
import { IntervalFunction, WebmailElementReplacer } from './setup-webmail-content-script.js';
import { ApiErr } from '../../common/api/shared/api-error.js';
import { Attachment } from '../../common/core/attachment.js';
import { BrowserMsg } from '../../common/browser/browser-msg.js';
import { Catch } from '../../common/platform/catch.js';
import { GlobalStore, LocalDraft } from '../../common/platform/store/global-store.js';
import { Injector } from '../../common/inject.js';
import { PubLookup } from '../../common/api/pub-lookup.js';
import { Notifications } from '../../common/notifications.js';
import { PgpArmor } from '../../common/core/crypto/pgp/pgp-armor.js';
import { Ui } from '../../common/browser/ui.js';
import { WebmailCommon } from '../../common/webmail.js';
import { Xss } from '../../common/platform/xss.js';
import { ClientConfiguration } from '../../common/client-configuration.js';
import { Dict, Str } from '../../../common/core/common.js';
import { FactoryReplyParams, XssSafeFactory } from '../../../common/xss-safe-factory.js';
import { ApiErr } from '../../../common/api/shared/api-error.js';
import { Attachment } from '../../../common/core/attachment.js';
import { BrowserMsg } from '../../../common/browser/browser-msg.js';
import { Catch } from '../../../common/platform/catch.js';
import { GlobalStore, LocalDraft } from '../../../common/platform/store/global-store.js';
import { Injector } from '../../../common/inject.js';
import { PubLookup } from '../../../common/api/pub-lookup.js';
import { Notifications } from '../../../common/notifications.js';
import { PgpArmor } from '../../../common/core/crypto/pgp/pgp-armor.js';
import { Ui } from '../../../common/browser/ui.js';
import { WebmailCommon } from '../../../common/webmail.js';
import { Xss } from '../../../common/platform/xss.js';
import { ClientConfiguration } from '../../../common/client-configuration.js';
// todo: can we somehow define a purely relay class for ContactStore to clearly show that crypto-libraries are not loaded and can't be used?
import { ContactStore } from '../../common/platform/store/contact-store.js';
import { MessageRenderer } from '../../common/message-renderer.js';
import { RelayManager } from '../../common/relay-manager.js';
import { MessageInfo } from '../../common/render-message.js';
import { ContactStore } from '../../../common/platform/store/contact-store.js';
import { MessageRenderer } from '../../../common/message-renderer.js';
import { RelayManager } from '../../../common/relay-manager.js';
import { MessageInfo } from '../../../common/render-message.js';
import { GmailLoaderContext } from './gmail-loader-context.js';
import { JQueryEl } from '../../common/loader-context-interface.js';
import { MessageBody, Mime } from '../../common/core/mime.js';
import { MsgBlock } from '../../common/core/msg-block.js';
import { ReplyOption } from '../../../chrome/elements/compose-modules/compose-reply-btn-popover-module.js';
import { JQueryEl } from '../../../common/loader-context-interface.js';
import { MessageBody, Mime } from '../../../common/core/mime.js';
import { MsgBlock } from '../../../common/core/msg-block.js';
import { ReplyOption } from '../../../../chrome/elements/compose-modules/compose-reply-btn-popover-module.js';
import { WebmailElementReplacer, IntervalFunction } from '../generic/webmail-element-replacer.js';

export class GmailElementReplacer implements WebmailElementReplacer {
export class GmailElementReplacer extends WebmailElementReplacer {
private debug = false;

private recipientHasPgpCache: Dict<boolean> = {};
Expand Down Expand Up @@ -74,6 +74,7 @@ export class GmailElementReplacer implements WebmailElementReplacer {
private readonly notifications: Notifications,
private readonly relayManager: RelayManager
) {
super();
this.webmailCommon = new WebmailCommon(acctEmail, injector);
this.pubLookup = new PubLookup(clientConfiguration);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

'use strict';

import { Attachment } from '../../common/core/attachment.js';
import { JQueryEl, LoaderContextInterface } from '../../common/loader-context-interface.js';
import { XssSafeFactory } from '../../common/xss-safe-factory.js';
import { Attachment } from '../../../common/core/attachment.js';
import { JQueryEl, LoaderContextInterface } from '../../../common/loader-context-interface.js';
import { XssSafeFactory } from '../../../common/xss-safe-factory.js';

export class GmailLoaderContext implements LoaderContextInterface {
public constructor(
Expand Down
Loading

0 comments on commit 6823435

Please sign in to comment.