Files
wallet/apps/extension/e2e/sandbox-test/index.html
T
Hanzo AI 78b18797d5 init: extract wallet from lux/exchange monorepo
Copies apps/extension, apps/mobile and 10 pkgs (wallet, ui, config,
utilities, sessions, gating, notifications, analytics, eslint-config,
prices) into a standalone pnpm workspace.  Resolves merge conflict
markers in extension and mobile package.json files, strips build
artifacts (.wxt, .output, Pods).
2026-04-11 01:59:19 -07:00

136 lines
5.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Extension Sandbox Origin Validation Test</title>
<style>
* { box-sizing: border-box; }
body { font-family: system-ui, -apple-system, sans-serif; background: #0f0f23; color: #e0e0e0; padding: 24px; margin: 0; }
h1 { color: #ff79c6; margin-bottom: 4px; }
.subtitle { color: #888; margin-bottom: 24px; }
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 24px; }
.card { background: #1a1a2e; border: 1px solid #333; border-radius: 8px; padding: 16px; }
.card h3 { margin: 0 0 8px; font-size: 14px; color: #bd93f9; }
.card .detail { font-size: 12px; color: #888; margin-bottom: 12px; }
.card iframe { width: 100%; height: 100px; border: 1px solid #444; border-radius: 4px; }
.result { margin-top: 12px; padding: 8px; border-radius: 4px; font-size: 13px; font-weight: 600; }
.result.pass { background: #0f5132; color: #75b798; border: 1px solid #0f5132; }
.result.fail { background: #842029; color: #ea868f; border: 1px solid #842029; }
.result.waiting { background: #332701; color: #ffda6a; border: 1px solid #332701; }
.instructions { background: #1a1a2e; border: 1px solid #333; border-radius: 8px; padding: 16px; font-size: 13px; line-height: 1.6; }
.instructions code { background: #2a2a3e; padding: 2px 6px; border-radius: 3px; font-size: 12px; }
</style>
</head>
<body>
<h1>Sandbox Origin Validation Test</h1>
<p class="subtitle">Bug bounty #621 — Verify sandboxed frames cannot receive the Uniswap provider</p>
<div class="grid">
<div class="card">
<h3>1. Normal Frame (no sandbox)</h3>
<div class="detail">Expected: origin = http://localhost:*, Uniswap provider = PRESENT</div>
<iframe id="frame-normal" src="child.html"></iframe>
<div id="result-normal" class="result waiting">Waiting for report...</div>
</div>
<div class="card">
<h3>2. Sandboxed (allow-scripts only)</h3>
<div class="detail">Expected: origin = "null", Uniswap provider = ABSENT</div>
<iframe id="frame-sandboxed" src="child.html" sandbox="allow-scripts"></iframe>
<div id="result-sandboxed" class="result waiting">Waiting for report...</div>
</div>
<div class="card">
<h3>3. Sandboxed (allow-scripts + allow-same-origin)</h3>
<div class="detail">Expected: origin = http://localhost:*, Uniswap provider = PRESENT</div>
<iframe id="frame-same-origin" src="child.html" sandbox="allow-scripts allow-same-origin"></iframe>
<div id="result-same-origin" class="result waiting">Waiting for report...</div>
</div>
</div>
<div class="instructions">
<strong>How to use:</strong><br>
1. Serve this directory: <code>python3 -m http.server 8080</code><br>
2. Load the extension in Chrome (webpack dev build via <code>bun start:webpack</code>)<br>
3. Open <code>http://localhost:8080</code> in Chrome<br>
4. All three cards should show their expected results (green = pass, red = fail)<br>
<br>
<strong>Note:</strong> This test detects the <strong>Uniswap provider specifically</strong> via EIP-6963 (<code>rdns: org.uniswap.app</code>),
so other wallet extensions (MetaMask, etc.) won't cause false positives.
</div>
<script>
const expectations = {
normal: { originIsNull: false, hasUniswapProvider: true },
sandboxed: { originIsNull: true, hasUniswapProvider: false },
'same-origin': { originIsNull: false, hasUniswapProvider: true },
};
const received = {};
window.addEventListener('message', (event) => {
if (!event.data || event.data.type !== 'sandbox-test-report') {
return;
}
const { origin, hasUniswapProvider } = event.data;
const isNull = origin === 'null';
// Determine which frame sent this
let frameId = null;
for (const [id, expect] of Object.entries(expectations)) {
if (received[id]) continue;
if (expect.originIsNull === isNull) {
frameId = id;
break;
}
}
// Fallback: match by source iframe
if (!frameId) {
const frames = ['normal', 'sandboxed', 'same-origin'];
for (const id of frames) {
if (received[id]) continue;
const iframe = document.getElementById('frame-' + id);
try {
if (event.source === iframe.contentWindow) {
frameId = id;
break;
}
} catch (e) { /* cross-origin access may throw */ }
}
}
if (!frameId) return;
received[frameId] = true;
const expect = expectations[frameId];
const originPass = expect.originIsNull === isNull;
const providerPass = expect.hasUniswapProvider === hasUniswapProvider;
const allPass = originPass && providerPass;
const el = document.getElementById('result-' + frameId);
el.className = 'result ' + (allPass ? 'pass' : 'fail');
el.innerHTML = `
${allPass ? 'PASS' : 'FAIL'} &mdash;
origin: ${origin} (${originPass ? 'ok' : 'WRONG'}),
Uniswap provider: ${hasUniswapProvider ? 'present' : 'absent'} (${providerPass ? 'ok' : 'WRONG'})
`;
});
// Timeout fallback
setTimeout(() => {
for (const id of Object.keys(expectations)) {
if (!received[id]) {
const el = document.getElementById('result-' + id);
if (el.classList.contains('waiting')) {
el.className = 'result fail';
el.textContent = 'No report received (frame may be blocked)';
}
}
}
}, 5000);
</script>
</body>
</html>