burnledger 0.2.1 → 0.3.0
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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/cjs/index.browser.d.ts +2 -1
- package/dist/cjs/index.browser.d.ts.map +1 -1
- package/dist/cjs/index.browser.js +7 -1
- package/dist/cjs/index.browser.js.map +1 -1
- package/dist/cjs/index.d.ts +9 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +17 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/keys.d.ts +4 -3
- package/dist/cjs/keys.d.ts.map +1 -1
- package/dist/cjs/keys.js +6 -4
- package/dist/cjs/keys.js.map +1 -1
- package/dist/cjs/models.d.ts +28 -1
- package/dist/cjs/models.d.ts.map +1 -1
- package/dist/cjs/models.js +8 -0
- package/dist/cjs/models.js.map +1 -1
- package/dist/cjs/verify.d.ts +55 -1
- package/dist/cjs/verify.d.ts.map +1 -1
- package/dist/cjs/verify.js +414 -104
- package/dist/cjs/verify.js.map +1 -1
- package/dist/cjs/web-verifier.d.ts +29 -0
- package/dist/cjs/web-verifier.d.ts.map +1 -0
- package/dist/cjs/web-verifier.js +70 -0
- package/dist/cjs/web-verifier.js.map +1 -0
- package/dist/esm/cli.d.ts +3 -0
- package/dist/esm/cli.d.ts.map +1 -1
- package/dist/esm/cli.js +51 -9
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/index.browser.d.ts +2 -1
- package/dist/esm/index.browser.d.ts.map +1 -1
- package/dist/esm/index.browser.js +3 -0
- package/dist/esm/index.browser.js.map +1 -1
- package/dist/esm/index.d.ts +9 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +13 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/keys.d.ts +4 -3
- package/dist/esm/keys.d.ts.map +1 -1
- package/dist/esm/keys.js +6 -4
- package/dist/esm/keys.js.map +1 -1
- package/dist/esm/models.d.ts +28 -1
- package/dist/esm/models.d.ts.map +1 -1
- package/dist/esm/models.js +8 -0
- package/dist/esm/models.js.map +1 -1
- package/dist/esm/verify.d.ts +55 -1
- package/dist/esm/verify.d.ts.map +1 -1
- package/dist/esm/verify.js +411 -105
- package/dist/esm/verify.js.map +1 -1
- package/dist/esm/web-verifier.d.ts +29 -0
- package/dist/esm/web-verifier.d.ts.map +1 -0
- package/dist/esm/web-verifier.js +63 -0
- package/dist/esm/web-verifier.js.map +1 -0
- package/package.json +12 -11
- package/src/cli.ts +207 -0
- package/src/client.ts +555 -0
- package/src/crypto-browser.ts +49 -0
- package/src/crypto-node.ts +40 -0
- package/src/crypto.ts +10 -0
- package/src/errors.ts +154 -0
- package/src/http.ts +209 -0
- package/src/index.browser.ts +110 -0
- package/src/index.ts +134 -0
- package/src/keys.ts +18 -0
- package/src/models.ts +558 -0
- package/src/pagination.ts +64 -0
- package/src/verify.ts +956 -0
- package/src/web-verifier.ts +89 -0
- package/src/webhooks.ts +76 -0
- package/dist/cjs/cli.d.ts +0 -16
- package/dist/cjs/cli.d.ts.map +0 -1
- package/dist/cjs/cli.js +0 -168
- package/dist/cjs/cli.js.map +0 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry point for the public browser verifier at `website/verify/`.
|
|
3
|
+
*
|
|
4
|
+
* Imports the leaf modules directly rather than re-exporting from
|
|
5
|
+
* `index.browser.ts`: that entry pulls in the HTTP client, which imports
|
|
6
|
+
* `node:fs/promises` and cannot be bundled for a browser at all. The page needs
|
|
7
|
+
* four functions, so this exposes four functions — the surface a relying party's
|
|
8
|
+
* browser is handed is then something you can read in one screen instead of
|
|
9
|
+
* inferring from a minified artifact.
|
|
10
|
+
*
|
|
11
|
+
* Built by `scripts/build-web-verifier.mjs`. The bundle this replaces was built
|
|
12
|
+
* by hand once and never regenerated, and had drifted into disagreeing with the
|
|
13
|
+
* Go reference on 24 of 29 fixture cases — accepting relabelled timestamps and
|
|
14
|
+
* an unsigned tree_size, and rejecting genuine certificates with a non-UTC
|
|
15
|
+
* offset (#457). It also contained `ed25519Supported`, which existed in no
|
|
16
|
+
* source file anywhere in the repository.
|
|
17
|
+
*/
|
|
18
|
+
import { browserCrypto } from "./crypto-browser.js";
|
|
19
|
+
import {
|
|
20
|
+
verifyCertificate as _verifyCertificate,
|
|
21
|
+
verifyCertificateWithStatus as _verifyCertificateWithStatus,
|
|
22
|
+
verifyTransparency as _verifyTransparency,
|
|
23
|
+
publicKeyFromHex as _publicKeyFromHex,
|
|
24
|
+
} from "./verify.js";
|
|
25
|
+
import type { PublicKeyInfo } from "./verify.js";
|
|
26
|
+
import type { VerificationResult, TransparencyResult } from "./models.js";
|
|
27
|
+
|
|
28
|
+
type Cert = Record<string, unknown>;
|
|
29
|
+
|
|
30
|
+
/** Verify all signatures on a deletion certificate offline. */
|
|
31
|
+
export function verifyCertificate(
|
|
32
|
+
certificate: Cert,
|
|
33
|
+
publicKeys: Map<string, PublicKeyInfo>,
|
|
34
|
+
): Promise<VerificationResult> {
|
|
35
|
+
return _verifyCertificate(browserCrypto, certificate, publicKeys);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Verify a certificate and, separately, what a signed statement says about its
|
|
40
|
+
* revocation. Returns "VALID_REVOCATION_UNKNOWN" when no fresh statement is
|
|
41
|
+
* supplied — never "VALID", because "not revoked" is not something an offline
|
|
42
|
+
* check can establish on its own.
|
|
43
|
+
*/
|
|
44
|
+
export function verifyCertificateWithStatus(
|
|
45
|
+
certificate: Cert,
|
|
46
|
+
publicKeys: Map<string, PublicKeyInfo>,
|
|
47
|
+
status?: Record<string, unknown> | null,
|
|
48
|
+
now?: Date,
|
|
49
|
+
): Promise<string> {
|
|
50
|
+
return _verifyCertificateWithStatus(browserCrypto, certificate, publicKeys, status, now);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Verify the transparency proof embedded in a certificate. */
|
|
54
|
+
export function verifyTransparency(
|
|
55
|
+
certificate: Cert,
|
|
56
|
+
publicKeys: Map<string, PublicKeyInfo>,
|
|
57
|
+
): Promise<TransparencyResult> {
|
|
58
|
+
return _verifyTransparency(browserCrypto, certificate, publicKeys);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Construct a PublicKeyInfo from a hex-encoded Ed25519 public key. */
|
|
62
|
+
export function publicKeyFromHex(
|
|
63
|
+
hexKey: string,
|
|
64
|
+
opts?: { revoked?: boolean },
|
|
65
|
+
): Promise<PublicKeyInfo> {
|
|
66
|
+
return _publicKeyFromHex(browserCrypto, hexKey, opts);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Report whether this browser's WebCrypto can verify Ed25519, so the page can
|
|
71
|
+
* say "your browser cannot check this" rather than failing silently.
|
|
72
|
+
*
|
|
73
|
+
* Feature-detected by importing a well-formed SPKI key rather than sniffing the
|
|
74
|
+
* user agent: support arrived at different versions across engines, and a
|
|
75
|
+
* capability question deserves a capability answer.
|
|
76
|
+
*/
|
|
77
|
+
export async function ed25519Supported(): Promise<boolean> {
|
|
78
|
+
try {
|
|
79
|
+
const spki = new Uint8Array([
|
|
80
|
+
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
|
|
81
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
|
82
|
+
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
|
|
83
|
+
]);
|
|
84
|
+
await crypto.subtle.importKey("spki", spki.buffer as ArrayBuffer, { name: "Ed25519" }, false, ["verify"]);
|
|
85
|
+
return true;
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
package/src/webhooks.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** Webhook signature verification for incoming BurnLedger events.
|
|
2
|
+
*
|
|
3
|
+
* The server signs webhook payloads with HMAC-SHA256 using the webhook secret.
|
|
4
|
+
* The signature is sent in the X-BurnLedger-Signature header as a hex string,
|
|
5
|
+
* and the timestamp in the X-BurnLedger-Timestamp header as an RFC3339 string.
|
|
6
|
+
*
|
|
7
|
+
* CR-M01: the signed preimage is `timestamp + "." + body`, where `timestamp` is
|
|
8
|
+
* the exact RFC3339 string from the X-BurnLedger-Timestamp header. Binding the
|
|
9
|
+
* timestamp into the MAC prevents a captured delivery from being replayed under
|
|
10
|
+
* a different timestamp. Receivers MUST also verify the timestamp is fresh (see
|
|
11
|
+
* isTimestampFresh) — the signature proves authenticity, freshness prevents
|
|
12
|
+
* replay of an old-but-validly-signed delivery.
|
|
13
|
+
*
|
|
14
|
+
* Node-only — webhooks are received server-side.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Verify that a webhook payload was signed by the expected secret.
|
|
21
|
+
*
|
|
22
|
+
* @param secret The webhook secret (raw UTF-8, as returned by the API)
|
|
23
|
+
* @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
|
|
24
|
+
* @param body The raw request body bytes
|
|
25
|
+
* @param signature The hex-encoded HMAC-SHA256 signature from the X-BurnLedger-Signature header
|
|
26
|
+
* @returns true if the signature is valid
|
|
27
|
+
*/
|
|
28
|
+
export function verifyWebhookSignature(
|
|
29
|
+
secret: string,
|
|
30
|
+
timestamp: string,
|
|
31
|
+
body: Uint8Array | string,
|
|
32
|
+
signature: string,
|
|
33
|
+
): boolean {
|
|
34
|
+
if (secret.length === 0) return false;
|
|
35
|
+
if (timestamp.length === 0) return false;
|
|
36
|
+
if (signature.length === 0) return false;
|
|
37
|
+
|
|
38
|
+
// Preimage: timestamp + "." + body. An RFC3339 timestamp never contains a
|
|
39
|
+
// ".", so the field boundary is unambiguous.
|
|
40
|
+
const bodyBytes =
|
|
41
|
+
typeof body === "string" ? Buffer.from(body, "utf-8") : Buffer.from(body);
|
|
42
|
+
const expected = createHmac("sha256", secret)
|
|
43
|
+
.update(Buffer.from(`${timestamp}.`, "utf-8"))
|
|
44
|
+
.update(bodyBytes)
|
|
45
|
+
.digest();
|
|
46
|
+
|
|
47
|
+
let received: Buffer;
|
|
48
|
+
try {
|
|
49
|
+
received = Buffer.from(signature, "hex");
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (received.length !== expected.length) return false;
|
|
55
|
+
|
|
56
|
+
return timingSafeEqual(expected, received);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Verify that the webhook timestamp is within an acceptable freshness window.
|
|
61
|
+
* Receivers MUST call this (in addition to verifyWebhookSignature) to prevent
|
|
62
|
+
* replay of an old-but-validly-signed delivery.
|
|
63
|
+
*
|
|
64
|
+
* @param timestamp The RFC3339 timestamp from the X-BurnLedger-Timestamp header
|
|
65
|
+
* @param toleranceSeconds Maximum accepted age/skew in seconds (default 300)
|
|
66
|
+
* @returns true if the timestamp parses and is within +/- tolerance of now
|
|
67
|
+
*/
|
|
68
|
+
export function isTimestampFresh(
|
|
69
|
+
timestamp: string,
|
|
70
|
+
toleranceSeconds: number = 300,
|
|
71
|
+
): boolean {
|
|
72
|
+
const parsed = Date.parse(timestamp);
|
|
73
|
+
if (Number.isNaN(parsed)) return false;
|
|
74
|
+
const ageSeconds = Math.abs(Date.now() - parsed) / 1000;
|
|
75
|
+
return ageSeconds <= toleranceSeconds;
|
|
76
|
+
}
|
package/dist/cjs/cli.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/** burnledger check — offline certificate verification.
|
|
3
|
-
* Exit codes: 0=valid, 1=invalid, 2=usage error */
|
|
4
|
-
type Cert = Record<string, unknown>;
|
|
5
|
-
/** The pass/fail decision behind the exit code. A signature failure, a
|
|
6
|
-
* transparency FAILURE (thrown, not NOT_AVAILABLE), or an online-confirmed
|
|
7
|
-
* revocation all make the certificate invalid. Exported for testing. */
|
|
8
|
-
export declare function certVerdict(sigResult: string, transparencyFailed: boolean, online: boolean, revocation: {
|
|
9
|
-
status: string;
|
|
10
|
-
} | undefined): boolean;
|
|
11
|
-
export declare function formatOutput(cert: Cert, sigResult: string, transparency: string, transparencyFailed: boolean, revocation: {
|
|
12
|
-
status: string;
|
|
13
|
-
reason?: string;
|
|
14
|
-
} | undefined, online: boolean): string;
|
|
15
|
-
export {};
|
|
16
|
-
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cjs/cli.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";AACA;mDACmD;AAQnD,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAiEpC;;wEAEwE;AACxE,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,OAAO,EAC3B,MAAM,EAAE,OAAO,EACf,UAAU,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACzC,OAAO,CAMT;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAChF,UAAU,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,GAC3E,MAAM,CAmCR"}
|
package/dist/cjs/cli.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/** burnledger check — offline certificate verification.
|
|
4
|
-
* Exit codes: 0=valid, 1=invalid, 2=usage error */
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.certVerdict = certVerdict;
|
|
7
|
-
exports.formatOutput = formatOutput;
|
|
8
|
-
const promises_1 = require("node:fs/promises");
|
|
9
|
-
const crypto_node_js_1 = require("./crypto-node.js");
|
|
10
|
-
const verify_js_1 = require("./verify.js");
|
|
11
|
-
const keys_js_1 = require("./keys.js");
|
|
12
|
-
const USAGE = "Usage: burnledger check --cert <file> --keys <file> [--online --api-url <url> --api-key <key>]\n";
|
|
13
|
-
function die(msg) { process.stderr.write(msg); process.exit(2); }
|
|
14
|
-
function parseArgs(argv) {
|
|
15
|
-
const args = argv.slice(2);
|
|
16
|
-
if (args[0] !== "check")
|
|
17
|
-
die(USAGE);
|
|
18
|
-
let certPath = "", keysPath = "", online = false, apiUrl = "", apiKey = "";
|
|
19
|
-
for (let i = 1; i < args.length; i++) {
|
|
20
|
-
const a = args[i];
|
|
21
|
-
if (a === "--cert") {
|
|
22
|
-
certPath = args[++i] ?? die("--cert requires a value\n");
|
|
23
|
-
}
|
|
24
|
-
else if (a === "--keys") {
|
|
25
|
-
keysPath = args[++i] ?? die("--keys requires a value\n");
|
|
26
|
-
}
|
|
27
|
-
else if (a === "--online") {
|
|
28
|
-
online = true;
|
|
29
|
-
}
|
|
30
|
-
else if (a === "--api-url") {
|
|
31
|
-
apiUrl = args[++i] ?? die("--api-url requires a value\n");
|
|
32
|
-
}
|
|
33
|
-
else if (a === "--api-key") {
|
|
34
|
-
apiKey = args[++i] ?? die("--api-key requires a value\n");
|
|
35
|
-
}
|
|
36
|
-
else
|
|
37
|
-
die(`Unknown argument: ${a}\n`);
|
|
38
|
-
}
|
|
39
|
-
if (!certPath || !keysPath)
|
|
40
|
-
die("Both --cert and --keys are required.\n");
|
|
41
|
-
if (online && (!apiUrl || !apiKey))
|
|
42
|
-
die("--online requires --api-url and --api-key.\n");
|
|
43
|
-
return { certPath, keysPath, online, apiUrl, apiKey };
|
|
44
|
-
}
|
|
45
|
-
async function loadKeys(path) {
|
|
46
|
-
let entries;
|
|
47
|
-
try {
|
|
48
|
-
entries = (0, keys_js_1.parseKeyEntries)(JSON.parse(await (0, promises_1.readFile)(path, "utf-8")));
|
|
49
|
-
}
|
|
50
|
-
catch (e) {
|
|
51
|
-
die(e.message + "\n");
|
|
52
|
-
}
|
|
53
|
-
const map = new Map();
|
|
54
|
-
for (const e of entries) {
|
|
55
|
-
// Fail closed: trust a key only if it explicitly declares active/retired.
|
|
56
|
-
const revoked = !(e.key_status === "active" || e.key_status === "retired");
|
|
57
|
-
let pki;
|
|
58
|
-
try {
|
|
59
|
-
pki = await (0, verify_js_1.publicKeyFromHex)(crypto_node_js_1.nodeCrypto, e.public_key, { revoked });
|
|
60
|
-
}
|
|
61
|
-
catch (err) {
|
|
62
|
-
die(`invalid public_key: ${err.message}\n`);
|
|
63
|
-
}
|
|
64
|
-
// Key-substitution defense: a declared key_id must match the id derived from
|
|
65
|
-
// the public key (dp_k_ + sha256(key)), and the map is keyed on the DERIVED
|
|
66
|
-
// id so a lying key_id cannot shadow a genuine one.
|
|
67
|
-
if (e.key_id !== undefined && e.key_id !== pki.keyId) {
|
|
68
|
-
die(`key_id ${e.key_id} does not match sha256(public_key) (${pki.keyId})\n`);
|
|
69
|
-
}
|
|
70
|
-
const existing = map.get(pki.keyId);
|
|
71
|
-
if (existing !== undefined && existing.revoked !== pki.revoked) {
|
|
72
|
-
die(`conflicting key_status for duplicate key ${pki.keyId}\n`);
|
|
73
|
-
}
|
|
74
|
-
map.set(pki.keyId, pki);
|
|
75
|
-
}
|
|
76
|
-
return map;
|
|
77
|
-
}
|
|
78
|
-
async function checkRevocation(apiUrl, apiKey, certId) {
|
|
79
|
-
const res = await fetch(`${apiUrl}/v1/certificates/${certId}/revocation-status`, {
|
|
80
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
81
|
-
});
|
|
82
|
-
if (!res.ok)
|
|
83
|
-
throw new Error(`Revocation check failed: HTTP ${res.status}`);
|
|
84
|
-
return (await res.json()).data;
|
|
85
|
-
}
|
|
86
|
-
/** The pass/fail decision behind the exit code. A signature failure, a
|
|
87
|
-
* transparency FAILURE (thrown, not NOT_AVAILABLE), or an online-confirmed
|
|
88
|
-
* revocation all make the certificate invalid. Exported for testing. */
|
|
89
|
-
function certVerdict(sigResult, transparencyFailed, online, revocation) {
|
|
90
|
-
return (sigResult === "VALID" &&
|
|
91
|
-
!transparencyFailed &&
|
|
92
|
-
!(online && revocation?.status === "REVOKED"));
|
|
93
|
-
}
|
|
94
|
-
function formatOutput(cert, sigResult, transparency, transparencyFailed, revocation, online) {
|
|
95
|
-
const id = cert.certificate_id.slice(0, 6);
|
|
96
|
-
const sub = cert.subject.identifier_hash;
|
|
97
|
-
const att = cert.attestation;
|
|
98
|
-
const ver = cert.verification;
|
|
99
|
-
const L = [];
|
|
100
|
-
if (sigResult !== "VALID")
|
|
101
|
-
return `Certificate dc_${id}: INVALID (${sigResult})\n`;
|
|
102
|
-
if (transparencyFailed)
|
|
103
|
-
return `Certificate dc_${id}: INVALID (transparency: ${transparency})\n`;
|
|
104
|
-
if (online && revocation?.status === "REVOKED") {
|
|
105
|
-
L.push(`Certificate dc_${id}: INVALID (REVOKED)`);
|
|
106
|
-
if (revocation.reason)
|
|
107
|
-
L.push(` Revocation reason: ${revocation.reason}`);
|
|
108
|
-
return L.join("\n") + "\n";
|
|
109
|
-
}
|
|
110
|
-
const tag = online ? "" : " (offline — revocation status not checked)";
|
|
111
|
-
L.push(`Certificate dc_${id}: VALID${tag}`);
|
|
112
|
-
L.push(` Subject: sha256:${sub.slice(0, 6)}...`);
|
|
113
|
-
L.push(` Canonical version: ${cert.certificate_format_version}`);
|
|
114
|
-
const sys = att.systems;
|
|
115
|
-
L.push(` Systems: ${sys.length} (${sys.map((s) => `${s.connector_type} [${s.hash_scope}]`).join(", ")})`);
|
|
116
|
-
L.push(` Records before: ${sys.reduce((n, s) => n + s.record_count, 0)}`);
|
|
117
|
-
L.push(` Records after: ${ver.systems.reduce((n, s) => n + s.record_count, 0)}`);
|
|
118
|
-
L.push(` Committed: ${att.attested_at}`);
|
|
119
|
-
L.push(` Verified: ${ver.verified_at}`);
|
|
120
|
-
if (transparency === "INCLUDED") {
|
|
121
|
-
const t = cert.transparency;
|
|
122
|
-
L.push(` Transparency log: entry #${t.entry_index}, inclusion proof VALID`);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
L.push(` Transparency log: ${transparency === "NOT_AVAILABLE" ? "not included" : transparency}`);
|
|
126
|
-
}
|
|
127
|
-
if (online && revocation)
|
|
128
|
-
L.push(` Revocation status: ${revocation.status}`);
|
|
129
|
-
return L.join("\n") + "\n";
|
|
130
|
-
}
|
|
131
|
-
async function main() {
|
|
132
|
-
const args = parseArgs(process.argv);
|
|
133
|
-
const cert = JSON.parse(await (0, promises_1.readFile)(args.certPath, "utf-8"));
|
|
134
|
-
const keys = await loadKeys(args.keysPath);
|
|
135
|
-
let sigResult = "VALID";
|
|
136
|
-
try {
|
|
137
|
-
await (0, verify_js_1.verifyCertificate)(crypto_node_js_1.nodeCrypto, cert, keys);
|
|
138
|
-
}
|
|
139
|
-
catch (e) {
|
|
140
|
-
sigResult = e instanceof Error ? e.message : "unknown error";
|
|
141
|
-
}
|
|
142
|
-
// NOT_AVAILABLE (no proof) is a legitimate result; only a thrown error is a
|
|
143
|
-
// transparency FAILURE and must fail the verdict + exit code.
|
|
144
|
-
let transparency = "NOT_AVAILABLE";
|
|
145
|
-
let transparencyFailed = false;
|
|
146
|
-
try {
|
|
147
|
-
transparency = await (0, verify_js_1.verifyTransparency)(crypto_node_js_1.nodeCrypto, cert, keys);
|
|
148
|
-
}
|
|
149
|
-
catch (e) {
|
|
150
|
-
transparency = e instanceof Error ? e.message : "unknown error";
|
|
151
|
-
transparencyFailed = true;
|
|
152
|
-
}
|
|
153
|
-
let revocation;
|
|
154
|
-
if (args.online)
|
|
155
|
-
revocation = await checkRevocation(args.apiUrl, args.apiKey, cert.certificate_id);
|
|
156
|
-
const valid = certVerdict(sigResult, transparencyFailed, args.online, revocation);
|
|
157
|
-
process.stdout.write(formatOutput(cert, sigResult, transparency, transparencyFailed, revocation, args.online));
|
|
158
|
-
process.exit(valid ? 0 : 1);
|
|
159
|
-
}
|
|
160
|
-
// Only run as a CLI entry point — importing this module (e.g. from tests) must
|
|
161
|
-
// not execute main(). argv[1] is the script path when invoked as the binary.
|
|
162
|
-
if (process.argv[1]?.endsWith("cli.js")) {
|
|
163
|
-
main().catch((e) => {
|
|
164
|
-
process.stderr.write(`Error: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
165
|
-
process.exit(2);
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
//# sourceMappingURL=cli.js.map
|
package/dist/cjs/cli.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|