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 |
| 57 | cd daimond |
| 58 | rustup target add wasm32-unknown-unknown |
| 59 | wasm-pack build --target web --out-dir www/pkg |
| 60 | node 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> |