# Academy TSP — offline-verifikator

Verktøy for å verifisere et Academy-sertifikatbevis **uten å stole på oss** og **uten nettkall**.
Beviser, etterprøvbart av tredjepart:

> «Denne personen ble stilt disse spørsmålene, svarte slik, på dette tidspunktet — og verken bevis eller svar er endret siden.»

Det finnes to speilede implementasjoner (samme kanonisering, samme resultat):

| Verktøy | Sti | Krever | Bruk |
| ------- | --- | ------ | ---- |
| **Node** (portabel) | `tools/tsp-verify-js/verify-offline.js` | Node 12+ | Kjør hvor som helst, ingen .NET |
| **.NET CLI** (referanse) | `tools/Lexico.Academy.TspVerify/` | .NET 10 SDK | Gjenbruker serverens egen kode |

## Hva du trenger

1. **Konvolutten** (`*.tsp.json`) — last ned fra `https://academy.lexico.no/Certificate/TspEnvelope/{id}` (innlogget) eller `https://academy.lexico.no/api/compliance/certificates/{id}/tsp`.
2. **Offentlig nøkkel** (PEM) — hent fra `https://academy.lexico.no/.well-known/lexico-academy-tsp-key`.
3. *(valgfritt)* **Svar-snapshot** — for å bevise at svarene er uendret. Tilgangsstyrt eksport fra
   `https://academy.lexico.no/Certificate/AssessmentSnapshot/{certificateId}` (krever innlogging + eierskap/firma-admin).

## Node

```bash
node tools/tsp-verify-js/verify-offline.js envelope.tsp.json publickey.pem
# med svar-snapshot:
node tools/tsp-verify-js/verify-offline.js envelope.tsp.json publickey.pem snapshot.json
```

## .NET CLI

Holdt utenfor `Academy.sln` så web-bygg/publish er uberørt. Bygges/kjøres separat:

```powershell
& 'C:\Program Files\dotnet\dotnet.exe' run --project tools\Lexico.Academy.TspVerify -- envelope.tsp.json publickey.pem snapshot.json
```

## Forventet output

```
Konvolutt: GYLDIG
  schema       passed
  contentHash  passed
  signature    passed
  timestamp    passed
  ledgerHash   passed
Vurderingsbevis: MATCHER — svarene er uendret siden signering.
```

Exit-kode `0` = gyldig (og snapshot matcher hvis oppgitt), ellers `1`.

## Hva som sjekkes

- **schema** — konvolutt-versjon er kjent (`4.1`, eller eldre `4.0-draft`).
- **contentHash** — SHA-256 av signert innhold matcher.
- **signature** — Ed25519-signatur over kanonisk signaturdomene, mot publisert nøkkel.
- **timestamp** — RFC3161-token (DigiCert) er til stede.
- **ledgerHash** — ledger-hashen matcher.
- **Vurderingsbevis** — `SHA-256(kanoniske_rader.join("\n"))` fra snapshotet er lik konvoluttens
  `assessmentEvidenceHash`. Radene binder svar, korrekthet, poeng og tidspunkt — **ikke** spørsmålstekst eller persondata.

## Determinisme og personvern

- Kanonisk form for svar-hashen er **spec `v1`** (feltet `assessmentHashSpec` i konvolutten) og er låst av enhetstest.
- Konvolutten inneholder **kun hash** av svarene — aldri rå svar, spørsmålstekst eller persondata.
- Gamle sertifikater uten `assessmentEvidenceHash` verifiseres fortsatt (svar-linjen rapporterer «ingen svar-hash»).

## Hva beviset IKKE er

Beviset bekrefter at **vurderingen ble gjennomført som registrert** og ikke er endret. Det beviser ikke
«personen forstår» i absolutt forstand, og er ikke i seg selv juridisk etterlevelse.
