// The Receipt widget: who signed a job's result, the digest and the signature, and // whether the receipt seals the request and the result. That verdict is the // engine's, checked in Python when the widget was made; this page only shows it. function el(tag, attrs = {}, ...kids) { const e = document.createElement(tag); for (const [k, v] of Object.entries(attrs)) { if (k === 'text') e.textContent = v; else if (v != null) e.setAttribute(k, String(v)); } for (const k of kids) if (k != null) e.append(k); return e; } const short = (s, keep) => (!s ? '' : s.length <= 2 * keep + 1 ? s : `${s.slice(0, keep)}…${s.slice(-keep)}`); function render({ model, el: host }) { const root = el('div', { class: 'wq wq-receipt-widget' }); host.append(root); function draw() { const d = model.get('data') || {}; const ok = d.valid === true; const rows = [ ['signer', d.signer || '—'], ['key', d.key || '—'], ['digest', d.digest || '—'], ['signature', short(d.signature, 16) || '—'], ['form', `${d.alg || '?'} over ${d.canon || 'the first form'} canonical JSON`], ]; const t = el('table', { class: 'wq-table' }); for (const [k, v] of rows) t.append(el('tr', {}, el('td', { class: 'wq-muted', text: k }), el('td', { class: 'wq-mono wq-break', text: v }))); const parts = [ el('div', {}, 'receipt ', el('span', { class: `wq-badge ${ok ? 'wq-good' : 'wq-bad'}`, text: ok ? 'verified' : 'INVALID' }), ' ', el('span', { class: 'wq-muted', text: `checked here, binding ${d.binds || 'the request and the result as given'}` })), t, ]; if (d.demo) parts.push(el('div', { class: 'wq-muted', text: 'Signed with the published demo key: it shows the result is unaltered, not who signed it.' })); root.replaceChildren(...parts); } draw(); model.on('change:data', draw); return () => model.off('change:data', draw); } export default { render };