Skip to content

Commit 6d6a340

Browse files
rrrooommmaaaRoman Shevchenko
and
Roman Shevchenko
authored
Issue 1509 window messaging from iframe to parent live test (#5320)
* frame-level dest and listener for confirmation_result and pgp_block_render * fix * helpers for getting async results from content-script, window postMessage support * prepare test infrastructure to test passphrase dialog on gmail page * refactor RelayManager to track reloaded frames, disabled test * restartable relays * tidy up, less dependency on frameId, protection against unexpected progress callbacks * removed unnecessary async * tidy up * stricter _tab_ detection * registry of content scripts in background page * prevent content script setup for non-top frame * Revert "prevent content script setup for non-top frame" This reverts commit 9d11287. * fixed wiring to window messages * rename * pgp_block_retry handling with window messaging and actual frame check --------- Co-authored-by: Roman Shevchenko <[email protected]>
1 parent e4dee98 commit 6d6a340

27 files changed

+560
-403
lines changed

extension/chrome/elements/attachment.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ import { AttachmentWarnings } from './shared/attachment_warnings.js';
2424

2525
export class AttachmentDownloadView extends View {
2626
public fesUrl?: string;
27-
public confirmationResultResolver?: (confirm: boolean) => void;
27+
public readonly parentTabId: string;
2828
protected readonly acctEmail: string;
29-
protected readonly parentTabId: string;
3029
protected readonly frameId: string;
3130
protected readonly origNameBasedOnFilename: string;
3231
protected readonly isEncrypted: boolean;
@@ -85,8 +84,8 @@ export class AttachmentDownloadView extends View {
8584
this.gmail = new Gmail(this.acctEmail);
8685
}
8786

88-
public getParentTabId = () => {
89-
return this.parentTabId;
87+
public getDest = () => {
88+
return this.tabId;
9089
};
9190

9291
public render = async () => {
@@ -151,7 +150,7 @@ export class AttachmentDownloadView extends View {
151150
this.ppChangedPromiseCancellation = { cancel: false }; // set to a new, not yet used object
152151
}
153152
});
154-
BrowserMsg.addListener('confirmation_result', CommonHandlers.createConfirmationResultHandler(this));
153+
BrowserMsg.addListener('confirmation_result', CommonHandlers.createAsyncResultHandler());
155154
BrowserMsg.listen(this.tabId);
156155
};
157156

extension/chrome/elements/pgp_block.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44

55
import { Url } from '../../js/common/core/common.js';
66
import { Assert } from '../../js/common/assert.js';
7-
import { RenderMessage, RenderMessageWithFrameId } from '../../js/common/render-message.js';
7+
import { RenderMessage } from '../../js/common/render-message.js';
88
import { Attachment } from '../../js/common/core/attachment.js';
99
import { Xss } from '../../js/common/platform/xss.js';
1010
import { PgpBlockViewAttachmentsModule } from './pgp_block_modules/pgp-block-attachmens-module.js';
1111
import { PgpBlockViewErrorModule } from './pgp_block_modules/pgp-block-error-module.js';
1212
import { PgpBlockViewPrintModule } from './pgp_block_modules/pgp-block-print-module.js';
1313
import { PgpBlockViewQuoteModule } from './pgp_block_modules/pgp-block-quote-module.js';
1414
import { PgpBlockViewRenderModule } from './pgp_block_modules/pgp-block-render-module.js';
15-
import { Ui } from '../../js/common/browser/ui.js';
15+
import { CommonHandlers, Ui } from '../../js/common/browser/ui.js';
1616
import { View } from '../../js/common/view.js';
17-
import { Bm } from '../../js/common/browser/browser-msg.js';
17+
import { BrowserMsg } from '../../js/common/browser/browser-msg.js';
1818

1919
export class PgpBlockView extends View {
2020
public readonly acctEmail: string; // needed for attachment decryption, probably should be refactored out
@@ -27,6 +27,7 @@ export class PgpBlockView extends View {
2727
public readonly errorModule: PgpBlockViewErrorModule;
2828
public readonly renderModule: PgpBlockViewRenderModule;
2929
public readonly printModule = new PgpBlockViewPrintModule();
30+
private tabId!: string;
3031

3132
public constructor() {
3233
super();
@@ -41,28 +42,27 @@ export class PgpBlockView extends View {
4142
this.quoteModule = new PgpBlockViewQuoteModule(this);
4243
this.errorModule = new PgpBlockViewErrorModule(this);
4344
this.renderModule = new PgpBlockViewRenderModule(this);
44-
chrome.runtime.onMessage.addListener((message: Bm.Raw) => {
45-
if (message.name === 'pgp_block_render') {
46-
const msg = message.data.bm as RenderMessageWithFrameId;
47-
if (msg.frameId === this.frameId) {
48-
this.processMessage(msg);
49-
return true;
50-
}
51-
}
52-
return false;
53-
});
54-
window.addEventListener('load', () => window.parent.postMessage({ readyToReceive: this.frameId }, '*'));
5545
}
5646

47+
public getDest = () => {
48+
return this.tabId;
49+
};
50+
5751
public render = async () => {
58-
//
52+
this.tabId = await BrowserMsg.requiredTabId();
5953
};
6054

6155
public setHandlers = () => {
6256
$('.pgp_print_button').on(
6357
'click',
6458
this.setHandler(() => this.printModule.printPGPBlock())
6559
);
60+
BrowserMsg.addListener('pgp_block_render', async (msg: RenderMessage) => {
61+
this.processMessage(msg);
62+
});
63+
BrowserMsg.addListener('confirmation_result', CommonHandlers.createAsyncResultHandler());
64+
BrowserMsg.listen(this.tabId);
65+
BrowserMsg.send.pgpBlockReady({ frameId: this.frameId, messageSender: this.tabId });
6666
};
6767

6868
private processMessage = (data: RenderMessage) => {

extension/chrome/elements/pgp_block_modules/pgp-block-attachmens-module.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Attachment } from '../../../js/common/core/attachment.js';
77
import { Browser } from '../../../js/common/browser/browser.js';
88
import { BrowserMsg } from '../../../js/common/browser/browser-msg.js';
99
import { PgpBlockView } from '../pgp_block.js';
10-
import { CommonHandlers, Ui } from '../../../js/common/browser/ui.js';
10+
import { Ui } from '../../../js/common/browser/ui.js';
1111
import { Xss } from '../../../js/common/platform/xss.js';
1212
import { KeyStore } from '../../../js/common/platform/store/key-store.js';
1313
import { XssSafeFactory } from '../../../js/common/xss-safe-factory.js';
@@ -21,10 +21,6 @@ export class PgpBlockViewAttachmentsModule {
2121

2222
public constructor(private view: PgpBlockView) {}
2323

24-
public getParentTabId = () => {
25-
return this.view.parentTabId;
26-
};
27-
2824
public renderInnerAttachments = (attachments: Attachment[], isEncrypted: boolean) => {
2925
Xss.sanitizeAppend('#pgp_block', '<div id="attachments"></div>');
3026
this.includedAttachments = attachments;
@@ -78,8 +74,6 @@ export class PgpBlockViewAttachmentsModule {
7874
}
7975
})
8076
);
81-
BrowserMsg.addListener('confirmation_result', CommonHandlers.createConfirmationResultHandler(this));
82-
BrowserMsg.listen(this.view.parentTabId);
8377
};
8478

8579
private previewAttachmentClickedHandler = async (attachment: Attachment) => {
@@ -102,7 +96,7 @@ export class PgpBlockViewAttachmentsModule {
10296
type: encrypted.type,
10397
data: decrypted.content,
10498
});
105-
if (await AttachmentWarnings.confirmSaveToDownloadsIfNeeded(attachment, this)) {
99+
if (await AttachmentWarnings.confirmSaveToDownloadsIfNeeded(attachment, this.view)) {
106100
Browser.saveToDownloads(attachment);
107101
}
108102
} else {

extension/chrome/elements/pgp_block_modules/pgp-block-render-module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export class PgpBlockViewRenderModule {
145145
public renderSignatureOffline = () => {
146146
this.renderSignatureStatus('error verifying signature: offline, click to retry').on(
147147
'click',
148-
this.view.setHandler(() => window.parent.postMessage({ retry: this.view.frameId }, '*'))
148+
this.view.setHandler(() => BrowserMsg.send.pgpBlockRetry({ frameId: this.view.frameId, messageSender: this.view.getDest() }))
149149
);
150150
};
151151
}

extension/chrome/settings/inbox/inbox-modules/inbox-active-thread-module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ export class InboxActiveThreadModule extends ViewModule<InboxView> {
189189
loaderContext.getRenderedMessageXssSafe() +
190190
loaderContext.getRenderedAttachmentsXssSafe();
191191
$('.thread').append(this.wrapMsg(htmlId, r)); // xss-safe-value
192-
await this.view.messageRenderer.startProcessingInlineBlocks(this.view.relayManager, this.view.factory, messageInfo, blocksInFrames);
192+
this.view.messageRenderer.startProcessingInlineBlocks(this.view.relayManager, this.view.factory, messageInfo, blocksInFrames);
193193
if (exportBtn) {
194194
$('.action-export').on(
195195
'click',

extension/chrome/settings/inbox/inbox.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import { XssSafeFactory } from '../../../js/common/xss-safe-factory.js';
2424
import { AcctStore } from '../../../js/common/platform/store/acct-store.js';
2525
import { RelayManager } from '../../../js/common/relay-manager.js';
2626
import { MessageRenderer } from '../../../js/common/message-renderer.js';
27-
import { Env } from '../../../js/common/browser/env.js';
2827

2928
export class InboxView extends View {
3029
public readonly inboxMenuModule: InboxMenuModule;
@@ -62,16 +61,11 @@ export class InboxView extends View {
6261
this.inboxNotificationModule = new InboxNotificationModule(this);
6362
this.inboxActiveThreadModule = new InboxActiveThreadModule(this);
6463
this.inboxListThreadsModule = new InboxListThreadsModule(this);
65-
window.addEventListener('message', e => {
66-
if (e.origin === Env.getExtensionOrigin()) {
67-
this.relayManager.handleMessageFromFrame(e.data);
68-
}
69-
});
7064
}
7165

7266
public render = async () => {
7367
this.tabId = await BrowserMsg.requiredTabId();
74-
this.relayManager = new RelayManager(this.tabId, this.debug);
68+
this.relayManager = new RelayManager(this.debug);
7569
this.factory = new XssSafeFactory(this.acctEmail, this.tabId);
7670
this.injector = new Injector('settings', undefined, this.factory);
7771
this.webmailCommon = new WebmailCommon(this.acctEmail, this.injector);
@@ -105,7 +99,9 @@ export class InboxView extends View {
10599

106100
public setHandlers = () => {
107101
// BrowserMsg.addPgpListeners(); // todo - re-allow when https://github.com/FlowCrypt/flowcrypt-browser/issues/2560 fixed
102+
this.addBrowserMsgListeners();
108103
BrowserMsg.listen(this.tabId);
104+
BrowserMsg.listenForWindowMessages(); // listen for direct messages from child iframes
109105
Catch.setHandledInterval(this.webmailCommon.addOrRemoveEndSessionBtnIfNeeded, 30000);
110106
$('.action_open_settings').on(
111107
'click',
@@ -122,7 +118,6 @@ export class InboxView extends View {
122118
'click',
123119
this.setHandlerPrevent('double', async () => await Settings.newGoogleAcctAuthPromptThenAlertOrForward(this.tabId))
124120
);
125-
this.addBrowserMsgListeners();
126121
};
127122

128123
public redirectToUrl = (params: UrlParams) => {
@@ -182,6 +177,12 @@ export class InboxView extends View {
182177
await Ui.modal.attachmentPreview(iframeUrl);
183178
});
184179
BrowserMsg.addListener('confirmation_show', CommonHandlers.showConfirmationHandler);
180+
BrowserMsg.addListener('pgp_block_ready', async ({ frameId, messageSender }: Bm.PgpBlockReady) => {
181+
this.relayManager.associate(frameId, messageSender);
182+
});
183+
BrowserMsg.addListener('pgp_block_retry', async ({ frameId, messageSender }: Bm.PgpBlockRetry) => {
184+
this.relayManager.retry(frameId, messageSender);
185+
});
185186
if (this.debug) {
186187
BrowserMsg.addListener('open_compose_window', async ({ draftId }: Bm.ComposeWindowOpenDraft) => {
187188
console.log('received open_compose_window');

extension/js/background_page/bg-handlers.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export class BgHandlers {
3030
};
3131

3232
public static ajaxHandler = async (r: Bm.Ajax, sender: Bm.Sender): Promise<Bm.Res.Ajax> => {
33-
if (r.req.context?.frameId) {
33+
if (r.req.context?.operationId) {
3434
// progress updates were requested via messages
3535
let dest = r.req.context.tabId;
3636
if (typeof dest === 'undefined') {
@@ -43,10 +43,10 @@ export class BgHandlers {
4343
}
4444
if (typeof dest !== 'undefined') {
4545
const destination = dest;
46-
const frameId = r.req.context.frameId;
46+
const operationId = r.req.context.operationId;
4747
const expectedTransferSize = r.req.context.expectedTransferSize;
4848
r.req.xhr = Api.getAjaxProgressXhrFactory({
49-
download: (percent, loaded, total) => BrowserMsg.send.ajaxProgress(destination, { percent, loaded, total, expectedTransferSize, frameId }),
49+
download: (percent, loaded, total) => BrowserMsg.send.ajaxProgress(destination, { percent, loaded, total, expectedTransferSize, operationId }),
5050
});
5151
}
5252
}
@@ -91,11 +91,15 @@ export class BgHandlers {
9191
});
9292
});
9393

94-
public static respondWithSenderTabId = async (r: unknown, sender: Bm.Sender): Promise<Bm.Res._tab_> => {
94+
public static respondWithSenderTabId = async (r: Bm._tab_, sender: Bm.Sender): Promise<Bm.Res._tab_> => {
9595
if (sender === 'background') {
9696
return { tabId: null }; // eslint-disable-line no-null/no-null
97-
} else if (sender.tab) {
98-
return { tabId: `${sender.tab.id}:${sender.frameId}` };
97+
} else if (typeof sender.tab?.id === 'number' && sender.tab.id > 0) {
98+
const tabId = `${sender.tab.id}:${sender.frameId}`;
99+
if (r.contentScript) {
100+
BrowserMsg.contentScriptsRegistry.add(tabId);
101+
}
102+
return { tabId };
99103
} else {
100104
// sender.tab: "This property will only be present when the connection was opened from a tab (including content scripts)"
101105
// https://developers.chrome.com/extensions/runtime#type-MessageSender

extension/js/common/api/email-provider/gmail/google.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class Google {
4040
// eslint-disable-next-line @typescript-eslint/naming-convention
4141
const headers = { Authorization: await GoogleAuth.googleApiAuthHeader(acctEmail) };
4242
const context =
43-
'frameId' in progress ? { frameId: progress.frameId, expectedTransferSize: progress.expectedTransferSize, tabId: progress.tabId } : undefined;
43+
'operationId' in progress ? { operationId: progress.operationId, expectedTransferSize: progress.expectedTransferSize, tabId: progress.tabId } : undefined;
4444
const xhr = Api.getAjaxProgressXhrFactory('download' in progress || 'upload' in progress ? progress : {});
4545
const request = { xhr, context, url, method, data, headers, crossDomain: true, contentType, async: true };
4646
return (await GoogleAuth.apiGoogleCallRetryAuthErrorOneTime(acctEmail, request)) as RT;

extension/js/common/api/shared/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type RawAjaxErr = {
2525
status?: number;
2626
statusText?: string;
2727
};
28-
export type ProgressDestFrame = { frameId: string; expectedTransferSize: number; tabId?: string };
28+
export type ProgressDestFrame = { operationId: string; expectedTransferSize: number; tabId?: string };
2929
export type ApiCallContext = ProgressDestFrame | undefined;
3030

3131
export type ChunkedCb = (r: ProviderContactsResults) => Promise<void>;

0 commit comments

Comments
 (0)