theseus/blocked.html
Local Dev 828100e2ce Theseus: warn before opening a name a blocklist flags
The blocklist consumer existed in the resolver library and the gateway, but
the browser opened a flagged name without comment. Now the indexer process
reads the subscribed lists from the chain every ten minutes and hands the
flags to main. A flagged name loads a warning page naming the reason, the
list and the report; the user may continue, and that is remembered per name.

Two gates, because content is reached two ways. loadBns shows the real
interstitial. serveBns refuses with an inline page on every path that skips
it: reload, back and forward, bns:// links, web app windows. The inline page
has no button, since a page at the site's own origin must not be able to
approve itself; only blocked.html may ask to continue, checked by file URL.

Settings › Naming has the policy: warn (default), never open, or ignore the
lists. The csam reason is never offered a way through. A list that cannot be
read keeps the last known flags and never stops a name from resolving.

The gateway put its own warning in front of flagged sites, which this
browser could not get past: it fetches files itself, with no cookie jar. It
now sends x-bns-policy: client and the gateway stays out of the way for a
client that says it decides for itself.

dev/blocklist-selftest.js runs the real protocol handler and decision
functions against a scratch profile.
2026-10-04 15:50:35 +02:00

103 lines
5.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Warning</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!--
Shown in a tab in place of a name that a subscribed blocklist flags
(Decentralized.DNS/PROTOCOL-ADDENDUM-blocklist.md). Loaded from disk by
loadBns() in main.js with the flag in the query string.
"Continue" navigates to bns://block-choose/, which the tab's will-navigate
listener intercepts — and honours only when the page asking is this file.
Nothing here is trusted beyond that: main.js re-checks the flag itself.
-->
<style>
:root {
color-scheme: dark light;
--bg: #140b0d; --fg: #f3e9ea; --muted: #b98b92; --border: #5a2630; --panel: #1c0f12; --warn: #ff8f9c;
}
@media (prefers-color-scheme: light) {
:root { --bg: #fbf3f4; --fg: #2a1216; --muted: #7a4a52; --border: #e6b9c0; --panel: #ffffff; --warn: #b3261e; }
}
* { box-sizing: border-box; }
html, body { margin: 0; min-height: 100%; }
body {
background: var(--bg); color: var(--fg);
font: 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
display: flex; align-items: center; justify-content: center; padding: 40px 24px;
}
main { width: 100%; max-width: 640px; background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 28px 30px; }
h1 { margin: 0 0 10px; font-size: 21px; font-weight: 600; color: var(--warn); letter-spacing: -.01em; }
p { margin: 10px 0; }
.muted { color: var(--muted); font-size: 13px; }
code { font: 12px ui-monospace, "Cascadia Mono", Consolas, monospace; word-break: break-all; }
dl { display: grid; grid-template-columns: max-content 1fr; gap: 4px 14px; margin: 16px 0; font-size: 13px; }
dt { color: var(--muted); }
dd { margin: 0; }
.actions { display: flex; align-items: center; gap: 18px; margin-top: 22px; flex-wrap: wrap; }
button { font: inherit; cursor: pointer; }
#back { padding: 10px 20px; border-radius: 999px; border: 0; background: var(--fg); color: var(--bg); font-weight: 600; }
#go { background: none; border: 0; padding: 0; color: var(--muted); text-decoration: underline; font-size: 13px; }
#go[hidden] { display: none; }
kbd { font: 11px ui-monospace, monospace; opacity: .6; margin-left: 8px; }
</style>
</head>
<body>
<main>
<h1>⚠ <span id="name"></span> is flagged as dangerous</h1>
<p id="why"></p>
<dl>
<dt>Reason</dt><dd><code id="reason"></code></dd>
<dt>List</dt><dd><code id="list"></code></dd>
<dt>Report</dt><dd><code id="report"></code></dd>
</dl>
<p class="muted">The name is still registered on chain and nobody has taken it from its owner. This warning comes from a blocklist Theseus subscribes to; the flag and the report behind it are public transactions anyone can read. You can change what Theseus does with flagged names in Settings › Naming.</p>
<p class="muted" id="refused" hidden>Theseus does not open names reported for this reason.</p>
<div class="actions">
<button id="back">Go back<kbd>Esc</kbd></button>
<button id="go" hidden>Continue to the site anyway</button>
</div>
</main>
<script>
const qs = new URLSearchParams(location.search);
const host = qs.get("host") || "";
const name = qs.get("name") || host;
const reason = qs.get("reason") || "";
const resturl = qs.get("resturl") || "/";
const canProceed = qs.get("proceed") === "1";
const WHY = {
"phishing": "It imitates another site to steal passwords, recovery phrases or funds.",
"impersonation": "It passes itself off as a person or organisation that has not authorised it.",
"malware": "It serves software designed to compromise your device.",
"scam-financial": "It makes a fraudulent financial offer, such as a fake exchange or a wallet drainer.",
"csam": "It was reported for child sexual abuse material.",
"stolen": "Its certificate was reported as moved without the owner's consent.",
};
document.getElementById("name").textContent = name;
document.getElementById("why").textContent = WHY[reason] || "It was reported as dangerous.";
document.getElementById("reason").textContent = reason;
document.getElementById("list").textContent = qs.get("list") || "";
document.getElementById("report").textContent = qs.get("report") || "";
document.title = "Warning: " + name + " is flagged";
const go = document.getElementById("go");
go.hidden = !canProceed;
document.getElementById("refused").hidden = canProceed;
function back() {
if (history.length > 1) history.back();
else location.href = "about:blank";
}
document.getElementById("back").addEventListener("click", back);
go.addEventListener("click", () => {
// Intercepted by main.js (will-navigate); only this page may ask.
location.href = "bns://block-choose/?" + new URLSearchParams({ host, name, choice: "continue", resturl }).toString();
});
document.addEventListener("keydown", (e) => { if (e.key === "Escape") back(); });
document.getElementById("back").focus();
</script>
</body>
</html>