mirror of
https://github.com/luxfi/wallet.git
synced 2026-07-27 03:37:41 +00:00
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).
136 lines
5.6 KiB
HTML
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'} —
|
|
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>
|