|
558 | 558 | transition: width 0.4s ease; |
559 | 559 | } |
560 | 560 |
|
| 561 | + |
| 562 | + .live-proof-intro { padding: 72px 0 28px; text-align:center; } |
| 563 | + .live-proof-intro h2 { font-size: clamp(2rem,4vw,3.2rem); line-height:1.15; letter-spacing:-0.03em; } |
| 564 | + .live-proof-intro .grad { background: linear-gradient(100deg,#2563eb,#7c3aed); -webkit-background-clip:text; color:transparent; } |
| 565 | + .live-proof { background: linear-gradient(180deg,#fff 0%, #f4f7ff 55%, #f6f0ff 100%); } |
| 566 | + .live-proof-card { max-width: 980px; margin:0 auto; background:#fff; border:1px solid #dbe4ff; border-radius:24px; box-shadow:0 18px 48px rgba(37,99,235,.1); padding:36px; } |
| 567 | + .live-proof-header .section-eyebrow { display:inline-block; padding:6px 12px; border-radius:999px; background:#eef2ff; border:1px solid #c7d2fe; } |
| 568 | + .lp-rows{ display:grid; gap:12px; margin:28px 0; } .lp-row{display:flex; justify-content:space-between; gap:18px; padding:16px; border:1px solid #e2e8f0; border-radius:14px; background:#f8fafc;} |
| 569 | + .lp-row-main{display:flex; align-items:center; gap:10px;} .lp-label{font-weight:700; font-size:1rem;} .lp-meta{color:#475569; margin-top:6px;} .lp-result{font-family:monospace; font-size:12px; color:#334155;align-self:center;} |
| 570 | + .lp-state{padding:4px 10px; border-radius:999px; font-size:12px; font-weight:700; text-transform:uppercase;} |
| 571 | + .lp-row.pending .lp-state{background:#e2e8f0;color:#475569;} .lp-row.running .lp-state{background:#ddd6fe;color:#5b21b6;} .lp-row.passed .lp-state{background:#dcfce7;color:#166534;} .lp-row.failed .lp-state{background:#fee2e2;color:#991b1b;} |
| 572 | + .lp-grid{display:grid;grid-template-columns:1fr 1fr; gap:14px; margin:22px 0;} .lp-panel{border-radius:14px;padding:16px;border:1px solid #e2e8f0;} .lp-panel-valid{background:#f0fdf4;border-color:#bbf7d0;} .lp-panel-invalid{background:#fff7ed;border-color:#fed7aa;} |
| 573 | + .lp-kv .status{font-size:1.2rem;font-weight:800;} .lp-kv .line{margin-top:6px;color:#334155;} .lp-note{margin-top:18px;padding:14px 16px;border-radius:12px;background:#f8fafc;border:1px solid #e2e8f0;color:#475569;line-height:1.6;} |
| 574 | + .lp-ctas{display:flex; gap:10px; flex-wrap:wrap; margin-top:14px;} |
| 575 | + |
561 | 576 | /* ── HOW IT WORKS ─────────────────────────────── */ |
562 | 577 | .how-section { |
563 | 578 | border-top: 1px solid var(--border); |
@@ -1158,26 +1173,34 @@ <h1 class="hero-h1"> |
1158 | 1173 | <span id="rp-bar-text">Verifying…</span> |
1159 | 1174 | </div> |
1160 | 1175 | </div> |
1161 | | - <p class="hero-note">The animation above explains the model. The live proof below runs it.</p> |
| 1176 | + </div> |
| 1177 | + </section> |
| 1178 | + |
| 1179 | + <section class="live-proof-intro"> |
| 1180 | + <div class="container"> |
| 1181 | + <p class="section-eyebrow">From preview to production</p> |
| 1182 | + <h2>The animation above explains the model.<br><span class="grad">The live proof below runs it.</span></h2> |
1162 | 1183 | </div> |
1163 | 1184 | </section> |
1164 | 1185 |
|
1165 | 1186 | <section class="section live-proof" id="live-proof"> |
1166 | 1187 | <div class="container"> |
1167 | | - <p class="section-eyebrow">Live Protocol Proof</p> |
1168 | | - <h2 class="section-h2">Resolve. Sign. Verify. Tamper. Reject.</h2> |
1169 | | - <p class="section-p">This is not a mock animation. The homepage calls the production runtime, verifies the returned receipt, then tampers with the payload and verifies again.</p> |
1170 | 1188 | <div class="live-proof-card"> |
| 1189 | + <div class="live-proof-header"> |
| 1190 | + <p class="section-eyebrow">LIVE PROTOCOL PROOF</p> |
| 1191 | + <h2 class="section-h2">Resolve. Sign. Verify. Tamper. Reject.</h2> |
| 1192 | + <p class="section-p">This is not a mock animation. The homepage calls the production runtime, verifies the returned receipt, tampers with the payload, and verifies again.</p> |
| 1193 | + </div> |
1171 | 1194 | <div class="lp-rows"> |
1172 | | - <div class="lp-row pending" data-live-step="resolve"><div><div class="lp-row-main"><span class="lp-dot"></span><span class="lp-label">Resolve / identify signer</span></div><div class="lp-meta" data-live-meta="resolve">pending</div></div><div class="lp-state" data-live-state="resolve">pending</div></div> |
1173 | | - <div class="lp-row pending" data-live-step="sign"><div><div class="lp-row-main"><span class="lp-dot"></span><span class="lp-label">Sign</span></div><div class="lp-meta" data-live-meta="sign">pending</div></div><div class="lp-state" data-live-state="sign">pending</div></div> |
1174 | | - <div class="lp-row pending" data-live-step="verify"><div><div class="lp-row-main"><span class="lp-dot"></span><span class="lp-label">Verify</span></div><div class="lp-meta" data-live-meta="verify">pending</div></div><div class="lp-state" data-live-state="verify">pending</div></div> |
1175 | | - <div class="lp-row pending" data-live-step="tamper"><div><div class="lp-row-main"><span class="lp-dot"></span><span class="lp-label">Tamper</span></div><div class="lp-meta" data-live-meta="tamper">pending</div></div><div class="lp-state" data-live-state="tamper">pending</div></div> |
1176 | | - <div class="lp-row pending" data-live-step="reject"><div><div class="lp-row-main"><span class="lp-dot"></span><span class="lp-label">Reject</span></div><div class="lp-meta" data-live-meta="reject">pending</div></div><div class="lp-state" data-live-state="reject">pending</div></div> |
| 1195 | + <div class="lp-row pending" data-live-step="resolve"><div><div class="lp-row-main"><span class="lp-label">1. Resolve</span><span class="lp-state" data-live-state="resolve">pending</span></div><div class="lp-meta" data-live-meta="resolve">Identify runtime signer identity</div></div><div class="lp-result" data-live-result="resolve">waiting for runtime.commandlayer.eth</div></div> |
| 1196 | + <div class="lp-row pending" data-live-step="sign"><div><div class="lp-row-main"><span class="lp-label">2. Sign</span><span class="lp-state" data-live-state="sign">pending</span></div><div class="lp-meta" data-live-meta="sign">Call runtime and receive signed metadata.proof</div></div><div class="lp-result" data-live-result="sign">waiting for signed payload</div></div> |
| 1197 | + <div class="lp-row pending" data-live-step="verify"><div><div class="lp-row-main"><span class="lp-label">3. Verify</span><span class="lp-state" data-live-state="verify">pending</span></div><div class="lp-meta" data-live-meta="verify">Verifier recomputes json.sorted_keys.v1 + SHA-256 + Ed25519</div></div><div class="lp-result" data-live-result="verify">waiting for verifier response</div></div> |
| 1198 | + <div class="lp-row pending" data-live-step="tamper"><div><div class="lp-row-main"><span class="lp-label">4. Tamper</span><span class="lp-state" data-live-state="tamper">pending</span></div><div class="lp-meta" data-live-meta="tamper">Mutate canonical payload bytes</div></div><div class="lp-result" data-live-result="tamper">waiting for mutation step</div></div> |
| 1199 | + <div class="lp-row pending" data-live-step="reject"><div><div class="lp-row-main"><span class="lp-label">5. Reject</span><span class="lp-state" data-live-state="reject">pending</span></div><div class="lp-meta" data-live-meta="reject">Verifier should reject tampered receipt</div></div><div class="lp-result" data-live-result="reject">waiting for invalid result</div></div> |
1177 | 1200 | </div> |
1178 | 1201 | <div class="lp-grid"> |
1179 | | - <div class="lp-panel"><h4>Original receipt</h4><div class="lp-kv" id="lp-valid-summary">waiting...</div></div> |
1180 | | - <div class="lp-panel"><h4>Tampered receipt</h4><div class="lp-kv" id="lp-invalid-summary">waiting...</div></div> |
| 1202 | + <div class="lp-panel lp-panel-valid"><h4>Original receipt</h4><div class="lp-kv" id="lp-valid-summary">waiting...</div></div> |
| 1203 | + <div class="lp-panel lp-panel-invalid"><h4>Tampered receipt</h4><div class="lp-kv" id="lp-invalid-summary">waiting...</div></div> |
1181 | 1204 | </div> |
1182 | 1205 | <div id="lp-error" class="lp-error" style="display:none;">Runtime or verifier unavailable. No success was faked.</div> |
1183 | 1206 | <details class="lp-raw"><summary>Show raw JSON</summary><pre id="lp-raw-json">No data yet.</pre></details> |
@@ -1445,62 +1468,59 @@ <h2>Trust the proof.<br><span class="grad">Not the agent.</span></h2> |
1445 | 1468 | const knownKid = 'vC4WbcNoq2znSCiQ'; |
1446 | 1469 | const stateEls = Object.fromEntries(['resolve','sign','verify','tamper','reject'].map(k => [k, document.querySelector(`[data-live-state="${k}"]`)])); |
1447 | 1470 | const metaEls = Object.fromEntries(['resolve','sign','verify','tamper','reject'].map(k => [k, document.querySelector(`[data-live-meta="${k}"]`)])); |
| 1471 | + const resultEls = Object.fromEntries(['resolve','sign','verify','tamper','reject'].map(k => [k, document.querySelector(`[data-live-result="${k}"]`)])); |
1448 | 1472 | const rowEls = Object.fromEntries(['resolve','sign','verify','tamper','reject'].map(k => [k, document.querySelector(`[data-live-step="${k}"]`)])); |
1449 | 1473 | const validSummary = document.getElementById('lp-valid-summary'); |
1450 | 1474 | const invalidSummary = document.getElementById('lp-invalid-summary'); |
1451 | 1475 | const raw = document.getElementById('lp-raw-json'); |
1452 | 1476 | const err = document.getElementById('lp-error'); |
1453 | 1477 | const compact = v => typeof v === 'string' && v.length > 18 ? `${v.slice(0,10)}…${v.slice(-8)}` : String(v ?? 'n/a'); |
1454 | | - const setStep = (name, status, meta) => { rowEls[name].className = `lp-row ${status}`; stateEls[name].textContent = status; metaEls[name].textContent = meta; }; |
1455 | | - const normalize = r => ({ status: r?.status || (r?.ok === true ? 'VALID' : 'INVALID'), hash_matches: r?.hash_matches, signature_valid: r?.signature_valid }); |
| 1478 | + const setStep = (name, status, meta, result) => { rowEls[name].className = `lp-row ${status}`; stateEls[name].textContent = status; metaEls[name].textContent = meta; if (resultEls[name] && result) resultEls[name].textContent = result; }; |
| 1479 | + const valueOrDash = v => (v === true || v === false ? String(v) : 'not returned'); |
| 1480 | + const pickCheck = (r, k) => r?.[k] ?? r?.checks?.[k] ?? r?.result?.[k]; |
| 1481 | + const normalize = r => ({ status: r?.status || (r?.ok === true ? 'VALID' : 'INVALID'), hash_matches: pickCheck(r,'hash_matches'), signature_valid: pickCheck(r,'signature_valid') }); |
1456 | 1482 | const isValid = r => r?.ok === true || r?.status === 'VALID' || r?.status === 'VERIFIED'; |
1457 | 1483 |
|
1458 | 1484 | async function runLive() { |
1459 | 1485 | err.style.display = 'none'; |
1460 | | - ['resolve','sign','verify','tamper','reject'].forEach(k => setStep(k,'pending','pending')); |
1461 | | - setStep('resolve','running','Signer identity loaded'); |
| 1486 | + ['resolve','sign','verify','tamper','reject'].forEach(k => setStep(k,'pending','pending','waiting...')); |
| 1487 | + setStep('resolve','running','resolving signer identity...','querying runtime.commandlayer.eth'); |
1462 | 1488 | await Promise.resolve(); |
1463 | | - setStep('resolve','passed',`signer_id=${signerId} · kid=${knownKid}`); |
| 1489 | + setStep('resolve','passed',`runtime.commandlayer.eth · kid=${knownKid}`,'resolved signer identity'); |
1464 | 1490 |
|
1465 | 1491 | let receipt; |
1466 | 1492 | try { |
1467 | | - setStep('sign','running','POST /trust-verification/sign/v1.0.0'); |
| 1493 | + setStep('sign','running','calling production runtime sign endpoint...','POST https://runtime.commandlayer.org/trust-verification/sign/v1.0.0'); |
1468 | 1494 | const signResp = await fetch(`${runtimeBase}/trust-verification/sign/v1.0.0`, { method:'POST', headers:{'content-type':'application/json'}, body: JSON.stringify({ payload:{ message:'homepage live proof', source:'commandlayer.org', ts:new Date().toISOString() } }) }); |
1469 | 1495 | const signJson = await signResp.json(); |
1470 | 1496 | receipt = signJson?.receipt || signJson?.final_receipt; |
1471 | 1497 | if (!signResp.ok || !receipt) throw new Error('TRANSPORT_ERROR'); |
1472 | 1498 | const proof = receipt?.metadata?.proof || {}; |
1473 | | - setStep('sign','passed',`verb=${receipt?.verb||'n/a'} class=${receipt?.class||'n/a'} hash=${compact(proof?.hash?.value)} kid=${proof?.signature?.kid||'n/a'} signer_id=${proof?.signer_id||'n/a'}`); |
| 1499 | + setStep('sign','passed',`runtime signed metadata.proof`,`verb=${receipt?.verb||'n/a'} hash=${compact(proof?.hash?.value)} kid=${proof?.signature?.kid||'n/a'} signer_id=${proof?.signer_id||'n/a'}`); |
1474 | 1500 |
|
1475 | | - setStep('verify','running','POST /verify'); |
| 1501 | + setStep('verify','running','verifying original receipt...','POST https://runtime.commandlayer.org/verify'); |
1476 | 1502 | const verifyResp = await fetch(`${runtimeBase}/verify`, { method:'POST', headers:{'content-type':'application/json'}, body: JSON.stringify({ receipt }) }); |
1477 | 1503 | const verifyJson = await verifyResp.json(); |
1478 | 1504 | const v = normalize(verifyJson); |
1479 | 1505 | if (!verifyResp.ok || !isValid(verifyJson)) throw new Error('VERIFY_INVALID'); |
1480 | | - setStep('verify','passed',`verifier_status=${v.status} hash_matches=${String(v.hash_matches)} signature_valid=${String(v.signature_valid)}`); |
1481 | | - validSummary.textContent = `VALID |
1482 | | -verifier_status: ${v.status} |
1483 | | -hash_matches: ${String(v.hash_matches)} |
1484 | | -signature_valid: ${String(v.signature_valid)}`; |
| 1506 | + setStep('verify','passed',`original receipt ${v.status}`,`hash_matches=${valueOrDash(v.hash_matches)} signature_valid=${valueOrDash(v.signature_valid)}`); |
| 1507 | + validSummary.innerHTML = `<div class="status">VALID</div><div class="line">verifier_status: ${v.status}</div><div class="line">hash_matches: ${valueOrDash(v.hash_matches)}</div><div class="line">signature_valid: ${valueOrDash(v.signature_valid)}</div>`; |
1485 | 1508 |
|
1486 | | - setStep('tamper','running','Mutating receipt.result.payload.message'); |
| 1509 | + setStep('tamper','running','modifying payload output text...','canonical payload mutated'); |
1487 | 1510 | const tampered = JSON.parse(JSON.stringify(receipt)); |
1488 | 1511 | if (!tampered.result) tampered.result = {}; |
1489 | 1512 | if (!tampered.result.payload) tampered.result.payload = {}; |
1490 | 1513 | tampered.result.payload.message = 'tampered homepage proof'; |
1491 | | - setStep('tamper','passed','message="tampered homepage proof"'); |
| 1514 | + setStep('tamper','passed','payload tampered (same signer metadata retained)','tampered receipt prepared'); |
1492 | 1515 |
|
1493 | | - setStep('reject','running','POST /verify with tampered receipt'); |
| 1516 | + setStep('reject','running','verifying tampered receipt...','expect INVALID result'); |
1494 | 1517 | const rejectResp = await fetch(`${runtimeBase}/verify`, { method:'POST', headers:{'content-type':'application/json'}, body: JSON.stringify({ receipt: tampered }) }); |
1495 | 1518 | const rejectJson = await rejectResp.json(); |
1496 | 1519 | const t = normalize(rejectJson); |
1497 | 1520 | const tamperRejected = !isValid(rejectJson); |
1498 | 1521 | if (!rejectResp.ok || !tamperRejected) throw new Error('REJECT_EXPECTED'); |
1499 | | - setStep('reject','failed',`tampered_status=${t.status} hash_matches=${String(t.hash_matches)} signature_valid=${String(t.signature_valid)}`); |
1500 | | - invalidSummary.textContent = `INVALID |
1501 | | -tampered_status: ${t.status} |
1502 | | -hash_matches: ${String(t.hash_matches)} |
1503 | | -signature_valid: ${String(t.signature_valid)}`; |
| 1522 | + setStep('reject','failed',`tampered receipt ${t.status}`,`hash_matches=${valueOrDash(t.hash_matches)} signature_valid=${valueOrDash(t.signature_valid)}`); |
| 1523 | + invalidSummary.innerHTML = `<div class="status">INVALID</div><div class="line">tampered_status: ${t.status}</div><div class="line">hash_matches: ${valueOrDash(t.hash_matches)}</div><div class="line">signature_valid: ${valueOrDash(t.signature_valid)}</div>`; |
1504 | 1524 | raw.textContent = JSON.stringify({ sign_response: signJson, verify_response: verifyJson, tampered_verify_response: rejectJson }, null, 2); |
1505 | 1525 | } catch (e) { |
1506 | 1526 | err.style.display = 'block'; |
|
0 commit comments