aqta-verify-receipt 1.0.2 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -128
- package/bin/aqta-verify-receipt.js +2 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +170 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +23 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -15
- package/dist/index.js.map +1 -1
- package/package.json +22 -11
- package/dist/index.test.d.ts +0 -6
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -85
- package/dist/index.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,172 +1,138 @@
|
|
|
1
|
+
```
|
|
2
|
+
▄▄▄▄▄▄▄▄
|
|
3
|
+
▄███████▀████▄▄
|
|
4
|
+
▄████████████████
|
|
5
|
+
██████████████▀▀
|
|
6
|
+
█████████████▀
|
|
7
|
+
▄█████████████
|
|
8
|
+
▄██████████████
|
|
9
|
+
▄█████████████████
|
|
10
|
+
▄███████████████████
|
|
11
|
+
████████████████████ ▄
|
|
12
|
+
██████████████▀ ████ ▄▀
|
|
13
|
+
▀▀█████████▀ ███▀ ▄▄▀▀
|
|
14
|
+
▀▀▀██▄▄▄▄▄▄██▀ ▀▀
|
|
15
|
+
```
|
|
16
|
+
|
|
1
17
|
# aqta-verify-receipt
|
|
2
18
|
|
|
3
19
|
[](https://www.npmjs.com/package/aqta-verify-receipt)
|
|
4
|
-
[](
|
|
20
|
+
[](https://pypi.org/project/aqta-verify-receipt/)
|
|
21
|
+
[](LICENSE)
|
|
6
22
|
|
|
7
|
-
|
|
8
|
-
receipts. Checks the Ed25519 signature on an enforcement-attestation
|
|
9
|
-
receipt using only the published public key: **no dependency on Aqta's
|
|
10
|
-
servers**.
|
|
23
|
+
Offline verifier for **Seal** receipts ([ATTESTATION-v1](https://github.com/Aqta-ai/attestation-spec/blob/main/spec/ATTESTATION-v1.md)).
|
|
11
24
|
|
|
12
|
-
|
|
25
|
+
Seal signs the model call at runtime. This package checks that signature
|
|
26
|
+
without contacting Aqta. No account. Exit code only if you want it quiet.
|
|
13
27
|
|
|
14
|
-
|
|
15
|
-
Regulators, auditors, and internal compliance teams need to verify
|
|
16
|
-
those receipts independently, without trusting the issuer. This
|
|
17
|
-
package is the reference implementation of that verifier, maintained
|
|
18
|
-
by Aqta under the open
|
|
19
|
-
[ATTESTATION-v1](https://github.com/Aqta-ai/attestation-spec/blob/main/spec/ATTESTATION-v1.md)
|
|
20
|
-
format specification.
|
|
28
|
+
Same algorithm on npm and PyPI. Reference implementation, not a platform SDK.
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
validate its own production receipts and to power the receipt-
|
|
24
|
-
verification endpoint exposed to customer audit teams.
|
|
25
|
-
|
|
26
|
-
## Install
|
|
30
|
+
## 30-second check
|
|
27
31
|
|
|
28
32
|
```bash
|
|
29
|
-
|
|
33
|
+
# download a receipt JSON, then:
|
|
34
|
+
npx aqta-verify-receipt@1.0.5 receipt.json \
|
|
35
|
+
--key gUoUhIvptKAoLTnry3VrDtOQEWggGQveLrHFVrfNqmE
|
|
30
36
|
```
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
Ed25519 verification.
|
|
34
|
-
|
|
35
|
-
## Usage
|
|
36
|
-
|
|
37
|
-
```ts
|
|
38
|
-
import { verifyReceipt, fetchPublishedPublicKey } from 'aqta-verify-receipt';
|
|
38
|
+
Or pipe a public share link body:
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// EVERY VERIFICATION: load the pinned value, do not re-fetch.
|
|
45
|
-
const pinned = loadFromConfig();
|
|
46
|
-
const result = verifyReceipt(receipt, { trustedPublicKey: pinned });
|
|
47
|
-
|
|
48
|
-
if (!result.valid) {
|
|
49
|
-
throw new Error(`Receipt invalid: ${result.reason}`);
|
|
50
|
-
}
|
|
40
|
+
```bash
|
|
41
|
+
curl -sS https://api.aqta.ai/r/YOUR_RECEIPT_ID | npx aqta-verify-receipt@1.0.5 - \
|
|
42
|
+
--key gUoUhIvptKAoLTnry3VrDtOQEWggGQveLrHFVrfNqmE
|
|
51
43
|
```
|
|
52
44
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
`fetchPublishedPublicKey()` performs a live HTTPS fetch. Calling it
|
|
56
|
-
inside a verification loop collapses the trust model back to "trust the
|
|
57
|
-
issuer's server right now", which is exactly what this format is
|
|
58
|
-
designed to avoid.
|
|
45
|
+
`ok` + exit `0` means the Ed25519 signature verifies against the pinned key.
|
|
46
|
+
`fail` + exit `1` means it does not. Exit `2` is usage or IO.
|
|
59
47
|
|
|
60
|
-
|
|
48
|
+
Production public key (also at
|
|
49
|
+
[`/v1/attestation/public-key`](https://api.aqta.ai/v1/attestation/public-key),
|
|
50
|
+
key id `aqta-att-0a18c7c16bc18a12`):
|
|
61
51
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
thereafter.
|
|
66
|
-
4. Rotate only when you receive a documented key-rotation notice via a
|
|
67
|
-
channel you already trust.
|
|
52
|
+
```
|
|
53
|
+
gUoUhIvptKAoLTnry3VrDtOQEWggGQveLrHFVrfNqmE
|
|
54
|
+
```
|
|
68
55
|
|
|
69
|
-
|
|
56
|
+
Pin that string. Do not re-fetch it inside a verify loop.
|
|
70
57
|
|
|
71
|
-
##
|
|
58
|
+
## Install
|
|
72
59
|
|
|
73
|
-
|
|
60
|
+
```bash
|
|
61
|
+
npm install aqta-verify-receipt
|
|
62
|
+
# or one-shot:
|
|
63
|
+
npx aqta-verify-receipt receipt.json --key <pinned>
|
|
64
|
+
```
|
|
74
65
|
|
|
75
|
-
|
|
76
|
-
public key.
|
|
66
|
+
Two runtime deps: `tweetnacl`, `tweetnacl-util`.
|
|
77
67
|
|
|
78
|
-
|
|
79
|
-
- `trustedPublicKey`: base64url public key. If set, the receipt's
|
|
80
|
-
`public_key` field must match byte for byte. **Strongly recommended
|
|
81
|
-
for production.**
|
|
82
|
-
- `strictFields` (default `true`): any unknown top-level field causes
|
|
83
|
-
rejection, per ATTESTATION-v1 §4. See "Forward compatibility" below.
|
|
68
|
+
## Library
|
|
84
69
|
|
|
85
|
-
|
|
70
|
+
```ts
|
|
71
|
+
import { verifyReceipt, fetchPublishedPublicKey } from 'aqta-verify-receipt';
|
|
86
72
|
|
|
87
|
-
|
|
73
|
+
// Once per environment: fetch, then pin somewhere you control.
|
|
74
|
+
const trustedPublicKey = await fetchPublishedPublicKey();
|
|
88
75
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
76
|
+
const result = verifyReceipt(receipt, { trustedPublicKey });
|
|
77
|
+
if (!result.valid) throw new Error(result.reason);
|
|
78
|
+
```
|
|
92
79
|
|
|
93
|
-
|
|
80
|
+
### Pin the key
|
|
94
81
|
|
|
95
|
-
`
|
|
96
|
-
|
|
97
|
-
against. This is the correct behaviour for a security-critical
|
|
98
|
-
verifier: a receipt containing an unknown field may carry
|
|
99
|
-
attacker-controlled metadata that downstream systems should not treat
|
|
100
|
-
as signed evidence.
|
|
82
|
+
`fetchPublishedPublicKey()` is for first-time setup. Calling it on every
|
|
83
|
+
verify collapses trust back to "trust the issuer's server right now".
|
|
101
84
|
|
|
102
|
-
|
|
85
|
+
1. Fetch once.
|
|
86
|
+
2. Persist (config, KMS, secret store).
|
|
87
|
+
3. Pass `trustedPublicKey` on every call.
|
|
88
|
+
4. Rotate only on a documented key-rotation notice.
|
|
103
89
|
|
|
104
|
-
|
|
105
|
-
field changes. Your verifier keeps working.
|
|
106
|
-
- **Minor** versions of the spec (v1.x.0): may add new optional
|
|
107
|
-
fields. A v1.0-era verifier will reject v1.1 receipts under
|
|
108
|
-
`strictFields: true`. Upgrade the verifier, or set
|
|
109
|
-
`strictFields: false` to let forward receipts through the signature
|
|
110
|
-
check. Cryptographic verification still holds in both cases; only
|
|
111
|
-
the structural-allowlist check is relaxed.
|
|
112
|
-
- **Major** versions (vN.0, N ≥ 2): breaking changes; upgrade
|
|
113
|
-
required.
|
|
90
|
+
## CLI
|
|
114
91
|
|
|
115
|
-
|
|
116
|
-
|
|
92
|
+
```
|
|
93
|
+
aqta-verify-receipt <file|-> --key <base64url> [--no-strict] [-q]
|
|
94
|
+
aqta-verify-receipt <file|-> --integrity-only [--no-strict] [-q]
|
|
95
|
+
```
|
|
117
96
|
|
|
118
|
-
|
|
97
|
+
| Flag | Meaning |
|
|
98
|
+
|------|---------|
|
|
99
|
+
| `--key` | Pin issuer identity (required for counsel-grade). |
|
|
100
|
+
| `--integrity-only` | Signature vs embedded key only; returns untrusted. Anyone can self-sign. |
|
|
101
|
+
| `--no-strict` | Allow unknown top-level fields |
|
|
102
|
+
| `-q` | Silent; exit code only |
|
|
119
103
|
|
|
120
|
-
|
|
121
|
-
each documenting one specific behaviour) lives in the spec repository:
|
|
104
|
+
## API
|
|
122
105
|
|
|
123
|
-
|
|
124
|
-
- Reproducible generator:
|
|
125
|
-
[`test-vectors/generate.py`](https://github.com/Aqta-ai/attestation-spec/blob/main/test-vectors/generate.py)
|
|
106
|
+
### `verifyReceipt(receipt, options?) → { valid, reason?, keySource? }`
|
|
126
107
|
|
|
127
|
-
|
|
128
|
-
|
|
108
|
+
Never throws. **Pinning is required by default.** Without `trustedPublicKey`,
|
|
109
|
+
returns `valid: false` unless `allowUntrustedEmbeddedKey: true` (then
|
|
110
|
+
`keySource: "untrusted"` on success). Default `strictFields: true` rejects
|
|
111
|
+
unknown top-level fields (ATTESTATION-v1 §4).
|
|
129
112
|
|
|
130
|
-
###
|
|
113
|
+
### `fetchPublishedPublicKey(url?) → Promise<string>`
|
|
131
114
|
|
|
132
|
-
|
|
133
|
-
|
|
115
|
+
Default: `https://app.aqta.ai/security/pubkey.txt`. Same material as
|
|
116
|
+
`https://api.aqta.ai/v1/attestation/public-key`.
|
|
134
117
|
|
|
135
|
-
|
|
136
|
-
git clone https://github.com/Aqta-ai/attestation-spec.git
|
|
137
|
-
cd attestation-spec
|
|
138
|
-
npm install aqta-verify-receipt
|
|
139
|
-
node - <<'JS'
|
|
140
|
-
const fs = require('node:fs');
|
|
141
|
-
const path = require('node:path');
|
|
142
|
-
const { verifyReceipt } = require('aqta-verify-receipt');
|
|
143
|
-
|
|
144
|
-
const TRUSTED = 'alWzEnrA_z9McN9z_MFfQCnH9mVgOwRZ26wrI7oix4E';
|
|
145
|
-
|
|
146
|
-
for (const sub of ['valid', 'invalid']) {
|
|
147
|
-
const shouldPass = sub === 'valid';
|
|
148
|
-
for (const name of fs.readdirSync(path.join('test-vectors', sub)).sort()) {
|
|
149
|
-
const r = JSON.parse(fs.readFileSync(path.join('test-vectors', sub, name), 'utf8'));
|
|
150
|
-
const { valid } = verifyReceipt(r, { trustedPublicKey: TRUSTED });
|
|
151
|
-
if (valid !== shouldPass) throw new Error(`${sub}/${name} behaved wrong`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
console.log('all 14 vectors behave as specified');
|
|
155
|
-
JS
|
|
156
|
-
```
|
|
118
|
+
## Test vectors
|
|
157
119
|
|
|
158
|
-
|
|
120
|
+
Conformance suite (6 valid + 8 invalid):
|
|
121
|
+
[`test-vectors/`](https://github.com/Aqta-ai/attestation-spec/tree/main/test-vectors).
|
|
159
122
|
|
|
160
|
-
##
|
|
123
|
+
## What this is not
|
|
161
124
|
|
|
162
|
-
|
|
125
|
+
Not a governance dashboard. Not a cost router. Not a chain explorer.
|
|
126
|
+
A small verifier for one signed model-call receipt.
|
|
163
127
|
|
|
164
|
-
## Security
|
|
128
|
+
## Security
|
|
165
129
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
[SECURITY.md](https://github.com/Aqta-ai/attestation-spec/blob/main/SECURITY.md).
|
|
130
|
+
Cryptographic issues: see [SECURITY.md](../../SECURITY.md). Prefer
|
|
131
|
+
security@aqta.ai over public issues for key or signature bugs.
|
|
169
132
|
|
|
170
133
|
## Licence
|
|
171
134
|
|
|
172
|
-
Apache-2.0.
|
|
135
|
+
Apache-2.0. Aqta Technologies Limited.
|
|
136
|
+
|
|
137
|
+
If you implement or cite the ATTESTATION-v1 format itself, credit under
|
|
138
|
+
CC-BY-4.0: see the repo [CITATION.cff](https://github.com/Aqta-ai/attestation-spec/blob/main/CITATION.cff).
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
/**
|
|
5
|
+
* aqta-verify-receipt CLI.
|
|
6
|
+
*
|
|
7
|
+
* Offline check of an ATTESTATION-v1 receipt. No account. No network by
|
|
8
|
+
* default. Exit 0 if the signature verifies, 1 if not, 2 on usage/IO errors.
|
|
9
|
+
*
|
|
10
|
+
* npx aqta-verify-receipt receipt.json --key <base64url-ed25519-key>
|
|
11
|
+
* curl -sS https://api.aqta.ai/r/REC_ID | npx aqta-verify-receipt - --key <key>
|
|
12
|
+
* npx aqta-verify-receipt receipt.json --integrity-only
|
|
13
|
+
*/
|
|
14
|
+
const fs_1 = require("fs");
|
|
15
|
+
const index_1 = require("./index");
|
|
16
|
+
const PUB_KEY_HINT = 'https://api.aqta.ai/v1/attestation/public-key';
|
|
17
|
+
/**
|
|
18
|
+
* The Seal mark, traced from the brand artwork: head up, snout right,
|
|
19
|
+
* one eye (the notch in the head). Half blocks give twice the vertical
|
|
20
|
+
* resolution per line; plain ASCII is the fallback for non UTF-8 terminals.
|
|
21
|
+
*/
|
|
22
|
+
const SEAL_BLOCK = [
|
|
23
|
+
' ▄▄▄▄▄▄▄▄',
|
|
24
|
+
' ▄███████▀████▄▄',
|
|
25
|
+
' ▄████████████████',
|
|
26
|
+
' ██████████████▀▀',
|
|
27
|
+
' █████████████▀',
|
|
28
|
+
' ▄█████████████',
|
|
29
|
+
' ▄██████████████',
|
|
30
|
+
' ▄█████████████████',
|
|
31
|
+
'▄███████████████████',
|
|
32
|
+
'████████████████████ ▄',
|
|
33
|
+
'██████████████▀ ████ ▄▀',
|
|
34
|
+
' ▀▀█████████▀ ███▀ ▄▄▀▀',
|
|
35
|
+
' ▀▀▀██▄▄▄▄▄▄██▀ ▀▀',
|
|
36
|
+
];
|
|
37
|
+
const SEAL_ASCII = [
|
|
38
|
+
' +%@@@@%+',
|
|
39
|
+
' %@@@@@@oo@@@@@',
|
|
40
|
+
' @@@@@@@@@@@@@@+',
|
|
41
|
+
' +@@@@@@@@@@@+',
|
|
42
|
+
' @@@@@@@@@@@',
|
|
43
|
+
' +@@@@@@@@@@@@%',
|
|
44
|
+
' @@@@@@@@@@@@@@@',
|
|
45
|
+
'@@@@@@@@@@@@@@@@@%',
|
|
46
|
+
'@@@@@@@@@@@@@%@@@%',
|
|
47
|
+
'+%@@@@@@@@@+ @@@',
|
|
48
|
+
' +%@@%+ @@+',
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Human-facing stamp: an intact seal when the signature verifies, a sheared
|
|
52
|
+
* one when it does not, so the shape carries the answer before the word.
|
|
53
|
+
*
|
|
54
|
+
* stderr only, TTY only, so piped runs still see exactly the verdict line.
|
|
55
|
+
*/
|
|
56
|
+
function stamp(valid) {
|
|
57
|
+
if (!process.stderr.isTTY)
|
|
58
|
+
return;
|
|
59
|
+
const utf8 = /UTF-?8/i.test(process.env.LC_ALL || process.env.LC_CTYPE || process.env.LANG || '');
|
|
60
|
+
const ESC = String.fromCharCode(27);
|
|
61
|
+
const colour = process.env.NO_COLOR === undefined;
|
|
62
|
+
const body = colour ? ESC + '[' + (valid ? '32' : '31') + 'm' : '';
|
|
63
|
+
const off = colour ? ESC + '[0m' : '';
|
|
64
|
+
// A failed check shears the mark along its midline: the seal is broken.
|
|
65
|
+
const base = utf8 ? SEAL_BLOCK : SEAL_ASCII;
|
|
66
|
+
const half = Math.ceil(base.length / 2);
|
|
67
|
+
const art = valid ? base : base.map((l, i) => (i < half ? l : ' ' + l));
|
|
68
|
+
const painted = art.map((l) => body + l + off);
|
|
69
|
+
painted.push(body + (valid ? ' sealed' : ' broken') + off);
|
|
70
|
+
process.stderr.write(painted.join('\n') + '\n');
|
|
71
|
+
}
|
|
72
|
+
function usage() {
|
|
73
|
+
console.error(`aqta-verify-receipt - offline check for ATTESTATION-v1 (Seal)
|
|
74
|
+
|
|
75
|
+
Usage:
|
|
76
|
+
aqta-verify-receipt <receipt.json | -> --key <base64url> [--no-strict] [-q]
|
|
77
|
+
aqta-verify-receipt <receipt.json | -> --integrity-only [--no-strict] [-q]
|
|
78
|
+
|
|
79
|
+
Options:
|
|
80
|
+
--key <key> pin the issuer public key (required for counsel-grade)
|
|
81
|
+
--integrity-only check signature vs embedded key only (anyone can self-sign)
|
|
82
|
+
--no-strict allow unknown top-level fields
|
|
83
|
+
-q, --quiet exit code only
|
|
84
|
+
|
|
85
|
+
Pin the production key once from ${PUB_KEY_HINT}
|
|
86
|
+
(field public_key). Do not re-fetch on every verify.
|
|
87
|
+
`);
|
|
88
|
+
process.exit(2);
|
|
89
|
+
}
|
|
90
|
+
function main() {
|
|
91
|
+
const args = process.argv.slice(2);
|
|
92
|
+
if (args.length === 0 || args.includes('--help') || args.includes('-h'))
|
|
93
|
+
usage();
|
|
94
|
+
let file = '';
|
|
95
|
+
let trustedKey;
|
|
96
|
+
let integrityOnly = false;
|
|
97
|
+
let strict = true;
|
|
98
|
+
let quiet = false;
|
|
99
|
+
for (let i = 0; i < args.length; i++) {
|
|
100
|
+
const a = args[i];
|
|
101
|
+
if (a === '--key') {
|
|
102
|
+
trustedKey = args[++i];
|
|
103
|
+
if (!trustedKey)
|
|
104
|
+
usage();
|
|
105
|
+
}
|
|
106
|
+
else if (a === '--integrity-only') {
|
|
107
|
+
integrityOnly = true;
|
|
108
|
+
}
|
|
109
|
+
else if (a === '--no-strict') {
|
|
110
|
+
strict = false;
|
|
111
|
+
}
|
|
112
|
+
else if (a === '--quiet' || a === '-q') {
|
|
113
|
+
quiet = true;
|
|
114
|
+
}
|
|
115
|
+
else if (!file) {
|
|
116
|
+
file = a;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
usage();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!file)
|
|
123
|
+
usage();
|
|
124
|
+
if (!trustedKey && !integrityOnly) {
|
|
125
|
+
console.error('aqta-verify-receipt: pass --key <pinned> (or --integrity-only for embedded-key checks)');
|
|
126
|
+
process.exit(2);
|
|
127
|
+
}
|
|
128
|
+
if (trustedKey && integrityOnly) {
|
|
129
|
+
console.error('aqta-verify-receipt: use --key or --integrity-only, not both');
|
|
130
|
+
process.exit(2);
|
|
131
|
+
}
|
|
132
|
+
let raw;
|
|
133
|
+
try {
|
|
134
|
+
raw = file === '-' ? (0, fs_1.readFileSync)(0, 'utf8') : (0, fs_1.readFileSync)(file, 'utf8');
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
console.error(`aqta-verify-receipt: cannot read ${file === '-' ? 'stdin' : file}`);
|
|
138
|
+
process.exit(2);
|
|
139
|
+
}
|
|
140
|
+
let receipt;
|
|
141
|
+
try {
|
|
142
|
+
receipt = JSON.parse(raw);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
console.error('aqta-verify-receipt: input is not valid JSON');
|
|
146
|
+
process.exit(2);
|
|
147
|
+
}
|
|
148
|
+
const result = (0, index_1.verifyReceipt)(receipt, {
|
|
149
|
+
trustedPublicKey: trustedKey,
|
|
150
|
+
allowUntrustedEmbeddedKey: integrityOnly,
|
|
151
|
+
strictFields: strict,
|
|
152
|
+
});
|
|
153
|
+
if (!quiet) {
|
|
154
|
+
stamp(result.valid);
|
|
155
|
+
const id = typeof receipt.attestation_id === 'string' ? receipt.attestation_id : '?';
|
|
156
|
+
const outcome = typeof receipt.outcome === 'string' ? receipt.outcome : '?';
|
|
157
|
+
if (result.valid) {
|
|
158
|
+
const trust = result.keySource === 'pinned'
|
|
159
|
+
? 'pinned key'
|
|
160
|
+
: 'untrusted embedded key (integrity only)';
|
|
161
|
+
console.log(`ok ${outcome} ${id} ${trust}`);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
console.log(`fail ${result.reason ?? 'verification failed'} ${id}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
process.exit(result.valid ? 0 : 1);
|
|
168
|
+
}
|
|
169
|
+
main();
|
|
170
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* aqta-verify-receipt
|
|
3
3
|
*
|
|
4
|
-
* Independent verifier for
|
|
4
|
+
* Independent verifier for Seal attestation receipts (ATTESTATION-v1).
|
|
5
5
|
* Verifies the Ed25519 signature on a receipt using only the published
|
|
6
6
|
* public key: no dependency on any third-party server.
|
|
7
7
|
*
|
|
@@ -24,14 +24,19 @@ export interface AttestationReceipt {
|
|
|
24
24
|
}
|
|
25
25
|
export interface VerifyOptions {
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* prevents an attacker from substituting a different key.
|
|
27
|
+
* Trusted issuer public key (base64url, no padding). Required for a
|
|
28
|
+
* counsel-grade check: the receipt must carry this key and verify under it.
|
|
30
29
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* Omit only with `allowUntrustedEmbeddedKey: true` for integrity-only
|
|
31
|
+
* checks against whatever key the receipt embeds (anyone can self-sign).
|
|
33
32
|
*/
|
|
34
33
|
trustedPublicKey?: string;
|
|
34
|
+
/**
|
|
35
|
+
* If true, verify against the receipt's embedded `public_key` without
|
|
36
|
+
* pinning an issuer. Result includes `keySource: "untrusted"`. Default
|
|
37
|
+
* false: without `trustedPublicKey`, verification fails.
|
|
38
|
+
*/
|
|
39
|
+
allowUntrustedEmbeddedKey?: boolean;
|
|
35
40
|
/**
|
|
36
41
|
* If true, unknown top-level fields in the receipt cause rejection. Default
|
|
37
42
|
* true per spec §4: "Verifiers MUST reject receipts containing unknown
|
|
@@ -39,18 +44,24 @@ export interface VerifyOptions {
|
|
|
39
44
|
*/
|
|
40
45
|
strictFields?: boolean;
|
|
41
46
|
}
|
|
47
|
+
export type KeySource = 'pinned' | 'untrusted';
|
|
42
48
|
export interface VerifyResult {
|
|
43
49
|
valid: boolean;
|
|
44
50
|
reason?: string;
|
|
51
|
+
/** Present when `valid` is true. */
|
|
52
|
+
keySource?: KeySource;
|
|
45
53
|
}
|
|
46
54
|
/**
|
|
47
|
-
* Verify
|
|
55
|
+
* Verify a Seal attestation receipt.
|
|
56
|
+
*
|
|
57
|
+
* Pinning is required by default. A self-signed receipt must not return
|
|
58
|
+
* `valid: true` unless `allowUntrustedEmbeddedKey` is set.
|
|
48
59
|
*
|
|
49
60
|
* @param receipt The full receipt object (including `signature`).
|
|
50
|
-
* @param options
|
|
51
|
-
* @returns `{ valid: true }` if the signature is valid under
|
|
52
|
-
*
|
|
53
|
-
* `{ valid: false, reason: string }`.
|
|
61
|
+
* @param options Verification constraints.
|
|
62
|
+
* @returns `{ valid: true, keySource }` if the signature is valid under
|
|
63
|
+
* the pinned (or explicitly allowed embedded) public key;
|
|
64
|
+
* otherwise `{ valid: false, reason: string }`.
|
|
54
65
|
*
|
|
55
66
|
* @example
|
|
56
67
|
* const result = verifyReceipt(receipt, {
|
|
@@ -60,7 +71,7 @@ export interface VerifyResult {
|
|
|
60
71
|
*/
|
|
61
72
|
export declare function verifyReceipt(receipt: unknown, options?: VerifyOptions): VerifyResult;
|
|
62
73
|
/**
|
|
63
|
-
* Fetch the
|
|
74
|
+
* Fetch the Seal public key from the published URL and return it as a
|
|
64
75
|
* base64url string ready to pass to `verifyReceipt` as `trustedPublicKey`.
|
|
65
76
|
*
|
|
66
77
|
* **PIN THE RESULT.** This helper performs a live HTTPS fetch. Calling it
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;IACzD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;IACzD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAEpC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAsED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAqFd;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,SAA4C,GAC9C,OAAO,CAAC,MAAM,CAAC,CAMjB"}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* aqta-verify-receipt
|
|
4
4
|
*
|
|
5
|
-
* Independent verifier for
|
|
5
|
+
* Independent verifier for Seal attestation receipts (ATTESTATION-v1).
|
|
6
6
|
* Verifies the Ed25519 signature on a receipt using only the published
|
|
7
7
|
* public key: no dependency on any third-party server.
|
|
8
8
|
*
|
|
@@ -67,24 +67,29 @@ function canonicalValue(v) {
|
|
|
67
67
|
return '[' + v.map(canonicalValue).join(',') + ']';
|
|
68
68
|
}
|
|
69
69
|
if (typeof v === 'number') {
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
70
|
+
// Spec section 6: integer-valued numbers serialise without a decimal
|
|
71
|
+
// point. JSON.stringify does that natively, so nothing extra is needed
|
|
72
|
+
// here. Python's json.dumps does NOT (it yields "0.0" for float 0.0),
|
|
73
|
+
// which is why the spec puts the coercion duty on the issuer: an
|
|
74
|
+
// integer-valued float must become an int before it is signed. A receipt
|
|
75
|
+
// carrying a literal "0.0" was signed by a non-conforming issuer, and
|
|
76
|
+
// failing it is correct behaviour, not a gap in this verifier.
|
|
75
77
|
return JSON.stringify(v);
|
|
76
78
|
}
|
|
77
79
|
// Strings, booleans
|
|
78
80
|
return JSON.stringify(v);
|
|
79
81
|
}
|
|
80
82
|
/**
|
|
81
|
-
* Verify
|
|
83
|
+
* Verify a Seal attestation receipt.
|
|
84
|
+
*
|
|
85
|
+
* Pinning is required by default. A self-signed receipt must not return
|
|
86
|
+
* `valid: true` unless `allowUntrustedEmbeddedKey` is set.
|
|
82
87
|
*
|
|
83
88
|
* @param receipt The full receipt object (including `signature`).
|
|
84
|
-
* @param options
|
|
85
|
-
* @returns `{ valid: true }` if the signature is valid under
|
|
86
|
-
*
|
|
87
|
-
* `{ valid: false, reason: string }`.
|
|
89
|
+
* @param options Verification constraints.
|
|
90
|
+
* @returns `{ valid: true, keySource }` if the signature is valid under
|
|
91
|
+
* the pinned (or explicitly allowed embedded) public key;
|
|
92
|
+
* otherwise `{ valid: false, reason: string }`.
|
|
88
93
|
*
|
|
89
94
|
* @example
|
|
90
95
|
* const result = verifyReceipt(receipt, {
|
|
@@ -123,9 +128,16 @@ function verifyReceipt(receipt, options = {}) {
|
|
|
123
128
|
if (typeof r.request_hash !== 'string' || !/^[0-9a-f]{64}$/.test(r.request_hash)) {
|
|
124
129
|
return { valid: false, reason: 'request_hash must be 64 lowercase hex chars' };
|
|
125
130
|
}
|
|
131
|
+
const pinned = options.trustedPublicKey;
|
|
132
|
+
const allowUntrusted = options.allowUntrustedEmbeddedKey === true;
|
|
133
|
+
if (pinned === undefined && !allowUntrusted) {
|
|
134
|
+
return {
|
|
135
|
+
valid: false,
|
|
136
|
+
reason: 'trustedPublicKey required (pass allowUntrustedEmbeddedKey for integrity-only)',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
126
139
|
// Public-key pinning
|
|
127
|
-
if (
|
|
128
|
-
options.trustedPublicKey !== r.public_key) {
|
|
140
|
+
if (pinned !== undefined && pinned !== r.public_key) {
|
|
129
141
|
return {
|
|
130
142
|
valid: false,
|
|
131
143
|
reason: 'public_key does not match trusted key',
|
|
@@ -152,14 +164,20 @@ function verifyReceipt(receipt, options = {}) {
|
|
|
152
164
|
return { valid: false, reason: 'public key length != 32 bytes' };
|
|
153
165
|
}
|
|
154
166
|
const ok = tweetnacl_1.default.sign.detached.verify(canonical, sig, pub);
|
|
155
|
-
|
|
167
|
+
if (!ok) {
|
|
168
|
+
return { valid: false, reason: 'signature check failed' };
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
valid: true,
|
|
172
|
+
keySource: pinned !== undefined ? 'pinned' : 'untrusted',
|
|
173
|
+
};
|
|
156
174
|
}
|
|
157
175
|
catch (e) {
|
|
158
176
|
return { valid: false, reason: `signature decode error: ${String(e)}` };
|
|
159
177
|
}
|
|
160
178
|
}
|
|
161
179
|
/**
|
|
162
|
-
* Fetch the
|
|
180
|
+
* Fetch the Seal public key from the published URL and return it as a
|
|
163
181
|
* base64url string ready to pass to `verifyReceipt` as `trustedPublicKey`.
|
|
164
182
|
*
|
|
165
183
|
* **PIN THE RESULT.** This helper performs a live HTTPS fetch. Calling it
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;AA6IH,sCAwFC;AAsBD,0DAQC;AAjQD,0DAA6B;AAC7B,oEAAsC;AAoDtC,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC;IACpD,SAAS;IACT,SAAS;IACT,YAAY;IACZ,QAAQ;CACT,CAAC,CAAC;AAEH,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC;IACnD,GAAG;IACH,gBAAgB;IAChB,UAAU;IACV,QAAQ;IACR,cAAc;IACd,OAAO;IACP,SAAS;IACT,gBAAgB;IAChB,oBAAoB;IACpB,WAAW;IACX,YAAY;IACZ,WAAW;CACZ,CAAC,CAAC;AAEH,gEAAgE;AAChE,SAAS,eAAe,CAAC,CAAS;IAChC,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACzD,OAAO,wBAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY,CAAC,OAAgC;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,cAAc,CAAC,CAAU;IAChC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,qEAAqE;QACrE,uEAAuE;QACvE,sEAAsE;QACtE,iEAAiE;QACjE,yEAAyE;QACzE,sEAAsE;QACtE,+DAA+D;QAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IACD,oBAAoB;IACpB,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,aAAa,CAC3B,OAAgB,EAChB,UAAyB,EAAE;IAE3B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACpD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;IAC9D,CAAC;IACD,MAAM,CAAC,GAAG,OAAkC,CAAC;IAE7C,oBAAoB;IACpB,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;YAClB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,KAAK,EAAE,EAAE,CAAC;QACtE,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;QACnC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,4BAA4B,CAAC,EAAE,EAAE,CAAC;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACd,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QACtE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,iCAAiC,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC;QACjF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;IACjF,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IACxC,MAAM,cAAc,GAAG,OAAO,CAAC,yBAAyB,KAAK,IAAI,CAAC;IAElE,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,cAAc,EAAE,CAAC;QAC5C,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EACJ,+EAA+E;SAClF,CAAC;IACJ,CAAC;IAED,qBAAqB;IACrB,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QACpD,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,uCAAuC;SAChD,CAAC;IACJ,CAAC;IAED,kDAAkD;IAClD,MAAM,OAAO,GAA4B,EAAE,GAAG,CAAC,EAAE,CAAC;IAClD,OAAO,OAAO,CAAC,SAAS,CAAC;IAEzB,IAAI,SAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC1E,CAAC;IAED,uBAAuB;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,SAAmB,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,UAAoB,CAAC,CAAC;QACpD,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YACtB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;QAClE,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YACtB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,+BAA+B,EAAE,CAAC;QACnE,CAAC;QACD,MAAM,EAAE,GAAG,mBAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1D,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;QAC5D,CAAC;QACD,OAAO;YACL,KAAK,EAAE,IAAI;YACX,SAAS,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW;SACzD,CAAC;IACJ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC1E,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACI,KAAK,UAAU,uBAAuB,CAC3C,GAAG,GAAG,yCAAyC;IAE/C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACnC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aqta-verify-receipt",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Offline CLI and library for Seal ATTESTATION-v1 receipts. Ed25519 check of a signed model call; no account, no Aqta server required.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"aqta-verify-receipt": "bin/aqta-verify-receipt.js"
|
|
9
|
+
},
|
|
7
10
|
"files": [
|
|
8
|
-
"
|
|
11
|
+
"bin/",
|
|
12
|
+
"dist/cli.js",
|
|
13
|
+
"dist/cli.js.map",
|
|
14
|
+
"dist/cli.d.ts",
|
|
15
|
+
"dist/cli.d.ts.map",
|
|
16
|
+
"dist/index.js",
|
|
17
|
+
"dist/index.js.map",
|
|
18
|
+
"dist/index.d.ts",
|
|
19
|
+
"dist/index.d.ts.map",
|
|
9
20
|
"README.md",
|
|
10
21
|
"LICENSE"
|
|
11
22
|
],
|
|
@@ -15,15 +26,15 @@
|
|
|
15
26
|
"prepublishOnly": "npm run build"
|
|
16
27
|
},
|
|
17
28
|
"keywords": [
|
|
29
|
+
"seal",
|
|
18
30
|
"aqta",
|
|
19
|
-
"
|
|
20
|
-
"attestation",
|
|
31
|
+
"attestation-v1",
|
|
21
32
|
"ed25519",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
33
|
+
"offline-verification",
|
|
34
|
+
"ai-receipts",
|
|
35
|
+
"model-call",
|
|
36
|
+
"tamper-evident",
|
|
37
|
+
"cli"
|
|
27
38
|
],
|
|
28
39
|
"author": "Aqta Technologies Ltd",
|
|
29
40
|
"license": "Apache-2.0",
|
|
@@ -32,7 +43,7 @@
|
|
|
32
43
|
"url": "https://github.com/Aqta-ai/attestation-spec.git",
|
|
33
44
|
"directory": "packages/verify-receipt"
|
|
34
45
|
},
|
|
35
|
-
"homepage": "https://
|
|
46
|
+
"homepage": "https://aqta.ai/verify",
|
|
36
47
|
"bugs": {
|
|
37
48
|
"url": "https://github.com/Aqta-ai/attestation-spec/issues"
|
|
38
49
|
},
|
package/dist/index.test.d.ts
DELETED
package/dist/index.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/index.test.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Interop tests: verify a receipt produced by the Python reference implementation
|
|
4
|
-
* against this TypeScript verifier. Run: `npm run build && node --test dist/index.test.js`.
|
|
5
|
-
*/
|
|
6
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
-
};
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
const node_test_1 = require("node:test");
|
|
11
|
-
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
12
|
-
const index_js_1 = require("./index.js");
|
|
13
|
-
/**
|
|
14
|
-
* Fixture receipt shape, used here to exercise the structural checks.
|
|
15
|
-
* Full signature-level interop is covered by the cross-implementation
|
|
16
|
-
* runner at `scripts/make-interop-fixture.mjs`, which generates a receipt
|
|
17
|
-
* with the reference issuer and verifies it with this library.
|
|
18
|
-
*/
|
|
19
|
-
const FIXTURE_RECEIPT = {
|
|
20
|
-
v: 1,
|
|
21
|
-
attestation_id: 'a3f2b1c4-9d87-4e6f-b012-34567890abcd',
|
|
22
|
-
trace_id: 'trace-fixture-v1',
|
|
23
|
-
org_id: 'org-test',
|
|
24
|
-
request_hash: '8f3a7e2b9c4d5f6a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a',
|
|
25
|
-
model: 'gpt-4o',
|
|
26
|
-
outcome: 'ALLOWED',
|
|
27
|
-
policy_applied: ['budget_guard', 'loop_guard'],
|
|
28
|
-
cost_prevented_eur: 0.0,
|
|
29
|
-
timestamp: '2026-04-23T10:15:30.123456+00:00',
|
|
30
|
-
public_key: '', // populated by make-test-fixture.py
|
|
31
|
-
signature: '', // populated by make-test-fixture.py
|
|
32
|
-
};
|
|
33
|
-
(0, node_test_1.test)('rejects empty object', () => {
|
|
34
|
-
const res = (0, index_js_1.verifyReceipt)({});
|
|
35
|
-
strict_1.default.equal(res.valid, false);
|
|
36
|
-
});
|
|
37
|
-
(0, node_test_1.test)('rejects missing required field', () => {
|
|
38
|
-
const bad = { ...FIXTURE_RECEIPT };
|
|
39
|
-
delete bad.outcome;
|
|
40
|
-
const res = (0, index_js_1.verifyReceipt)(bad);
|
|
41
|
-
strict_1.default.equal(res.valid, false);
|
|
42
|
-
strict_1.default.match(res.reason ?? '', /missing required field/);
|
|
43
|
-
});
|
|
44
|
-
(0, node_test_1.test)('rejects unknown top-level field (strict mode)', () => {
|
|
45
|
-
const bad = { ...FIXTURE_RECEIPT, extra: 'foo' };
|
|
46
|
-
const res = (0, index_js_1.verifyReceipt)(bad);
|
|
47
|
-
strict_1.default.equal(res.valid, false);
|
|
48
|
-
strict_1.default.match(res.reason ?? '', /unknown top-level field/);
|
|
49
|
-
});
|
|
50
|
-
(0, node_test_1.test)('rejects unsupported version', () => {
|
|
51
|
-
const bad = { ...FIXTURE_RECEIPT, v: 2 };
|
|
52
|
-
const res = (0, index_js_1.verifyReceipt)(bad);
|
|
53
|
-
strict_1.default.equal(res.valid, false);
|
|
54
|
-
strict_1.default.match(res.reason ?? '', /unsupported version/);
|
|
55
|
-
});
|
|
56
|
-
(0, node_test_1.test)('rejects invalid outcome', () => {
|
|
57
|
-
const bad = { ...FIXTURE_RECEIPT, outcome: 'YOLO' };
|
|
58
|
-
const res = (0, index_js_1.verifyReceipt)(bad);
|
|
59
|
-
strict_1.default.equal(res.valid, false);
|
|
60
|
-
strict_1.default.match(res.reason ?? '', /invalid outcome/);
|
|
61
|
-
});
|
|
62
|
-
(0, node_test_1.test)('rejects malformed request_hash', () => {
|
|
63
|
-
const bad = { ...FIXTURE_RECEIPT, request_hash: 'not-a-hash' };
|
|
64
|
-
const res = (0, index_js_1.verifyReceipt)(bad);
|
|
65
|
-
strict_1.default.equal(res.valid, false);
|
|
66
|
-
strict_1.default.match(res.reason ?? '', /request_hash/);
|
|
67
|
-
});
|
|
68
|
-
(0, node_test_1.test)('rejects pinned-key mismatch', () => {
|
|
69
|
-
const res = (0, index_js_1.verifyReceipt)(FIXTURE_RECEIPT, {
|
|
70
|
-
trustedPublicKey: 'different_key_000000000000000000000000000000',
|
|
71
|
-
});
|
|
72
|
-
strict_1.default.equal(res.valid, false);
|
|
73
|
-
strict_1.default.match(res.reason ?? '', /does not match trusted key/);
|
|
74
|
-
});
|
|
75
|
-
// Note: full signature-verification interop test requires the fixture to be
|
|
76
|
-
// populated by `scripts/make-test-fixture.py` before running this suite.
|
|
77
|
-
// When FIXTURE_RECEIPT.signature is empty, the signature check is skipped.
|
|
78
|
-
(0, node_test_1.test)('signature decoder rejects empty signature', () => {
|
|
79
|
-
const res = (0, index_js_1.verifyReceipt)(FIXTURE_RECEIPT);
|
|
80
|
-
strict_1.default.equal(res.valid, false);
|
|
81
|
-
// Either the empty signature fails decode or fails length check
|
|
82
|
-
strict_1.default.ok(/signature/.test(res.reason ?? '') ||
|
|
83
|
-
/signature length/.test(res.reason ?? ''));
|
|
84
|
-
});
|
|
85
|
-
//# sourceMappingURL=index.test.js.map
|
package/dist/index.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AAEH,yCAAiC;AACjC,gEAAwC;AACxC,yCAA2C;AAE3C;;;;;GAKG;AACH,MAAM,eAAe,GAAG;IACtB,CAAC,EAAE,CAAC;IACJ,cAAc,EAAE,sCAAsC;IACtD,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,UAAU;IAClB,YAAY,EAAE,kEAAkE;IAChF,KAAK,EAAE,QAAQ;IACf,OAAO,EAAE,SAAkB;IAC3B,cAAc,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;IAC9C,kBAAkB,EAAE,GAAG;IACvB,SAAS,EAAE,kCAAkC;IAC7C,UAAU,EAAE,EAAE,EAAE,oCAAoC;IACpD,SAAS,EAAE,EAAE,EAAG,oCAAoC;CACrD,CAAC;AAEF,IAAA,gBAAI,EAAC,sBAAsB,EAAE,GAAG,EAAE;IAChC,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,EAAE,CAAC,CAAC;IAC9B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,gCAAgC,EAAE,GAAG,EAAE;IAC1C,MAAM,GAAG,GAAG,EAAE,GAAG,eAAe,EAAS,CAAC;IAC1C,OAAO,GAAG,CAAC,OAAO,CAAC;IACnB,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,GAAG,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,wBAAwB,CAAC,CAAC;AAC3D,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,+CAA+C,EAAE,GAAG,EAAE;IACzD,MAAM,GAAG,GAAG,EAAE,GAAG,eAAe,EAAE,KAAK,EAAE,KAAK,EAAS,CAAC;IACxD,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,GAAG,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,yBAAyB,CAAC,CAAC;AAC5D,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,6BAA6B,EAAE,GAAG,EAAE;IACvC,MAAM,GAAG,GAAG,EAAE,GAAG,eAAe,EAAE,CAAC,EAAE,CAAC,EAAS,CAAC;IAChD,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,GAAG,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,qBAAqB,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,yBAAyB,EAAE,GAAG,EAAE;IACnC,MAAM,GAAG,GAAG,EAAE,GAAG,eAAe,EAAE,OAAO,EAAE,MAAM,EAAS,CAAC;IAC3D,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,GAAG,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,iBAAiB,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,gCAAgC,EAAE,GAAG,EAAE;IAC1C,MAAM,GAAG,GAAG,EAAE,GAAG,eAAe,EAAE,YAAY,EAAE,YAAY,EAAS,CAAC;IACtE,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,GAAG,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,cAAc,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAA,gBAAI,EAAC,6BAA6B,EAAE,GAAG,EAAE;IACvC,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,eAAe,EAAE;QACzC,gBAAgB,EAAE,8CAA8C;KACjE,CAAC,CAAC;IACH,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/B,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,4BAA4B,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC;AAEH,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,IAAA,gBAAI,EAAC,2CAA2C,EAAE,GAAG,EAAE;IACrD,MAAM,GAAG,GAAG,IAAA,wBAAa,EAAC,eAAe,CAAC,CAAC;IAC3C,gBAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/B,gEAAgE;IAChE,gBAAM,CAAC,EAAE,CACP,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;QAChC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAC5C,CAAC;AACJ,CAAC,CAAC,CAAC"}
|