Trustvice è in beta limitata. Alla registrazione o all’accesso devi inserire la password da beta tester che hai ricevuto oppure richiederne una a preview@trustvice.com. Grazie.
Caricamento…
Ingegneria
Verifiche
Tutorial
Verificare una ricevuta offline, in circa quaranta righe di codice
Un esempio pratico che costruisce un verificatore di ricevute senza dipendenze con WebCrypto, lo controlla su un test vector firmato, dimostra che rifiuta le ricevute manomesse e poi porta la stessa procedura in Python e nella shell.
Di The Trustvice team··5 min lettura
Inizia gratis
Trustvice 360
Dichiara le regole. Fai controllare ogni esecuzione.
Agenti, prove, governance, commercio e informativa sono in Trustvice 360. Registrati gratis e apri tutte le suite da un'unica dashboard.
Il modo più forte di controllare una ricevuta Trustvice è con codice che controlli tu, su una macchina che controlli tu, con chiavi che hai fissato tu. Questo post costruisce quel verificatore da zero. Alla fine avrai un unico modulo JavaScript senza dipendenze, un test vector che prova che funziona e una lista di casi che provano che fallisce quando deve.
Node 20 o successivo, o qualsiasi runtime il cui crypto.subtle supporti Ed25519: browser attuali, Deno, Bun e Cloudflare Workers vanno tutti bene. Nessun pacchetto da installare. Non ti serve nemmeno un account Trustvice: il test vector qui sotto è firmato con una chiave usa e getta generata per questo post.
Salva questo come receipt.json. È una ricevuta di test firmata con quella chiave usa e getta. Il body è solo illustrativo; conta che sia firmata davvero.
Per le ricevute reali sostituirai keys.json con il set pubblicato su https://trustvice.com/.well-known/receipt-keys.json, idealmente una copia che hai fissato. La procedura non cambia.
La firma copre la forma canonica RFC 8785 della ricevuta senza il suo membro signature. In JavaScript, JSON.stringify produce già la forma numerica ECMAScript e l’escape minimo delle stringhe. Resta da ordinare le chiavi degli oggetti, ricorsivamente, per unità di codice UTF-16, che è l’ordine di default di Array.prototype.sort:
js
function canonicalize(value) {
if (Array.isArray(value)) return value.map(canonicalize);
if (value && typeof value === "object") {
return Object.fromEntries(
Object.keys(value).sort().map((key) => [key, canonicalize(value[key])]),
);
}
return value;
}
exportconst jcs = (value) => JSON.stringify(canonicalize(value));
Per il test vector, la stringa canonica è una riga senza spazi:
Passo 4: controlla la forma, trova la chiave, verifica#
Ora il verificatore vero e proprio. Non lancia mai eccezioni su input ostili; restituisce uno di tre motivi, gli stessi usati dalla pagina di verifica e dall’API.
Nota la riga di destructuring. Rimuove signature e tiene tutto il resto, compresi i membri che questo codice non ha mai visto. È voluto: ogni membro tranne signature è firmato, quindi un verificatore che scarta un membro che non riconosce rifiuterebbe ricevute valide.
Metti insieme i tre snippet in verify-receipt.mjs. Quello è tutto il verificatore.
Un piccolo wrapper da riga di comando legge i file ed esce con 0 per una ricevuta valida e 1 altrimenti. Accetta anche il wrapper { "receipt": … } restituito dall’API:
Il kid deriva dalla chiave: è il base64url dei primi 16 byte dello SHA-256 dei 32 byte grezzi di x. Per la chiave di test risulta LfPAIisXFvNmFhD6vBQbBw. Ricalcolarlo conferma che la voce nel tuo file di chiavi è coerente con sé stessa:
js
exportasyncfunction keyIdOf(x) {
const digest = await crypto.subtle.digest("SHA-256", base64urlToBytes(x));
let bin = "";
for (const b ofnew Uint8Array(digest).slice(0, 16)) bin += String.fromCharCode(b);
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
La procedura è la stessa ovunque, ma due linguaggi richiedono attenzione.
Python.json.dumps non è JCS: stampa i float interi come 1.0, riempie gli esponenti e di default fa l’escape dei caratteri non ASCII. Un port in Python ha bisogno di un piccolo serializzatore RFC 8785 che ordini le chiavi per unità di codice UTF-16, e può verificare con Ed25519PublicKey del pacchetto cryptography.
Shell. Con jq e OpenSSL 3, jq -S -c 'del(.signature)' produce i byte canonici delle ricevute, perché i loro body contengono solo stringhe, interi, booleani, null, array e oggetti. Non è un’implementazione JCS generale, ma per una ricevuta o corrisponde o fallisce; non ne fa mai passare una che non dovrebbe. La chiave pubblica viene incapsulata in una SubjectPublicKeyInfo DER anteponendo un header fisso di 12 byte ai 32 byte grezzi, e openssl pkeyutl -verify -rawin fa il resto. La LibreSSL inclusa in macOS non ci riesce; installa OpenSSL 3.
Una firma valida prova origine, integrità e un’ora firmata: il titolare di una chiave di firma Trustvice ha firmato esattamente questi byte, nulla è cambiato da allora, e Trustvice afferma l’ora in issuedAt. Non prova che un fatto da te fornito sia vero, e non contiene i tuoi contenuti. Per mostrare che un documento corrisponde a una ricevuta, calcola tu l’hash del documento e confrontalo. Trattiamo questi confini in What a receipt proves, and what it does not.
Per un controllo rapido senza scrivere codice, incolla una ricevuta qualsiasi su /verify. Esegue la stessa procedura nel tuo browser e non ci invia mai la ricevuta.
Incolla una qualsiasi ricevuta Trustvice nel verificatore. Controlla la firma nel tuo browser con le nostre chiavi pubblicate, senza bisogno di un account.