Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/www/verify.html

8.7 KiB, 1 run

created by r2519314175:1489, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1<!doctype html>
2<html lang="en">
3<head>
4<meta charset="utf-8">
5<meta name="viewport" content="width=device-width, initial-scale=1">
6<title data-i18n="verify.page_title">Verify Daimond</title>
7<style>
8 :root { color-scheme: dark light; --bg:#17130F; --fg:#ECE6DC; --dim:#A79E92; --line:#332C25;
9 --ok:#7FB069; --no:#E07A67; --warn:#D6A24A; --acc:#D2604F; }
10 * { box-sizing: border-box; }
11 body { margin:0; background:var(--bg); color:var(--fg); font:15px/1.55 system-ui, sans-serif; }
12 main { max-width: 720px; margin: 0 auto; padding: 40px 20px 80px; }
13 h1 { font-size: 22px; margin: 0 0 6px; }
14 .lede { color: var(--dim); margin: 0 0 24px; }
15 .card { border:1px solid var(--line); border-radius:10px; padding:16px 18px; margin:14px 0; }
16 .verdict { font-size:18px; font-weight:600; display:flex; align-items:center; gap:10px; }
17 .dot { width:12px; height:12px; border-radius:50%; background:var(--dim); flex:0 0 auto; }
18 .dot.ok{background:var(--ok);} .dot.no{background:var(--no);} .dot.warn{background:var(--warn);}
19 ul.checks { list-style:none; margin:14px 0 0; padding:0; }
20 ul.checks li { display:flex; gap:10px; padding:7px 0; border-top:1px solid var(--line); align-items:baseline; }
21 .mark { font-weight:700; flex:0 0 auto; width:16px; }
22 .mark.ok{color:var(--ok);} .mark.no{color:var(--no);} .mark.warn{color:var(--warn);}
23 .name { flex:0 0 auto; }
24 .detail { color:var(--dim); font-size:13px; }
25 .mono { font-family: ui-monospace, monospace; font-size:12px; color:var(--dim); word-break:break-all; }
26 .caveat { color:var(--warn); background:rgba(214,162,74,0.08); border:1px solid rgba(214,162,74,0.3);
27 border-radius:8px; padding:12px 14px; font-size:13.5px; }
28 pre { background:#100D0A; border:1px solid var(--line); border-radius:8px; padding:12px 14px; overflow:auto; font-size:12.5px; }
29 a { color: var(--acc); }
30 button { font:inherit; background:var(--acc); color:#fff; border:0; border-radius:8px; padding:9px 16px; cursor:pointer; }
31 button:disabled { opacity:.6; cursor:default; }
32 .prog { color:var(--dim); font-size:13px; }
33</style>
34</head>
35<body>
36<main>
37 <h1 data-i18n="verify.page_title">Verify Daimond</h1>
38 <p class="lede" data-i18n="verify.page_lede">Check that the Daimond this page came from is the published open source. The evidence is a hash you can reproduce yourself.</p>
39
40 <div class="card">
41 <div id="verdict" class="verdict"><span class="dot" id="dot"></span><span id="headline" data-i18n="verify.checking">Checking this build…</span></div>
42 <div id="ids" class="mono" style="margin-top:8px"></div>
43 <ul class="checks" id="checks"></ul>
44 <p class="prog" id="prog"></p>
45 <p style="margin-top:14px"><button id="recheck" disabled data-i18n="verify.recheck">Check again</button></p>
46 </div>
47
48 <div class="card caveat" id="caveat"></div>
49
50 <div class="card">
51 <b data-i18n="verify.independent">The independent check.</b>
52 <p class="lede" style="margin:8px 0 6px" data-i18n="verify.independent_body">A page cannot fully vouch for itself. Build the public source and run the verifier; nothing this server controls is in that loop:</p>
53 <!-- The commands are commands. They are the same in every language and are
54 deliberately unmarked; only the stand-in for this site's address is a
55 word, and the script replaces it with the address itself. -->
56 <pre>git clone https://github.com/oxedyne-com/daimond
57cd daimond
58rustup target add wasm32-unknown-unknown
59wasm-pack build --target web --out-dir www/pkg
60node verify/check.mjs --url <span id="origin" data-i18n="verify.this_site">this site</span></pre>
61 <p class="lede" style="margin:6px 0 0" id="green"></p>
62 </div>
63</main>
64
65<!-- The delivery check speaks the interface's language too. The engine and the
66 English baseline are loaded before the checker, and the user's own choice
67 (kept beside the theme, in localStorage) is loaded after -- so a page whose
68 verdict a person has to read arrives in a language they read. Guarded
69 throughout: without these two files the checker still runs, in English. -->
70<script src="js/i18n.js"></script>
71<script src="i18n/en.js"></script>
72<script src="js/verify.js"></script>
73<script>
74(function () {
75 var dot = document.getElementById('dot'), headline = document.getElementById('headline');
76 var checksEl = document.getElementById('checks'), idsEl = document.getElementById('ids');
77 var progEl = document.getElementById('prog'), caveatEl = document.getElementById('caveat');
78 var btn = document.getElementById('recheck'), greenEl = document.getElementById('green');
79 var LOG = 'https://github.com/oxedyne-com/daimond/blob/main/verify/transparency.jsonl';
80
81 /// The table's string, or the English beside the key while the tables load --
82 /// and for a page served without them at all. Named `tOr` because
83 /// `dev/i18nfallback.mjs` finds fallbacks by that name and holds every one of
84 /// them to the catalogue's own wording.
85 function tOr(key, english, vars) {
86 var s = window.DaimondI18n ? DaimondI18n.t(key, vars) : key;
87 if (s !== key) return s;
88 if (!vars) return english;
89 return String(english).replace(/\{(\w+)\}/g, function (whole, k) {
90 return vars[k] != null ? String(vars[k]) : whole;
91 });
92 }
93
94 /// A sentence put on a node, and the node RE-MARKED with the key it came from.
95 ///
96 /// The mark is what `apply()` repaints from, and the headline changes what it
97 /// is saying: it ships marked `verify.checking` and then carries a verdict.
98 /// Leaving the old mark on it means the table landing a moment later paints
99 /// "Checking this build…" back over a finished verdict.
100 ///
101 /// The key is written twice at each call, once here and once inside the `tOr`
102 /// that resolves the words. That is deliberate: `dev/i18nfallback.mjs` finds a
103 /// fallback by the `tOr(` around it, so a helper that took the English itself
104 /// would hide every sentence on this page from the check that keeps them in
105 /// step with the catalogue.
106 function say(node, key, text) {
107 node.setAttribute('data-i18n', key);
108 node.textContent = text;
109 }
110
111 // This site's own address, in the command a reader is meant to copy. The mark
112 // goes with it: the address is not a string any table has, and a repaint would
113 // put the stand-in back over it.
114 try {
115 var originEl = document.getElementById('origin');
116 originEl.removeAttribute('data-i18n');
117 originEl.textContent = location.origin;
118 } catch (e) {}
119
120 /// The closing sentence, whose last words are a link. The address is the
121 /// page's, never a translation's -- {url} is filled here so a locale file
122 /// carries the sentence and not the URL.
123 function paintGreen() {
124 greenEl.innerHTML = tOr('verify.green_means',
125 'Green means the bytes this site served are the source you just built, and that build is'
126 + ' a sealed entry in the public <a href="{url}">transparency log</a>.', { url: LOG });
127 }
128 paintGreen();
129
130 // Bring in the chosen language, if there is one, and redraw when it lands.
131 if (window.DaimondI18n) {
132 try {
133 DaimondI18n.load(DaimondI18n.locale()).then(function () {
134 DaimondI18n.apply();
135 try { document.documentElement.lang = DaimondI18n.locale(); } catch (e) {}
136 paintGreen();
137 if (!btn.disabled) run();
138 });
139 } catch (e) { /* English is already here */ }
140 }
141
142 function mark(c) { return c.ok === true ? ['ok', '✓'] : c.ok === false ? ['no', '✗'] : ['warn', '?']; }
143
144 async function run() {
145 btn.disabled = true; checksEl.innerHTML = ''; idsEl.textContent = '';
146 dot.className = 'dot';
147 say(headline, 'verify.checking', tOr('verify.checking', 'Checking this build…'));
148 progEl.textContent = '';
149 var v = await window.DaimondVerify.check({
150 onProgress: function (d, t) {
151 progEl.textContent = tOr('verify.hashing', 'hashing served files… {done} / {total}',
152 { done: d, total: t });
153 },
154 });
155 progEl.textContent = '';
156 dot.className = 'dot ' + (v.ok ? 'ok' : v.failed ? 'no' : 'warn');
157 if (v.ok) say(headline, 'verify.verdict_ok',
158 tOr('verify.verdict_ok', 'This build is the published source, and it was sealed.'));
159 else if (v.failed) say(headline, 'verify.verdict_no',
160 tOr('verify.verdict_no', 'This build does NOT match the published source.'));
161 else say(headline, 'verify.verdict_partial',
162 tOr('verify.verdict_partial', 'Could not fully verify. The checks say why.'));
163 if (v.build) idsEl.textContent = tOr('verify.ids', 'build {build} · bundle {bundle}',
164 { build: v.build, bundle: v.bundle });
165 v.checks.forEach(function (c) {
166 var m = mark(c);
167 var li = document.createElement('li');
168 li.innerHTML = '<span class="mark ' + m[0] + '">' + m[1] + '</span>'
169 + '<span class="name">' + c.name + '</span>'
170 + (c.detail ? '<span class="detail">— ' + c.detail + '</span>' : '');
171 checksEl.appendChild(li);
172 });
173 caveatEl.textContent = v.caveat;
174 btn.disabled = false;
175 }
176 btn.addEventListener('click', run);
177 run();
178})();
179</script>
180</body>
181</html>