Skip to content

Commit b292a14

Browse files
SarahJane87Sarah-Jane Skeete
and
Sarah-Jane Skeete
authored
fix: Same-origin iframe set/get cookie/localStorage bug (QwikDev#600)
* Set isSameOrigin after iframe src set * same/cross origin iframe cookie/localStorage tests --------- Co-authored-by: Sarah-Jane Skeete <[email protected]>
1 parent b2f642b commit b292a14

7 files changed

+288
-9
lines changed

src/lib/web-worker/worker-iframe.ts

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export const patchHTMLIFrameElement = (WorkerHTMLIFrameElement: any, env: WebWor
5757

5858
env.$location$.href = src = resolveUrl(env, src, 'iframe');
5959
env.$isLoading$ = 1;
60+
env.$isSameOrigin$ = webWorkerCtx.$origin$ === env.$location$.origin;
6061

6162
setInstanceStateValue(this, StateProp.loadErrorStatus, undefined);
6263

src/lib/web-worker/worker-storage.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -6,52 +6,51 @@ import { warnCrossOrigin } from '../log';
66
export const addStorageApi = (
77
win: any,
88
storageName: 'localStorage' | 'sessionStorage',
9-
isSameOrigin: boolean,
109
env: WebWorkerEnvironment
1110
) => {
1211
let storage: Storage = {
1312
getItem(key) {
14-
if (isSameOrigin) {
13+
if (env.$isSameOrigin$) {
1514
return callMethod(win, [storageName, 'getItem'], [key], CallType.Blocking);
1615
} else {
1716
warnCrossOrigin('get', storageName, env);
1817
}
1918
},
2019

2120
setItem(key, value) {
22-
if (isSameOrigin) {
21+
if (env.$isSameOrigin$) {
2322
callMethod(win, [storageName, 'setItem'], [key, value], CallType.Blocking);
2423
} else {
2524
warnCrossOrigin('set', storageName, env);
2625
}
2726
},
2827

2928
removeItem(key) {
30-
if (isSameOrigin) {
29+
if (env.$isSameOrigin$) {
3130
callMethod(win, [storageName, 'removeItem'], [key], CallType.Blocking);
3231
} else {
3332
warnCrossOrigin('remove', storageName, env);
3433
}
3534
},
3635

3736
key(index) {
38-
if (isSameOrigin) {
37+
if (env.$isSameOrigin$) {
3938
return callMethod(win, [storageName, 'key'], [index], CallType.Blocking);
4039
} else {
4140
warnCrossOrigin('key', storageName, env);
4241
}
4342
},
4443

4544
clear() {
46-
if (isSameOrigin) {
45+
if (env.$isSameOrigin$) {
4746
callMethod(win, [storageName, 'clear'], EMPTY_ARRAY, CallType.Blocking);
4847
} else {
4948
warnCrossOrigin('clear', storageName, env);
5049
}
5150
},
5251

5352
get length() {
54-
if (isSameOrigin) {
53+
if (env.$isSameOrigin$) {
5554
return getter(win, [storageName, 'length']);
5655
} else {
5756
warnCrossOrigin('length', storageName, env);

src/lib/web-worker/worker-window.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -417,8 +417,8 @@ export const createWindow = (
417417
win.cancelIdleCallback = (id: number) => clearTimeout(id);
418418

419419
// add storage APIs to the window
420-
addStorageApi(win, 'localStorage', $isSameOrigin$, env);
421-
addStorageApi(win, 'sessionStorage', $isSameOrigin$, env);
420+
addStorageApi(win, 'localStorage', env);
421+
addStorageApi(win, 'sessionStorage', env);
422422

423423
if (!$isSameOrigin$) {
424424
win.indexeddb = undefined;

tests/platform/iframe/cookie.html

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<html>
2+
<head>
3+
<style>
4+
body {
5+
background-color: skyblue;
6+
margin: 2px;
7+
}
8+
</style>
9+
</head>
10+
<body>
11+
<div>
12+
<span>iframe origin:</span>
13+
<span id="iframe-origin"></span>
14+
</div>
15+
<div>
16+
<span>cookie value:</span>
17+
<span id="test-cookie"></span>
18+
</div>
19+
<script>
20+
document.getElementById('iframe-origin').textContent = window.origin;
21+
document.cookie = 'foo=88';
22+
document.getElementById('test-cookie').textContent = document.cookie;
23+
</script>
24+
</body>
25+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { ConsoleMessage, expect, test } from '@playwright/test';
2+
3+
test('iframe cookie & localStorage', async ({ page }) => {
4+
let pageConsoleWarnings: Array<ConsoleMessage> = [];
5+
page.on('console', msg => {
6+
if (msg.type() === 'warning') {
7+
pageConsoleWarnings.push(msg);
8+
}
9+
});
10+
11+
await page.goto('/tests/platform/iframe/index-cookie-localstorage.html');
12+
await page.waitForSelector('.completed');
13+
14+
pageConsoleWarnings = [];
15+
const sameOriginCookieButton = page.locator('#sameOriginCookieButton');
16+
await sameOriginCookieButton.click();
17+
const sameOriginCookie = page.frameLocator('#iframe-same-origin-cookie').locator('#test-cookie');
18+
await expect(sameOriginCookie).toContainText('foo=88');
19+
expect(pageConsoleWarnings.length).toBe(0);
20+
21+
pageConsoleWarnings = [];
22+
const sameOriginLocalStorageButton = page.locator('#sameOriginLocalStorageButton');
23+
await sameOriginLocalStorageButton.click();
24+
const sameOriginLocalStorage = page.frameLocator('#iframe-same-origin-localstorage').locator('#test-localstorage');
25+
await expect(sameOriginLocalStorage).toContainText('88');
26+
expect(pageConsoleWarnings.length).toBe(0);
27+
28+
pageConsoleWarnings = [];
29+
const crossOriginCookieButton = page.locator('#crossOriginCookieButton');
30+
await crossOriginCookieButton.click();
31+
const crossOriginCookie = page.frameLocator('#iframe-cross-origin-cookie').locator('#test-cookie');
32+
await expect(crossOriginCookie).not.toContainText('foo=88');
33+
expect(pageConsoleWarnings.length).toBe(2);
34+
expect(pageConsoleWarnings.some(warning => warning.text().includes('Partytown unable to set cross-origin cookie'))).toBe(true);
35+
expect(pageConsoleWarnings.some(warning => warning.text().includes('Partytown unable to get cross-origin cookie'))).toBe(true);
36+
37+
pageConsoleWarnings = [];
38+
const crossOriginLocalStorageButton = page.locator('#crossOriginLocalStorageButton');
39+
await crossOriginLocalStorageButton.click();
40+
const crossOriginLocalStorage = page.frameLocator('#iframe-cross-origin-localstorage').locator('#test-localstorage');
41+
await expect(crossOriginLocalStorage).not.toContainText('88');
42+
expect(pageConsoleWarnings.length).toBe(2);
43+
expect(pageConsoleWarnings.some(warning => warning.text().includes('Partytown unable to set cross-origin localStorage'))).toBe(true);
44+
expect(pageConsoleWarnings.some(warning => warning.text().includes('Partytown unable to get cross-origin localStorage'))).toBe(true);
45+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<meta name="description" content="Partytown Test Page" />
8+
<title>Iframe origin</title>
9+
<style>
10+
body {
11+
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif,
12+
Apple Color Emoji, Segoe UI Emoji;
13+
font-size: 12px;
14+
}
15+
16+
h1 {
17+
margin: 0 0 15px 0;
18+
}
19+
20+
ul {
21+
list-style-type: none;
22+
margin: 0;
23+
padding: 0;
24+
}
25+
26+
a {
27+
display: block;
28+
padding: 16px 8px;
29+
}
30+
31+
a:link,
32+
a:visited {
33+
text-decoration: none;
34+
color: blue;
35+
}
36+
37+
a:hover {
38+
background-color: #eee;
39+
}
40+
41+
li {
42+
display: block;
43+
height: 80px;
44+
}
45+
46+
li strong,
47+
li code,
48+
li button {
49+
white-space: nowrap;
50+
margin: 0 5px;
51+
min-width: 10px;
52+
}
53+
54+
iframe {
55+
width: 100%;
56+
height: 36px;
57+
border: none;
58+
}
59+
</style>
60+
<script>
61+
window.name = 'Main';
62+
</script>
63+
<script>
64+
partytown = {
65+
logCalls: true,
66+
logGetters: true,
67+
logSetters: true,
68+
logImageRequests: true,
69+
logSendBeaconRequests: true,
70+
logStackTraces: false,
71+
logScriptExecution: true,
72+
};
73+
</script>
74+
<script src="/~partytown/debug/partytown.js"></script>
75+
</head>
76+
77+
<body>
78+
<h1>Iframe cookie & localStorage</h1>
79+
<ul>
80+
<li>
81+
<strong>Same origin cookie set/get</strong>
82+
<button id="sameOriginCookieButton">Create iframe</button>
83+
<code id="testSameOriginCookie"></code>
84+
<script type="text/partytown">
85+
(function () {
86+
const btn = document.getElementById('sameOriginCookieButton');
87+
btn.addEventListener('click', function (ev) {
88+
const elm = document.getElementById('testSameOriginCookie');
89+
const iframe = document.createElement('iframe');
90+
iframe.id = 'iframe-same-origin-cookie';
91+
iframe.style.height = '60px';
92+
const url = new URL('/tests/platform/iframe/cookie.html', location.origin);
93+
iframe.src = url.href;
94+
elm.parentNode.appendChild(iframe);
95+
});
96+
})();
97+
</script>
98+
</li>
99+
100+
<li>
101+
<strong>Same origin localStorage set/get</strong>
102+
<button id="sameOriginLocalStorageButton">Create iframe</button>
103+
<code id="testSameOriginLocalStorage"></code>
104+
<script type="text/partytown">
105+
(function () {
106+
const btn = document.getElementById('sameOriginLocalStorageButton');
107+
btn.addEventListener('click', function (ev) {
108+
const elm = document.getElementById('testSameOriginLocalStorage');
109+
const iframe = document.createElement('iframe');
110+
iframe.id = 'iframe-same-origin-localstorage';
111+
iframe.style.height = '60px';
112+
const url = new URL('/tests/platform/iframe/localstorage.html', location.origin);
113+
iframe.src = url.href;
114+
elm.parentNode.appendChild(iframe);
115+
});
116+
})();
117+
</script>
118+
</li>
119+
120+
<li>
121+
<strong>Cross origin cookie set/get</strong>
122+
<button id="crossOriginCookieButton">Create iframe</button>
123+
<code id="testCrossOriginCookie"></code>
124+
<script type="text/partytown">
125+
(function () {
126+
const btn = document.getElementById('crossOriginCookieButton');
127+
btn.addEventListener('click', function (ev) {
128+
const url = new URL('/tests/platform/iframe/cookie.html', location.origin);
129+
fetch(url)
130+
.then(response => response.text())
131+
.then(htmlContent => {
132+
// simulating cross origin iframe by using a datauri
133+
// which won't have the same origin
134+
const dataUri = `data:text/html;base64,${btoa(htmlContent)}`;
135+
const elm = document.getElementById('testCrossOriginCookie');
136+
const iframe = document.createElement('iframe');
137+
iframe.id = 'iframe-cross-origin-cookie';
138+
iframe.style.height = '60px';
139+
iframe.src = dataUri;
140+
elm.parentNode.appendChild(iframe);
141+
});
142+
});
143+
})();
144+
</script>
145+
</li>
146+
147+
<li>
148+
<strong>Cross origin localStorage set/get</strong>
149+
<button id="crossOriginLocalStorageButton">Create iframe</button>
150+
<code id="testCrossOriginLocalStorage"></code>
151+
<script type="text/partytown">
152+
(function () {
153+
const btn = document.getElementById('crossOriginLocalStorageButton');
154+
btn.addEventListener('click', function (ev) {
155+
const url = new URL('/tests/platform/iframe/localstorage.html', location.origin);
156+
fetch(url)
157+
.then(response => response.text())
158+
.then(htmlContent => {
159+
// simulating cross origin iframe by using a datauri
160+
// which won't have the same origin
161+
const dataUri = `data:text/html;base64,${btoa(htmlContent)}`;
162+
const elm = document.getElementById('testCrossOriginLocalStorage');
163+
const iframe = document.createElement('iframe');
164+
iframe.id = 'iframe-cross-origin-localstorage';
165+
iframe.style.height = '60px';
166+
iframe.src = dataUri;
167+
elm.parentNode.appendChild(iframe);
168+
});
169+
});
170+
})();
171+
</script>
172+
</li>
173+
</ul>
174+
175+
<script type="text/partytown">
176+
(function () {
177+
document.body.classList.add('completed');
178+
})();
179+
</script>
180+
<hr />
181+
<p><a href="/tests/">All Tests</a></p>
182+
</body>
183+
184+
</html>
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<html>
2+
<head>
3+
<style>
4+
body {
5+
background-color: skyblue;
6+
margin: 2px;
7+
}
8+
</style>
9+
</head>
10+
<body>
11+
<div>
12+
<span>iframe origin:</span>
13+
<span id="iframe-origin"></span>
14+
</div>
15+
<div>
16+
<span>localStorage value:</span>
17+
<span id="test-localstorage"></span>
18+
</div>
19+
<script>
20+
document.getElementById('iframe-origin').textContent = window.origin;
21+
window.localStorage.setItem('bar', '88');
22+
document.getElementById('test-localstorage').textContent = window.localStorage.getItem('bar');
23+
</script>
24+
</body>
25+
</html>

0 commit comments

Comments
 (0)