112 lines
3.6 KiB
HTML
112 lines
3.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Identity Leak Test</title>
|
|
<style>
|
|
body { font: 14px/1.5 -apple-system, system-ui, sans-serif; margin: 2rem; max-width: 720px; }
|
|
h1 { font-size: 1.4rem; }
|
|
.box { border: 1px solid #ccc; padding: 1rem 1.25rem; margin: 1rem 0; border-radius: 6px; }
|
|
.marker { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 1.1rem; word-break: break-all; }
|
|
.fresh { color: #080; }
|
|
.leaked { color: #c00; font-weight: 600; }
|
|
button { font: inherit; padding: .35rem .8rem; margin: .25rem .25rem .25rem 0; cursor: pointer; }
|
|
code { background: #f4f4f4; padding: .1rem .3rem; border-radius: 3px; }
|
|
ul { margin: .5rem 0; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Identity Leak Test</h1>
|
|
|
|
<p>This page writes a per-session marker to <code>localStorage</code> and a
|
|
session cookie, then shows them on every load. Use it to verify that logging
|
|
out and back in as a different identity does <strong>not</strong> leak the
|
|
previous user's marker.</p>
|
|
|
|
<div class="box">
|
|
<strong>Marker for this session:</strong>
|
|
<div id="marker" class="marker">(none yet)</div>
|
|
<div id="status"></div>
|
|
</div>
|
|
|
|
<div class="box">
|
|
<strong>Stored values seen by this page:</strong>
|
|
<ul>
|
|
<li><code>localStorage["sb_identity_marker"]</code> = <span id="ls-val">(none)</span></li>
|
|
<li><code>document.cookie</code> = <span id="ck-val">(none)</span></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<p>
|
|
<button id="set">Write fresh marker</button>
|
|
<button id="clear">Clear marker</button>
|
|
<button id="reload">Reload page</button>
|
|
</p>
|
|
|
|
<script>
|
|
(function () {
|
|
var KEY = "sb_identity_marker";
|
|
|
|
function freshMarker() {
|
|
// Random hex string + timestamp so each "write" is distinguishable.
|
|
var rnd = Math.random().toString(16).slice(2, 10);
|
|
var ts = Date.now().toString(16);
|
|
return "user-" + ts + "-" + rnd;
|
|
}
|
|
|
|
function render() {
|
|
var ls = localStorage.getItem(KEY) || "";
|
|
var ck = "";
|
|
document.cookie.split("; ").forEach(function (c) {
|
|
if (c.indexOf(KEY + "=") === 0) ck = c.slice(KEY.length + 1);
|
|
});
|
|
|
|
var el = document.getElementById("marker");
|
|
var st = document.getElementById("status");
|
|
var lsEl = document.getElementById("ls-val");
|
|
var ckEl = document.getElementById("ck-val");
|
|
|
|
lsEl.textContent = ls || "(none)";
|
|
ckEl.textContent = ck || "(none)";
|
|
|
|
if (ls && ck && ls === ck) {
|
|
el.textContent = ls;
|
|
el.className = "marker fresh";
|
|
st.textContent = "Marker present from a previous visit on this identity.";
|
|
} else if (ls || ck) {
|
|
el.textContent = (ls || ck);
|
|
el.className = "marker leaked";
|
|
st.textContent = "PARTIAL: one of localStorage/cookie is set but not both. " +
|
|
"If this appears right after switching identities, it is a leak.";
|
|
} else {
|
|
el.textContent = "(none — fresh identity)";
|
|
el.className = "marker";
|
|
st.textContent = "No marker found. This is what a fresh identity should see.";
|
|
}
|
|
}
|
|
|
|
document.getElementById("set").addEventListener("click", function () {
|
|
var m = freshMarker();
|
|
localStorage.setItem(KEY, m);
|
|
// Session cookie (no max-age) scoped to this origin.
|
|
document.cookie = KEY + "=" + m + "; path=/";
|
|
render();
|
|
});
|
|
|
|
document.getElementById("clear").addEventListener("click", function () {
|
|
localStorage.removeItem(KEY);
|
|
document.cookie = KEY + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
|
|
render();
|
|
});
|
|
|
|
document.getElementById("reload").addEventListener("click", function () {
|
|
location.reload();
|
|
});
|
|
|
|
render();
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|