From b292a14047a0c12ca05ba97df1833935d42fdb66 Mon Sep 17 00:00:00 2001 From: SJ Date: Wed, 12 Jun 2024 06:24:57 -0700 Subject: [PATCH] fix: Same-origin iframe set/get cookie/localStorage bug (#600) * Set isSameOrigin after iframe src set * same/cross origin iframe cookie/localStorage tests --------- Co-authored-by: Sarah-Jane Skeete --- src/lib/web-worker/worker-iframe.ts | 1 + src/lib/web-worker/worker-storage.ts | 13 +- src/lib/web-worker/worker-window.ts | 4 +- tests/platform/iframe/cookie.html | 25 +++ .../iframe/iframe-cookie-localstorage.spec.ts | 45 +++++ .../iframe/index-cookie-localstorage.html | 184 ++++++++++++++++++ tests/platform/iframe/localstorage.html | 25 +++ 7 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 tests/platform/iframe/cookie.html create mode 100644 tests/platform/iframe/iframe-cookie-localstorage.spec.ts create mode 100644 tests/platform/iframe/index-cookie-localstorage.html create mode 100644 tests/platform/iframe/localstorage.html diff --git a/src/lib/web-worker/worker-iframe.ts b/src/lib/web-worker/worker-iframe.ts index 8dfc863f..c57eb6b9 100644 --- a/src/lib/web-worker/worker-iframe.ts +++ b/src/lib/web-worker/worker-iframe.ts @@ -57,6 +57,7 @@ export const patchHTMLIFrameElement = (WorkerHTMLIFrameElement: any, env: WebWor env.$location$.href = src = resolveUrl(env, src, 'iframe'); env.$isLoading$ = 1; + env.$isSameOrigin$ = webWorkerCtx.$origin$ === env.$location$.origin; setInstanceStateValue(this, StateProp.loadErrorStatus, undefined); diff --git a/src/lib/web-worker/worker-storage.ts b/src/lib/web-worker/worker-storage.ts index 37fa9c02..cb4f80d9 100644 --- a/src/lib/web-worker/worker-storage.ts +++ b/src/lib/web-worker/worker-storage.ts @@ -6,12 +6,11 @@ import { warnCrossOrigin } from '../log'; export const addStorageApi = ( win: any, storageName: 'localStorage' | 'sessionStorage', - isSameOrigin: boolean, env: WebWorkerEnvironment ) => { let storage: Storage = { getItem(key) { - if (isSameOrigin) { + if (env.$isSameOrigin$) { return callMethod(win, [storageName, 'getItem'], [key], CallType.Blocking); } else { warnCrossOrigin('get', storageName, env); @@ -19,7 +18,7 @@ export const addStorageApi = ( }, setItem(key, value) { - if (isSameOrigin) { + if (env.$isSameOrigin$) { callMethod(win, [storageName, 'setItem'], [key, value], CallType.Blocking); } else { warnCrossOrigin('set', storageName, env); @@ -27,7 +26,7 @@ export const addStorageApi = ( }, removeItem(key) { - if (isSameOrigin) { + if (env.$isSameOrigin$) { callMethod(win, [storageName, 'removeItem'], [key], CallType.Blocking); } else { warnCrossOrigin('remove', storageName, env); @@ -35,7 +34,7 @@ export const addStorageApi = ( }, key(index) { - if (isSameOrigin) { + if (env.$isSameOrigin$) { return callMethod(win, [storageName, 'key'], [index], CallType.Blocking); } else { warnCrossOrigin('key', storageName, env); @@ -43,7 +42,7 @@ export const addStorageApi = ( }, clear() { - if (isSameOrigin) { + if (env.$isSameOrigin$) { callMethod(win, [storageName, 'clear'], EMPTY_ARRAY, CallType.Blocking); } else { warnCrossOrigin('clear', storageName, env); @@ -51,7 +50,7 @@ export const addStorageApi = ( }, get length() { - if (isSameOrigin) { + if (env.$isSameOrigin$) { return getter(win, [storageName, 'length']); } else { warnCrossOrigin('length', storageName, env); diff --git a/src/lib/web-worker/worker-window.ts b/src/lib/web-worker/worker-window.ts index 025e0085..5500a36d 100644 --- a/src/lib/web-worker/worker-window.ts +++ b/src/lib/web-worker/worker-window.ts @@ -417,8 +417,8 @@ export const createWindow = ( win.cancelIdleCallback = (id: number) => clearTimeout(id); // add storage APIs to the window - addStorageApi(win, 'localStorage', $isSameOrigin$, env); - addStorageApi(win, 'sessionStorage', $isSameOrigin$, env); + addStorageApi(win, 'localStorage', env); + addStorageApi(win, 'sessionStorage', env); if (!$isSameOrigin$) { win.indexeddb = undefined; diff --git a/tests/platform/iframe/cookie.html b/tests/platform/iframe/cookie.html new file mode 100644 index 00000000..bba44da2 --- /dev/null +++ b/tests/platform/iframe/cookie.html @@ -0,0 +1,25 @@ + + + + + +
+ iframe origin: + +
+
+ cookie value: + +
+ + + diff --git a/tests/platform/iframe/iframe-cookie-localstorage.spec.ts b/tests/platform/iframe/iframe-cookie-localstorage.spec.ts new file mode 100644 index 00000000..1830a813 --- /dev/null +++ b/tests/platform/iframe/iframe-cookie-localstorage.spec.ts @@ -0,0 +1,45 @@ +import { ConsoleMessage, expect, test } from '@playwright/test'; + +test('iframe cookie & localStorage', async ({ page }) => { + let pageConsoleWarnings: Array = []; + page.on('console', msg => { + if (msg.type() === 'warning') { + pageConsoleWarnings.push(msg); + } + }); + + await page.goto('/tests/platform/iframe/index-cookie-localstorage.html'); + await page.waitForSelector('.completed'); + + pageConsoleWarnings = []; + const sameOriginCookieButton = page.locator('#sameOriginCookieButton'); + await sameOriginCookieButton.click(); + const sameOriginCookie = page.frameLocator('#iframe-same-origin-cookie').locator('#test-cookie'); + await expect(sameOriginCookie).toContainText('foo=88'); + expect(pageConsoleWarnings.length).toBe(0); + + pageConsoleWarnings = []; + const sameOriginLocalStorageButton = page.locator('#sameOriginLocalStorageButton'); + await sameOriginLocalStorageButton.click(); + const sameOriginLocalStorage = page.frameLocator('#iframe-same-origin-localstorage').locator('#test-localstorage'); + await expect(sameOriginLocalStorage).toContainText('88'); + expect(pageConsoleWarnings.length).toBe(0); + + pageConsoleWarnings = []; + const crossOriginCookieButton = page.locator('#crossOriginCookieButton'); + await crossOriginCookieButton.click(); + const crossOriginCookie = page.frameLocator('#iframe-cross-origin-cookie').locator('#test-cookie'); + await expect(crossOriginCookie).not.toContainText('foo=88'); + expect(pageConsoleWarnings.length).toBe(2); + expect(pageConsoleWarnings.some(warning => warning.text().includes('Partytown unable to set cross-origin cookie'))).toBe(true); + expect(pageConsoleWarnings.some(warning => warning.text().includes('Partytown unable to get cross-origin cookie'))).toBe(true); + + pageConsoleWarnings = []; + const crossOriginLocalStorageButton = page.locator('#crossOriginLocalStorageButton'); + await crossOriginLocalStorageButton.click(); + const crossOriginLocalStorage = page.frameLocator('#iframe-cross-origin-localstorage').locator('#test-localstorage'); + await expect(crossOriginLocalStorage).not.toContainText('88'); + expect(pageConsoleWarnings.length).toBe(2); + expect(pageConsoleWarnings.some(warning => warning.text().includes('Partytown unable to set cross-origin localStorage'))).toBe(true); + expect(pageConsoleWarnings.some(warning => warning.text().includes('Partytown unable to get cross-origin localStorage'))).toBe(true); +}); diff --git a/tests/platform/iframe/index-cookie-localstorage.html b/tests/platform/iframe/index-cookie-localstorage.html new file mode 100644 index 00000000..a4c7a4f7 --- /dev/null +++ b/tests/platform/iframe/index-cookie-localstorage.html @@ -0,0 +1,184 @@ + + + + + + + + Iframe origin + + + + + + + +

Iframe cookie & localStorage

+
    +
  • + Same origin cookie set/get + + + +
  • + +
  • + Same origin localStorage set/get + + + +
  • + +
  • + Cross origin cookie set/get + + + +
  • + +
  • + Cross origin localStorage set/get + + + +
  • +
+ + +
+

All Tests

+ + + \ No newline at end of file diff --git a/tests/platform/iframe/localstorage.html b/tests/platform/iframe/localstorage.html new file mode 100644 index 00000000..f2ea8787 --- /dev/null +++ b/tests/platform/iframe/localstorage.html @@ -0,0 +1,25 @@ + + + + + +
+ iframe origin: + +
+
+ localStorage value: + +
+ + +