Browse Source

fix: don't expose window's vault until ready

tophf 4 years ago
parent
commit
e51376b6c2
3 changed files with 29 additions and 22 deletions
  1. 2 2
      src/injected/content/index.js
  2. 26 18
      src/injected/content/inject.js
  3. 1 2
      src/injected/web/index.js

+ 2 - 2
src/injected/content/index.js

@@ -33,9 +33,9 @@ let pendingSetPopup;
     IS_FIREFOX && global.location.href,
     { retry: true });
   const isXml = document instanceof XMLDocument;
-  if (!isXml) injectPageSandbox(contentId, webId);
-  // Binding now so iframe's injectPageSandbox can call our bridge.post before `data` is received
+  // Binding now so injectPageSandbox can call our bridge.post before `data` is received
   bindEvents(contentId, webId, bridge, global.cloneInto);
+  if (!isXml) injectPageSandbox(contentId, webId);
   // detecting if browser.contentScripts is usable, it was added in FF59 as well as composedPath
   const data = IS_FIREFOX && Event[PROTO].composedPath
     ? await getDataFF(dataPromise)

+ 26 - 18
src/injected/content/inject.js

@@ -31,22 +31,35 @@ window::on(INIT_FUNC_NAME, evt => {
     frameEventWnd = evt::getRelatedTarget();
   } else {
     // setupVaultId's second event is the vaultId
-    bridge.post('Frame', evt::getDetail(), INJECT_PAGE, frameEventWnd);
+    bridge.post('WriteVault', evt::getDetail(), INJECT_PAGE, frameEventWnd);
     frameEventWnd = null;
   }
 });
 bridge.addHandlers({
-  // FF bug workaround to enable processing of sourceURL in injected page scripts
+  /**
+   * FF bug workaround to enable processing of sourceURL in injected page scripts
+   */
   InjectList: IS_FIREFOX && injectList,
-  /** @this {Node} window */
-  VaultId(vaultId) {
-    this[VAULT_SEED_NAME] = vaultId; // goes into the isolated world of the content scripts
+  /**
+   * Writes the value into the isolated world of the intercepted window
+   * @this {Node} window
+   */
+  VaultId(id) {
+    this[VAULT_SEED_NAME] = { id, parent: window };
   },
 });
 
 export function injectPageSandbox(contentId, webId) {
-  const vaultId = window[VAULT_SEED_NAME] || !IS_TOP && setupVaultId() || '';
-  delete window[VAULT_SEED_NAME];
+  let vaultId = window[VAULT_SEED_NAME];
+  if (vaultId) {
+    delete window[VAULT_SEED_NAME];
+    vaultId = tellParentToWriteVault(vaultId.parent, vaultId.id);
+  } else {
+    vaultId = !IS_TOP
+      && isSameOriginWindow(window.parent)
+      && tellParentToWriteVault(window.parent, getUniqIdSafe())
+      || '';
+  }
   inject({
     code: `(${VMInitInjection}('${vaultId}',${IS_FIREFOX}))('${webId}','${contentId}')`
       + `\n//# sourceURL=${browser.runtime.getURL('sandbox/injected-web.js')}`,
@@ -229,15 +242,10 @@ function setupContentInvoker(contentId, webId) {
   };
 }
 
-function setupVaultId() {
-  const { parent } = window;
-  // Testing for same-origin parent without throwing an exception.
-  if (isSameOriginWindow(parent)) {
-    const vaultId = getUniqIdSafe();
-    // In FF, content scripts running in a same-origin frame cannot directly call parent's functions
-    // TODO: Use a single PointerEvent with `pointerType: vaultId` when strict_min_version >= 59
-    parent::fire(new MouseEventSafe(INIT_FUNC_NAME, { relatedTarget: window }));
-    parent::fire(new CustomEventSafe(INIT_FUNC_NAME, { detail: vaultId }));
-    return vaultId;
-  }
+function tellParentToWriteVault(parent, vaultId) {
+  // In FF, content scripts running in a same-origin frame cannot directly call parent's functions
+  // TODO: Use a single PointerEvent with `pointerType: vaultId` when strict_min_version >= 59
+  parent::fire(new MouseEventSafe(INIT_FUNC_NAME, { relatedTarget: window }));
+  parent::fire(new CustomEventSafe(INIT_FUNC_NAME, { detail: vaultId }));
+  return vaultId;
 }

+ 1 - 2
src/injected/web/index.js

@@ -40,7 +40,7 @@ export default function initialize(
     bindEvents(webId, contentId, bridge);
     bridge.addHandlers({
       /** @this {Node} contentWindow */
-      Frame(id) {
+      WriteVault(id) {
         this[id] = VAULT;
       },
       Ping() {
@@ -51,7 +51,6 @@ export default function initialize(
       const wnd = openWindow::apply(this, args);
       const vaultId = wnd && isSameOriginWindow(wnd) && getUniqIdSafe();
       if (vaultId) {
-        wnd[vaultId] = VAULT;
         bridge.post('VaultId', vaultId, undefined, wnd);
       }
       return wnd;