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.
103 lines
5.1 KiB
HTML
103 lines
5.1 KiB
HTML
<!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>
|