Skip to content

Commit

Permalink
Update WebviewExecutionService
Browse files Browse the repository at this point in the history
  • Loading branch information
gantunesr committed Dec 14, 2022
1 parent df937db commit d2f84ec
Showing 1 changed file with 16 additions and 65 deletions.
81 changes: 16 additions & 65 deletions app/components/Views/Wallet/WebviewExecutionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import {
ExecutionServiceArgs,
} from '@metamask/snap-controllers';
import snapsState from '../../../core/SnapsState';
// import SnapWebviewPostMessageStream from './SnapWebviewPostMessageStream';
import { SnapDuplex } from './SnapDuplex';

// const ObjectMultiplex = require('obj-multiplex');

type IframeExecutionEnvironmentServiceArgs = {
iframeUrl: URL;
Expand All @@ -27,13 +31,6 @@ export default class WebviewExecutionService extends AbstractExecutionService<Wi
this.iframeUrl = iframeUrl;
}

protected terminateJob(jobWrapper: Job<Window>): void {
// eslint-disable-next-line no-console
console.log('TERMINATE JOB----', jobWrapper);
// Send message to webview to remove certain iframe
//document.getElementById(jobWrapper.id)?.remove();
}

protected async _initEnvStream(jobId: string): Promise<{
worker;
stream: BasePostMessageStream;
Expand All @@ -43,65 +40,19 @@ export default class WebviewExecutionService extends AbstractExecutionService<Wi
const iframeWindow = snapsState.webview;
const stream = snapsState.stream;

return { worker: iframeWindow, stream };
}

/**
* Creates the iframe to be used as the execution environment. This may run
* forever if the iframe never loads, but the promise should be wrapped in
* an initialization timeout in the SnapController.
*
* @param uri - The iframe URI.
* @param jobId - The job id.
* @returns A promise that resolves to the contentWindow of the iframe.
*/
private async createWindow(uri: string, jobId: string): Promise<Window> {
return new Promise((resolve, reject) => {
const iframe = document.createElement('iframe');
// The order of operations appears to matter for everything except this
// attribute. We may as well set it here.
iframe.setAttribute('id', jobId);

// In the past, we've had problems that appear to be symptomatic of the
// iframe firing the `load` event before its scripts are actually loaded,
// which has prevented snaps from executing properly. Therefore, we set
// the `src` attribute and append the iframe to the DOM before attaching
// the `load` listener.
//
// `load` should only fire when "all dependent resources" have been
// loaded, which includes scripts.
//
// MDN article for `load` event: https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
// Re: `load` firing twice: https://stackoverflow.com/questions/10781880/dynamically-created-iframe-triggers-onload-event-twice/15880489#15880489
iframe.setAttribute('src', uri);
document.body.appendChild(iframe);
const snapStream = new SnapDuplex({
stream,
jobId,
});

iframe.addEventListener('load', () => {
if (iframe.contentWindow) {
resolve(iframe.contentWindow);
} else {
// We don't know of a case when this would happen, but better to fail
// fast if it does.
reject(
new Error(
`iframe.contentWindow not present on load for job "${jobId}".`,
),
);
}
});
return { worker: iframeWindow, stream: snapStream };
}

// We need to set the sandbox attribute after appending the iframe to the
// DOM, otherwise errors in the iframe will not be propagated via `error`
// and `unhandledrejection` events, and we cannot catch and handle them.
// We wish we knew why this was the case.
//
// We set this property after adding the `load` listener because it
// appears to work dependably. ¯\_(ツ)_/¯
//
// We apply this property as a principle of least authority (POLA)
// measure.
// Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox
iframe.setAttribute('sandbox', 'allow-scripts');
});
protected _terminate(jobWrapper: Job<Window>): void {
// eslint-disable-next-line no-console
console.log(
'This method should a command to the WebView to teardown the iframe for the job with ID',
jobWrapper.id,
);
}
}

0 comments on commit d2f84ec

Please sign in to comment.