Skip to content

Commit cac4f54

Browse files
Add proxy wrapper to memory storage
1 parent 74e8e90 commit cac4f54

File tree

2 files changed

+66
-10
lines changed

2 files changed

+66
-10
lines changed

integration-test/test-pages/runtime-checks/pages/generic-overload.html

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
<p>This page verifies that script overloading works <a href="../config/script-overload.json">config</a></p>
1414

1515
<script>
16-
test('Script should have generic overloaded changes', async () => {
16+
test('Script should have generic overloaded localStorage changes', async () => {
1717
// @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f
1818
window.scriptOutput = false;
1919
window.scriptyRan = false;
2020
const scriptElement = document.createElement('script');
21-
scriptElement.src = './../../shared/replay.js';
21+
// TODO fix with some URL injection import (needs to be a different URL than the tab)
22+
scriptElement.src = `http://localhost:${window.location.port}/shared/replay.js`;
2223
scriptElement.id = 'overloadedScript';
2324
let resolver
2425
const promise = new Promise((resolve) => {
@@ -29,27 +30,70 @@
2930
}
3031
document.body.appendChild(scriptElement);
3132
await promise
32-
console.log(window.scriptyRan, window.replayScript)
3333
localStorage.clear()
3434
replayScript(`
3535
localStorage.clear();
3636
localStorage.setItem('test', 'test');
37+
localStorage.other = "test";
3738
window.scriptyRan = true;
3839
window.scriptOutput = {
39-
item: localStorage.getItem('test')
40+
item: localStorage.getItem('test'),
41+
other: localStorage.getItem('other'),
4042
}
4143
`)
42-
4344
const scripty = document.querySelector('script#overloadedScript');
4445
const nodeAndFakeNodeMatch = scripty === scriptElement;
4546

4647
return [
4748
{ name: 'script ran', result: window.scriptyRan, expected: true },
4849
{ name: 'node and fake node match', result: nodeAndFakeNodeMatch, expected: false },
4950
{ name: 'expected localStorage first response', result: window.scriptOutput, expected: {
50-
item: 'test'
51+
item: 'test',
52+
other: 'test'
53+
}},
54+
{ name: 'did not globally store', result: localStorage.getItem('test'), expected: null },
55+
{ name: 'did session store', result: sessionStorage.getItem('test'), expected: 'test' },
56+
];
57+
});
58+
59+
test('Script should have generic overloaded sessionStorage changes', async () => {
60+
// @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f
61+
window.script2Output = false;
62+
const scriptElement = document.createElement('script');
63+
// TODO fix with some URL injection import (needs to be a different URL than the tab)
64+
scriptElement.src = `http://localhost:${window.location.port}/shared/replay.js`;
65+
scriptElement.id = 'overloadedScript2';
66+
let resolver
67+
const promise = new Promise((resolve) => {
68+
resolver = resolve
69+
})
70+
scriptElement.onload = () => {
71+
resolver()
72+
}
73+
document.body.appendChild(scriptElement);
74+
await promise
75+
sessionStorage.clear()
76+
replayScript(`
77+
sessionStorage.clear();
78+
sessionStorage.setItem('test', 'test');
79+
sessionStorage.other = "test";
80+
window.script2Output = {
81+
item: sessionStorage.getItem('test'),
82+
other: sessionStorage.getItem('other'),
83+
}
84+
`)
85+
const scripty = document.querySelector('script#overloadedScript');
86+
const nodeAndFakeNodeMatch = scripty === scriptElement;
87+
88+
return [
89+
{ name: 'script ran', result: !!window.script2Output, expected: true },
90+
{ name: 'node and fake node match', result: nodeAndFakeNodeMatch, expected: false },
91+
{ name: 'expected localStorage first response', result: window.script2Output, expected: {
92+
item: 'test',
93+
other: 'test'
5194
}},
52-
{ name: 'did not globally store', result: localStorage.getItem('test'), expected: null }
95+
{ name: 'did not globally store', result: localStorage.getItem('test'), expected: null },
96+
{ name: 'did session store', result: sessionStorage.getItem('test'), expected: null },
5397
];
5498
});
5599

src/features/runtime-checks.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* global TrustedScriptURL, TrustedScript */
22

33
import ContentFeature from '../content-feature.js'
4-
import { DDGProxy, getStackTraceOrigins, getStack, matchHostname, injectGlobalStyles, createStyleElement, postDebugMessage, taintSymbol, hasTaintedMethod, taintedOrigins } from '../utils.js'
4+
import { DDGProxy, getStackTraceOrigins, getStack, matchHostname, injectGlobalStyles, createStyleElement, postDebugMessage, taintSymbol, hasTaintedMethod, taintedOrigins, getTabHostname } from '../utils.js'
55
import { defineProperty } from '../wrapper-utils.js'
66
import { wrapScriptCodeOverload } from './runtime-checks/script-overload.js'
77
import { Reflect } from '../captured-globals.js'
@@ -185,7 +185,7 @@ class DDGRuntimeChecks extends HTMLElement {
185185
}
186186
try {
187187
const origin = this.src && new URL(this.src, window.location.href).hostname
188-
if (origin && taintedOrigins()) {
188+
if (origin && taintedOrigins() && getTabHostname() !== origin) {
189189
taintedOrigins()?.add(origin)
190190
}
191191
} catch {}
@@ -690,7 +690,19 @@ export default class RuntimeChecks extends ContentFeature {
690690
}
691691
}
692692

693-
const storage = new MemoryStorage()
693+
const instance = new MemoryStorage()
694+
const storage = new Proxy(instance, {
695+
set (target, prop, value, receiver) {
696+
Reflect.apply(target.setItem, target, [prop, value], receiver)
697+
return true
698+
},
699+
get (target, prop) {
700+
if (typeof target[prop] === 'function') {
701+
return target[prop].bind(instance)
702+
}
703+
return Reflect.get(target, prop, instance)
704+
}
705+
})
694706
this.overrideStorage(config, key, storage)
695707
}
696708

0 commit comments

Comments
 (0)