@passportsign/core 0.1.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 +201 -0
- package/README.md +36 -0
- package/dist/badge.d.ts +37 -0
- package/dist/badge.d.ts.map +1 -0
- package/dist/badge.js +94 -0
- package/dist/badge.js.map +1 -0
- package/dist/bind.d.ts +61 -0
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +79 -0
- package/dist/bind.js.map +1 -0
- package/dist/bundle.d.ts +47 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +95 -0
- package/dist/bundle.js.map +1 -0
- package/dist/canonical.d.ts +19 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +30 -0
- package/dist/canonical.js.map +1 -0
- package/dist/dsse.d.ts +55 -0
- package/dist/dsse.d.ts.map +1 -0
- package/dist/dsse.js +64 -0
- package/dist/dsse.js.map +1 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/github.d.ts +28 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +113 -0
- package/dist/github.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/log/rekor.d.ts +91 -0
- package/dist/log/rekor.d.ts.map +1 -0
- package/dist/log/rekor.js +218 -0
- package/dist/log/rekor.js.map +1 -0
- package/dist/merkle.d.ts +37 -0
- package/dist/merkle.d.ts.map +1 -0
- package/dist/merkle.js +160 -0
- package/dist/merkle.js.map +1 -0
- package/dist/nonce.d.ts +24 -0
- package/dist/nonce.d.ts.map +1 -0
- package/dist/nonce.js +50 -0
- package/dist/nonce.js.map +1 -0
- package/dist/sdk-payload.d.ts +33 -0
- package/dist/sdk-payload.d.ts.map +1 -0
- package/dist/sdk-payload.js +36 -0
- package/dist/sdk-payload.js.map +1 -0
- package/dist/statement.d.ts +67 -0
- package/dist/statement.d.ts.map +1 -0
- package/dist/statement.js +67 -0
- package/dist/statement.js.map +1 -0
- package/dist/storage/sqlite.d.ts +45 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +132 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/submit.d.ts +26 -0
- package/dist/submit.d.ts.map +1 -0
- package/dist/submit.js +35 -0
- package/dist/submit.js.map +1 -0
- package/dist/verifier.d.ts +74 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +197 -0
- package/dist/verifier.js.map +1 -0
- package/package.json +60 -0
- package/src/badge.ts +113 -0
- package/src/bind.ts +137 -0
- package/src/bundle.ts +127 -0
- package/src/canonical.ts +33 -0
- package/src/dsse.ts +91 -0
- package/src/errors.ts +37 -0
- package/src/github.ts +196 -0
- package/src/index.ts +121 -0
- package/src/log/rekor.ts +334 -0
- package/src/merkle.ts +187 -0
- package/src/nonce.ts +53 -0
- package/src/sdk-payload.ts +62 -0
- package/src/statement.ts +119 -0
- package/src/storage/sqlite.ts +185 -0
- package/src/submit.ts +54 -0
- package/src/truestamp-canonify.d.ts +7 -0
- package/src/verifier.ts +317 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-payload.d.ts","sourceRoot":"","sources":["../src/sdk-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,8DAA8D;IAC9D,cAAc,EAAE,OAAO,CAAC;IACxB,wDAAwD;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,yDAAyD;IACzD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,KAAK,EAAE,UAAU,CAAC;IAClB,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ,uGAAuG;IACvG,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,gBAAgB,CAKpE;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAkBxD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pack/unpack the zkPassport SDK inputs that a verifier needs to re-run
|
|
3
|
+
* proof verification offline.
|
|
4
|
+
*
|
|
5
|
+
* Rather than expanding the bundle schema, we re-purpose the existing
|
|
6
|
+
* `proof_blob` field: it's the base64 of canonical JCS bytes of an
|
|
7
|
+
* {@link SdkPayload} object. The statement's `proof_blob_sha256` already
|
|
8
|
+
* binds those bytes to the rest of the binding — Day 5's hash check
|
|
9
|
+
* carries through.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { canonicalize } from './canonical.js';
|
|
13
|
+
export function packSdkPayload(payload) {
|
|
14
|
+
const bytes = canonicalize(payload);
|
|
15
|
+
const b64 = Buffer.from(bytes).toString('base64');
|
|
16
|
+
const sha256Hex = createHash('sha256').update(bytes).digest('hex');
|
|
17
|
+
return { bytes, b64, sha256Hex };
|
|
18
|
+
}
|
|
19
|
+
export function unpackSdkPayload(b64) {
|
|
20
|
+
const bytes = Buffer.from(b64, 'base64');
|
|
21
|
+
const parsed = JSON.parse(bytes.toString('utf8'));
|
|
22
|
+
// Defensive shape check (cheap; the canonicalize round-trip would already catch shape issues elsewhere).
|
|
23
|
+
if (typeof parsed['sdk_version'] !== 'string' ||
|
|
24
|
+
typeof parsed['dev_mode'] !== 'boolean' ||
|
|
25
|
+
!Array.isArray(parsed['proofs'])) {
|
|
26
|
+
throw new TypeError('unpackSdkPayload: not a valid SdkPayload shape');
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
sdk_version: parsed['sdk_version'],
|
|
30
|
+
proofs: parsed['proofs'],
|
|
31
|
+
original_query: parsed['original_query'],
|
|
32
|
+
query_result: parsed['query_result'],
|
|
33
|
+
dev_mode: parsed['dev_mode'],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=sdk-payload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-payload.js","sourceRoot":"","sources":["../src/sdk-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAwB9C,MAAM,UAAU,cAAc,CAAC,OAAmB;IAChD,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA4B,CAAC;IAC7E,yGAAyG;IACzG,IACE,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,QAAQ;QACzC,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,SAAS;QACvC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAChC,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,gDAAgD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,aAAa,CAAC;QAClC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC,gBAAgB,CAAC;QACxC,YAAY,EAAE,MAAM,CAAC,cAAc,CAAC;QACpC,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC;KAC7B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* in-toto Statement v1 builder for passportsign attestations.
|
|
3
|
+
*
|
|
4
|
+
* The statement's canonical JCS bytes are what gets hashed into the
|
|
5
|
+
* Rekor entry, so this module is the authoritative source for the
|
|
6
|
+
* statement shape. Test vectors in
|
|
7
|
+
* `test/fixtures/canonical-vectors.json` pin the canonicalization
|
|
8
|
+
* output for representative statements built here.
|
|
9
|
+
*/
|
|
10
|
+
export declare const IN_TOTO_STATEMENT_TYPE: "https://in-toto.io/Statement/v1";
|
|
11
|
+
export declare const PASSPORTSIGN_PREDICATE_TYPE: "https://passportsign.dev/personhood/v1";
|
|
12
|
+
export type DisclosureLevel = 'personhood' | 'personhood+country';
|
|
13
|
+
export interface PassportsignPredicate {
|
|
14
|
+
/** From the zkPassport SDK — deterministic for (passport, domain, scope). */
|
|
15
|
+
unique_identifier: string;
|
|
16
|
+
/** ICAO 3-letter code if disclosed, else null. Pass through as-returned by SDK. */
|
|
17
|
+
issuing_country: string | null;
|
|
18
|
+
/** Derived from issuing_country (null → personhood, set → personhood+country). */
|
|
19
|
+
disclosure_level: DisclosureLevel;
|
|
20
|
+
/** Lowercase hex SHA-256 of the proof blob bytes. */
|
|
21
|
+
proof_blob_sha256: string;
|
|
22
|
+
/** Public gist URL captured at binding time. */
|
|
23
|
+
gist_url: string;
|
|
24
|
+
/** Lowercase hex SHA-256 of the gist's content bytes. Also the subject digest. */
|
|
25
|
+
gist_content_sha256: string;
|
|
26
|
+
/** zkPassport scope (e.g. "passportsign.dev:nationality-disclose:1"). */
|
|
27
|
+
scope: string;
|
|
28
|
+
/** Version string from the zkPassport SDK that produced the proof. */
|
|
29
|
+
zkpassport_sdk_version: string;
|
|
30
|
+
}
|
|
31
|
+
export interface PassportsignStatement {
|
|
32
|
+
_type: typeof IN_TOTO_STATEMENT_TYPE;
|
|
33
|
+
subject: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
digest: {
|
|
36
|
+
sha256: string;
|
|
37
|
+
};
|
|
38
|
+
}>;
|
|
39
|
+
predicateType: typeof PASSPORTSIGN_PREDICATE_TYPE;
|
|
40
|
+
predicate: PassportsignPredicate;
|
|
41
|
+
}
|
|
42
|
+
export interface BuildStatementInput {
|
|
43
|
+
github_username: string;
|
|
44
|
+
unique_identifier: string;
|
|
45
|
+
issuing_country: string | null;
|
|
46
|
+
proof_blob_sha256: string;
|
|
47
|
+
gist_url: string;
|
|
48
|
+
gist_content_sha256: string;
|
|
49
|
+
scope: string;
|
|
50
|
+
zkpassport_sdk_version: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build a passportsign in-toto Statement v1.
|
|
54
|
+
*
|
|
55
|
+
* Invariants enforced here (so the canonical bytes are always well-formed):
|
|
56
|
+
* - `proof_blob_sha256` and `gist_content_sha256` are lowercase 64-char hex.
|
|
57
|
+
* - `github_username`, `unique_identifier`, `gist_url`, `scope`,
|
|
58
|
+
* `zkpassport_sdk_version` are non-empty.
|
|
59
|
+
* - `subject[0].digest.sha256 === gist_content_sha256` — the subject digest
|
|
60
|
+
* is the artifact whose control was demonstrated (the gist content).
|
|
61
|
+
* - `disclosure_level` is derived from `issuing_country` and is never
|
|
62
|
+
* accepted from the caller.
|
|
63
|
+
* - There is no `bound_at` field — the Rekor inclusion timestamp is the
|
|
64
|
+
* authoritative time of binding.
|
|
65
|
+
*/
|
|
66
|
+
export declare function buildStatement(input: BuildStatementInput): PassportsignStatement;
|
|
67
|
+
//# sourceMappingURL=statement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statement.d.ts","sourceRoot":"","sources":["../src/statement.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,sBAAsB,EAAG,iCAA0C,CAAC;AACjF,eAAO,MAAM,2BAA2B,EACtC,wCAAiD,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,oBAAoB,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,6EAA6E;IAC7E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kFAAkF;IAClF,gBAAgB,EAAE,eAAe,CAAC;IAClC,qDAAqD;IACrD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,sBAAsB,CAAC;IACrC,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;KAC5B,CAAC,CAAC;IACH,aAAa,EAAE,OAAO,2BAA2B,CAAC;IAClD,SAAS,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAkBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,qBAAqB,CAgChF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* in-toto Statement v1 builder for passportsign attestations.
|
|
3
|
+
*
|
|
4
|
+
* The statement's canonical JCS bytes are what gets hashed into the
|
|
5
|
+
* Rekor entry, so this module is the authoritative source for the
|
|
6
|
+
* statement shape. Test vectors in
|
|
7
|
+
* `test/fixtures/canonical-vectors.json` pin the canonicalization
|
|
8
|
+
* output for representative statements built here.
|
|
9
|
+
*/
|
|
10
|
+
export const IN_TOTO_STATEMENT_TYPE = 'https://in-toto.io/Statement/v1';
|
|
11
|
+
export const PASSPORTSIGN_PREDICATE_TYPE = 'https://passportsign.dev/personhood/v1';
|
|
12
|
+
const SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
13
|
+
function assertSha256Hex(value, field) {
|
|
14
|
+
if (!SHA256_HEX.test(value)) {
|
|
15
|
+
throw new TypeError(`${field}: expected lowercase 64-char hex SHA-256, got ${JSON.stringify(value)}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function assertNonEmpty(value, field) {
|
|
19
|
+
if (value.length === 0) {
|
|
20
|
+
throw new TypeError(`${field}: must be non-empty`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build a passportsign in-toto Statement v1.
|
|
25
|
+
*
|
|
26
|
+
* Invariants enforced here (so the canonical bytes are always well-formed):
|
|
27
|
+
* - `proof_blob_sha256` and `gist_content_sha256` are lowercase 64-char hex.
|
|
28
|
+
* - `github_username`, `unique_identifier`, `gist_url`, `scope`,
|
|
29
|
+
* `zkpassport_sdk_version` are non-empty.
|
|
30
|
+
* - `subject[0].digest.sha256 === gist_content_sha256` — the subject digest
|
|
31
|
+
* is the artifact whose control was demonstrated (the gist content).
|
|
32
|
+
* - `disclosure_level` is derived from `issuing_country` and is never
|
|
33
|
+
* accepted from the caller.
|
|
34
|
+
* - There is no `bound_at` field — the Rekor inclusion timestamp is the
|
|
35
|
+
* authoritative time of binding.
|
|
36
|
+
*/
|
|
37
|
+
export function buildStatement(input) {
|
|
38
|
+
assertSha256Hex(input.proof_blob_sha256, 'proof_blob_sha256');
|
|
39
|
+
assertSha256Hex(input.gist_content_sha256, 'gist_content_sha256');
|
|
40
|
+
assertNonEmpty(input.github_username, 'github_username');
|
|
41
|
+
assertNonEmpty(input.unique_identifier, 'unique_identifier');
|
|
42
|
+
assertNonEmpty(input.gist_url, 'gist_url');
|
|
43
|
+
assertNonEmpty(input.scope, 'scope');
|
|
44
|
+
assertNonEmpty(input.zkpassport_sdk_version, 'zkpassport_sdk_version');
|
|
45
|
+
const disclosure_level = input.issuing_country === null ? 'personhood' : 'personhood+country';
|
|
46
|
+
return {
|
|
47
|
+
_type: IN_TOTO_STATEMENT_TYPE,
|
|
48
|
+
subject: [
|
|
49
|
+
{
|
|
50
|
+
name: `github.com/${input.github_username}`,
|
|
51
|
+
digest: { sha256: input.gist_content_sha256 },
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
predicateType: PASSPORTSIGN_PREDICATE_TYPE,
|
|
55
|
+
predicate: {
|
|
56
|
+
unique_identifier: input.unique_identifier,
|
|
57
|
+
issuing_country: input.issuing_country,
|
|
58
|
+
disclosure_level,
|
|
59
|
+
proof_blob_sha256: input.proof_blob_sha256,
|
|
60
|
+
gist_url: input.gist_url,
|
|
61
|
+
gist_content_sha256: input.gist_content_sha256,
|
|
62
|
+
scope: input.scope,
|
|
63
|
+
zkpassport_sdk_version: input.zkpassport_sdk_version,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=statement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statement.js","sourceRoot":"","sources":["../src/statement.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,iCAA0C,CAAC;AACjF,MAAM,CAAC,MAAM,2BAA2B,GACtC,wCAAiD,CAAC;AA4CpD,MAAM,UAAU,GAAG,gBAAgB,CAAC;AAEpC,SAAS,eAAe,CAAC,KAAa,EAAE,KAAa;IACnD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,SAAS,CACjB,GAAG,KAAK,iDAAiD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CACjF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa,EAAE,KAAa;IAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,eAAe,CAAC,KAAK,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;IAC9D,eAAe,CAAC,KAAK,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC;IAClE,cAAc,CAAC,KAAK,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC;IACzD,cAAc,CAAC,KAAK,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;IAC7D,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3C,cAAc,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACrC,cAAc,CAAC,KAAK,CAAC,sBAAsB,EAAE,wBAAwB,CAAC,CAAC;IAEvE,MAAM,gBAAgB,GACpB,KAAK,CAAC,eAAe,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,oBAAoB,CAAC;IAEvE,OAAO;QACL,KAAK,EAAE,sBAAsB;QAC7B,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,cAAc,KAAK,CAAC,eAAe,EAAE;gBAC3C,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,mBAAmB,EAAE;aAC9C;SACF;QACD,aAAa,EAAE,2BAA2B;QAC1C,SAAS,EAAE;YACT,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,gBAAgB;YAChB,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;YAC9C,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;SACrD;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite cache mirroring spec §5's `bindings` table.
|
|
3
|
+
*
|
|
4
|
+
* The cache is **non-authoritative** by design — losing it is an
|
|
5
|
+
* availability incident, not a security one. The canonical state lives
|
|
6
|
+
* in Rekor, and `passportsign rebuild` reconstructs the cache from log
|
|
7
|
+
* entries.
|
|
8
|
+
*
|
|
9
|
+
* Uses Node's built-in `node:sqlite` (experimental but functional in
|
|
10
|
+
* Node 22.5+; stable enough for our single-user CLI use). Avoids the
|
|
11
|
+
* `better-sqlite3` native-build dependency, which requires Visual
|
|
12
|
+
* Studio C++ tools on Windows.
|
|
13
|
+
*
|
|
14
|
+
* Usernames are normalized to lowercase on insert and read per spec §10
|
|
15
|
+
* row 7. Display casing is the caller's responsibility.
|
|
16
|
+
*/
|
|
17
|
+
export type Status = 'active' | 'stale' | 'revoked';
|
|
18
|
+
export type DisclosureLevel = 'personhood' | 'personhood+country';
|
|
19
|
+
export interface BindingRow {
|
|
20
|
+
github_username: string;
|
|
21
|
+
unique_identifier: string;
|
|
22
|
+
issuing_country: string | null;
|
|
23
|
+
disclosure_level: DisclosureLevel;
|
|
24
|
+
scope: string;
|
|
25
|
+
zkpassport_sdk_ver: string;
|
|
26
|
+
proof_blob: Uint8Array;
|
|
27
|
+
gist_url: string;
|
|
28
|
+
gist_content_sha256: string;
|
|
29
|
+
bound_at: string;
|
|
30
|
+
log_entry_hash: string;
|
|
31
|
+
log_inclusion_proof: unknown;
|
|
32
|
+
log_root_at_submission: string;
|
|
33
|
+
last_checked_at: string;
|
|
34
|
+
status: Status;
|
|
35
|
+
}
|
|
36
|
+
export interface PassportsignCache {
|
|
37
|
+
upsertBinding(row: BindingRow): void;
|
|
38
|
+
getByUsername(username: string): BindingRow | null;
|
|
39
|
+
getByUniqueIdentifier(uid: string): BindingRow[];
|
|
40
|
+
setStatus(username: string, status: Status): void;
|
|
41
|
+
setLastChecked(username: string, when: Date): void;
|
|
42
|
+
close(): void;
|
|
43
|
+
}
|
|
44
|
+
export declare function openCache(path: string): PassportsignCache;
|
|
45
|
+
//# sourceMappingURL=sqlite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/storage/sqlite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AACpD,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,oBAAoB,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,gBAAgB,EAAE,eAAe,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACrC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACnD,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAAC;IACjD,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IACnD,KAAK,IAAI,IAAI,CAAC;CACf;AA6DD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA4EzD"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite cache mirroring spec §5's `bindings` table.
|
|
3
|
+
*
|
|
4
|
+
* The cache is **non-authoritative** by design — losing it is an
|
|
5
|
+
* availability incident, not a security one. The canonical state lives
|
|
6
|
+
* in Rekor, and `passportsign rebuild` reconstructs the cache from log
|
|
7
|
+
* entries.
|
|
8
|
+
*
|
|
9
|
+
* Uses Node's built-in `node:sqlite` (experimental but functional in
|
|
10
|
+
* Node 22.5+; stable enough for our single-user CLI use). Avoids the
|
|
11
|
+
* `better-sqlite3` native-build dependency, which requires Visual
|
|
12
|
+
* Studio C++ tools on Windows.
|
|
13
|
+
*
|
|
14
|
+
* Usernames are normalized to lowercase on insert and read per spec §10
|
|
15
|
+
* row 7. Display casing is the caller's responsibility.
|
|
16
|
+
*/
|
|
17
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
18
|
+
const SCHEMA = `
|
|
19
|
+
CREATE TABLE IF NOT EXISTS bindings (
|
|
20
|
+
github_username TEXT PRIMARY KEY,
|
|
21
|
+
unique_identifier TEXT NOT NULL,
|
|
22
|
+
issuing_country TEXT,
|
|
23
|
+
disclosure_level TEXT NOT NULL CHECK (disclosure_level IN ('personhood','personhood+country')),
|
|
24
|
+
scope TEXT NOT NULL,
|
|
25
|
+
zkpassport_sdk_ver TEXT NOT NULL,
|
|
26
|
+
proof_blob BLOB NOT NULL,
|
|
27
|
+
gist_url TEXT NOT NULL,
|
|
28
|
+
gist_content_sha256 TEXT NOT NULL,
|
|
29
|
+
bound_at TEXT NOT NULL,
|
|
30
|
+
log_entry_hash TEXT NOT NULL UNIQUE,
|
|
31
|
+
log_inclusion_proof TEXT NOT NULL,
|
|
32
|
+
log_root_at_submission TEXT NOT NULL,
|
|
33
|
+
last_checked_at TEXT NOT NULL,
|
|
34
|
+
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','stale','revoked'))
|
|
35
|
+
);
|
|
36
|
+
CREATE INDEX IF NOT EXISTS bindings_unique_identifier ON bindings(unique_identifier);
|
|
37
|
+
`;
|
|
38
|
+
function rowFromDb(r) {
|
|
39
|
+
return {
|
|
40
|
+
github_username: r.github_username,
|
|
41
|
+
unique_identifier: r.unique_identifier,
|
|
42
|
+
issuing_country: r.issuing_country,
|
|
43
|
+
disclosure_level: r.disclosure_level,
|
|
44
|
+
scope: r.scope,
|
|
45
|
+
zkpassport_sdk_ver: r.zkpassport_sdk_ver,
|
|
46
|
+
proof_blob: new Uint8Array(r.proof_blob),
|
|
47
|
+
gist_url: r.gist_url,
|
|
48
|
+
gist_content_sha256: r.gist_content_sha256,
|
|
49
|
+
bound_at: r.bound_at,
|
|
50
|
+
log_entry_hash: r.log_entry_hash,
|
|
51
|
+
log_inclusion_proof: JSON.parse(r.log_inclusion_proof),
|
|
52
|
+
log_root_at_submission: r.log_root_at_submission,
|
|
53
|
+
last_checked_at: r.last_checked_at,
|
|
54
|
+
status: r.status,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function openCache(path) {
|
|
58
|
+
const db = new DatabaseSync(path);
|
|
59
|
+
db.exec('PRAGMA journal_mode = WAL');
|
|
60
|
+
db.exec(SCHEMA);
|
|
61
|
+
const upsertStmt = db.prepare(`
|
|
62
|
+
INSERT INTO bindings (
|
|
63
|
+
github_username, unique_identifier, issuing_country, disclosure_level,
|
|
64
|
+
scope, zkpassport_sdk_ver, proof_blob, gist_url, gist_content_sha256,
|
|
65
|
+
bound_at, log_entry_hash, log_inclusion_proof, log_root_at_submission,
|
|
66
|
+
last_checked_at, status
|
|
67
|
+
) VALUES (
|
|
68
|
+
:github_username, :unique_identifier, :issuing_country, :disclosure_level,
|
|
69
|
+
:scope, :zkpassport_sdk_ver, :proof_blob, :gist_url, :gist_content_sha256,
|
|
70
|
+
:bound_at, :log_entry_hash, :log_inclusion_proof, :log_root_at_submission,
|
|
71
|
+
:last_checked_at, :status
|
|
72
|
+
)
|
|
73
|
+
ON CONFLICT(github_username) DO UPDATE SET
|
|
74
|
+
unique_identifier = excluded.unique_identifier,
|
|
75
|
+
issuing_country = excluded.issuing_country,
|
|
76
|
+
disclosure_level = excluded.disclosure_level,
|
|
77
|
+
scope = excluded.scope,
|
|
78
|
+
zkpassport_sdk_ver = excluded.zkpassport_sdk_ver,
|
|
79
|
+
proof_blob = excluded.proof_blob,
|
|
80
|
+
gist_url = excluded.gist_url,
|
|
81
|
+
gist_content_sha256 = excluded.gist_content_sha256,
|
|
82
|
+
bound_at = excluded.bound_at,
|
|
83
|
+
log_entry_hash = excluded.log_entry_hash,
|
|
84
|
+
log_inclusion_proof = excluded.log_inclusion_proof,
|
|
85
|
+
log_root_at_submission = excluded.log_root_at_submission,
|
|
86
|
+
last_checked_at = excluded.last_checked_at,
|
|
87
|
+
status = excluded.status
|
|
88
|
+
`);
|
|
89
|
+
const getByUsernameStmt = db.prepare(`SELECT * FROM bindings WHERE github_username = ?`);
|
|
90
|
+
const getByUniqueIdStmt = db.prepare(`SELECT * FROM bindings WHERE unique_identifier = ? ORDER BY bound_at`);
|
|
91
|
+
const setStatusStmt = db.prepare(`UPDATE bindings SET status = ? WHERE github_username = ?`);
|
|
92
|
+
const setLastCheckedStmt = db.prepare(`UPDATE bindings SET last_checked_at = ? WHERE github_username = ?`);
|
|
93
|
+
return {
|
|
94
|
+
upsertBinding(row) {
|
|
95
|
+
upsertStmt.run({
|
|
96
|
+
github_username: row.github_username.toLowerCase(),
|
|
97
|
+
unique_identifier: row.unique_identifier,
|
|
98
|
+
issuing_country: row.issuing_country,
|
|
99
|
+
disclosure_level: row.disclosure_level,
|
|
100
|
+
scope: row.scope,
|
|
101
|
+
zkpassport_sdk_ver: row.zkpassport_sdk_ver,
|
|
102
|
+
proof_blob: row.proof_blob,
|
|
103
|
+
gist_url: row.gist_url,
|
|
104
|
+
gist_content_sha256: row.gist_content_sha256,
|
|
105
|
+
bound_at: row.bound_at,
|
|
106
|
+
log_entry_hash: row.log_entry_hash,
|
|
107
|
+
log_inclusion_proof: JSON.stringify(row.log_inclusion_proof),
|
|
108
|
+
log_root_at_submission: row.log_root_at_submission,
|
|
109
|
+
last_checked_at: row.last_checked_at,
|
|
110
|
+
status: row.status,
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
getByUsername(username) {
|
|
114
|
+
const r = getByUsernameStmt.get(username.toLowerCase());
|
|
115
|
+
return r ? rowFromDb(r) : null;
|
|
116
|
+
},
|
|
117
|
+
getByUniqueIdentifier(uid) {
|
|
118
|
+
const rows = getByUniqueIdStmt.all(uid);
|
|
119
|
+
return rows.map(rowFromDb);
|
|
120
|
+
},
|
|
121
|
+
setStatus(username, status) {
|
|
122
|
+
setStatusStmt.run(status, username.toLowerCase());
|
|
123
|
+
},
|
|
124
|
+
setLastChecked(username, when) {
|
|
125
|
+
setLastCheckedStmt.run(when.toISOString(), username.toLowerCase());
|
|
126
|
+
},
|
|
127
|
+
close() {
|
|
128
|
+
db.close();
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/storage/sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/submit.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Submit a {@link PreparedBinding} to a Rekor log and assemble the
|
|
3
|
+
* resulting {@link PassportsignBundle}.
|
|
4
|
+
*
|
|
5
|
+
* Composes the DSSE envelope step (with ephemeral ECDSA P-256 key)
|
|
6
|
+
* with a {@link RekorClient}. Day 7 calls this to turn a real-passport
|
|
7
|
+
* bind into a public-log entry plus a portable bundle.
|
|
8
|
+
*/
|
|
9
|
+
import { type PreparedBinding } from './bind.js';
|
|
10
|
+
import { type PassportsignBundle } from './bundle.js';
|
|
11
|
+
import { type RekorClient, type RekorEntryResponse } from './log/rekor.js';
|
|
12
|
+
export interface SubmitBindingDeps {
|
|
13
|
+
rekor: RekorClient;
|
|
14
|
+
}
|
|
15
|
+
export interface SubmitBindingResult {
|
|
16
|
+
bundle: PassportsignBundle;
|
|
17
|
+
rekorEntry: RekorEntryResponse;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Sign the canonical statement bytes with an ephemeral ECDSA P-256 key,
|
|
21
|
+
* submit the in-toto entry to Rekor, and assemble the bundle. Throws
|
|
22
|
+
* `PassportsignError('log_submission_failed', …)` (from the client) on
|
|
23
|
+
* any Rekor failure.
|
|
24
|
+
*/
|
|
25
|
+
export declare function submitBinding(prepared: PreparedBinding, deps: SubmitBindingDeps): Promise<SubmitBindingResult>;
|
|
26
|
+
//# sourceMappingURL=submit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../src/submit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAE3E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,kBAAkB,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,mBAAmB,CAAC,CAiB9B"}
|
package/dist/submit.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Submit a {@link PreparedBinding} to a Rekor log and assemble the
|
|
3
|
+
* resulting {@link PassportsignBundle}.
|
|
4
|
+
*
|
|
5
|
+
* Composes the DSSE envelope step (with ephemeral ECDSA P-256 key)
|
|
6
|
+
* with a {@link RekorClient}. Day 7 calls this to turn a real-passport
|
|
7
|
+
* bind into a public-log entry plus a portable bundle.
|
|
8
|
+
*/
|
|
9
|
+
import {} from './bind.js';
|
|
10
|
+
import { BUNDLE_FORMAT_VERSION, validateBundle, } from './bundle.js';
|
|
11
|
+
import { IN_TOTO_PAYLOAD_TYPE, signEnvelope } from './dsse.js';
|
|
12
|
+
import {} from './log/rekor.js';
|
|
13
|
+
/**
|
|
14
|
+
* Sign the canonical statement bytes with an ephemeral ECDSA P-256 key,
|
|
15
|
+
* submit the in-toto entry to Rekor, and assemble the bundle. Throws
|
|
16
|
+
* `PassportsignError('log_submission_failed', …)` (from the client) on
|
|
17
|
+
* any Rekor failure.
|
|
18
|
+
*/
|
|
19
|
+
export async function submitBinding(prepared, deps) {
|
|
20
|
+
const { envelope } = signEnvelope(prepared.statement_canonical, IN_TOTO_PAYLOAD_TYPE);
|
|
21
|
+
const rekorEntry = await deps.rekor.submitIntoto(envelope);
|
|
22
|
+
const bundle = {
|
|
23
|
+
bundle_format_version: BUNDLE_FORMAT_VERSION,
|
|
24
|
+
statement: Buffer.from(prepared.statement_canonical).toString('hex'),
|
|
25
|
+
proof_blob: prepared.proof_blob_b64,
|
|
26
|
+
rekor: {
|
|
27
|
+
log_entry_hash: rekorEntry.uuid,
|
|
28
|
+
inclusion_proof: rekorEntry.verification.inclusionProof,
|
|
29
|
+
log_root_at_submission: rekorEntry.verification.inclusionProof.rootHash,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
validateBundle(bundle);
|
|
33
|
+
return { bundle, rekorEntry };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=submit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit.js","sourceRoot":"","sources":["../src/submit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAwB,MAAM,WAAW,CAAC;AACjD,OAAO,EACL,qBAAqB,EAErB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAA6C,MAAM,gBAAgB,CAAC;AAW3E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAyB,EACzB,IAAuB;IAEvB,MAAM,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC,QAAQ,CAAC,mBAAmB,EAAE,oBAAoB,CAAC,CAAC;IACtF,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAE3D,MAAM,MAAM,GAAuB;QACjC,qBAAqB,EAAE,qBAAqB;QAC5C,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QACpE,UAAU,EAAE,QAAQ,CAAC,cAAc;QACnC,KAAK,EAAE;YACL,cAAc,EAAE,UAAU,CAAC,IAAI;YAC/B,eAAe,EAAE,UAAU,CAAC,YAAY,CAAC,cAAc;YACvD,sBAAsB,EAAE,UAAU,CAAC,YAAY,CAAC,cAAc,CAAC,QAAQ;SACxE;KACF,CAAC;IACF,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle verifier — the trust anchor for everyone who is not us.
|
|
3
|
+
*
|
|
4
|
+
* Day 6 scope: structural integrity (statement hash matches Rekor's
|
|
5
|
+
* recorded payloadHash), Merkle inclusion proof against the captured
|
|
6
|
+
* root, and log-root consistency between the captured root and the
|
|
7
|
+
* current witnessed root.
|
|
8
|
+
*
|
|
9
|
+
* Day 7 scope (deferred): SDK proof verification. Requires a
|
|
10
|
+
* bundle-schema extension to carry SDK inputs (proofs array,
|
|
11
|
+
* originalQuery, queryResult). For now `sdk_proof` reports
|
|
12
|
+
* `'pending_day_7'`.
|
|
13
|
+
*/
|
|
14
|
+
import { type PassportsignBundle } from './bundle.js';
|
|
15
|
+
import { type RekorClient } from './log/rekor.js';
|
|
16
|
+
export type CheckResult = 'pass' | 'fail' | 'skipped';
|
|
17
|
+
export interface BundleVerifyResult {
|
|
18
|
+
/**
|
|
19
|
+
* Statement bytes in the bundle hash to the `payloadHash` Rekor recorded
|
|
20
|
+
* for the entry.
|
|
21
|
+
*/
|
|
22
|
+
hash_match: CheckResult;
|
|
23
|
+
/**
|
|
24
|
+
* The captured inclusion proof verifies the Rekor entry's leaf hash
|
|
25
|
+
* against the captured root.
|
|
26
|
+
*/
|
|
27
|
+
inclusion_proof: CheckResult;
|
|
28
|
+
/**
|
|
29
|
+
* The captured root is a prefix of the current witnessed root (the log
|
|
30
|
+
* has not been rewritten in a way that orphans our entry). Skipped when
|
|
31
|
+
* no rekor client is provided.
|
|
32
|
+
*/
|
|
33
|
+
root_consistency: CheckResult;
|
|
34
|
+
/**
|
|
35
|
+
* SDK proof verification. `'skipped'` when no SDK verifier is injected.
|
|
36
|
+
* `'pass'` when the SDK validates the proofs AND the returned
|
|
37
|
+
* uniqueIdentifier matches the statement's predicate.
|
|
38
|
+
*/
|
|
39
|
+
sdk_proof: CheckResult;
|
|
40
|
+
/**
|
|
41
|
+
* `'pass'` only when every enabled check passes; `'fail'` if any check
|
|
42
|
+
* fails; `'pending'` when one or more checks are `'skipped'`.
|
|
43
|
+
*/
|
|
44
|
+
overall: 'pass' | 'fail' | 'pending';
|
|
45
|
+
errors: string[];
|
|
46
|
+
}
|
|
47
|
+
export interface SdkVerifyInput {
|
|
48
|
+
proofs: unknown[];
|
|
49
|
+
originalQuery: unknown;
|
|
50
|
+
queryResult: unknown;
|
|
51
|
+
scope?: string;
|
|
52
|
+
devMode?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface SdkVerifyResult {
|
|
55
|
+
verified: boolean;
|
|
56
|
+
uniqueIdentifier: string | undefined;
|
|
57
|
+
}
|
|
58
|
+
export interface SdkVerifier {
|
|
59
|
+
verify(input: SdkVerifyInput): Promise<SdkVerifyResult>;
|
|
60
|
+
}
|
|
61
|
+
export interface VerifyBundleDeps {
|
|
62
|
+
/** Inject a Rekor client to enable hash_match / inclusion / consistency checks. */
|
|
63
|
+
rekor?: RekorClient;
|
|
64
|
+
/** Inject a zkPassport SDK verifier to enable the sdk_proof check. */
|
|
65
|
+
sdkVerifier?: SdkVerifier;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Verify a passportsign bundle. Online checks (hash_match, inclusion_proof,
|
|
69
|
+
* root_consistency) require a {@link RekorClient}; without one they are
|
|
70
|
+
* marked `'skipped'`. SDK proof verification is Day 7 work and currently
|
|
71
|
+
* always returns `'pending_day_7'`.
|
|
72
|
+
*/
|
|
73
|
+
export declare function verifyBundle(bundle: PassportsignBundle, deps?: VerifyBundleDeps): Promise<BundleVerifyResult>;
|
|
74
|
+
//# sourceMappingURL=verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,KAAK,kBAAkB,EAAkB,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,UAAU,EAAE,WAAW,CAAC;IACxB;;;OAGG;IACH,eAAe,EAAE,WAAW,CAAC;IAC7B;;;;OAIG;IACH,gBAAgB,EAAE,WAAW,CAAC;IAC9B;;;;OAIG;IACH,SAAS,EAAE,WAAW,CAAC;IACvB;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,sEAAsE;IACtE,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AA+BD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,kBAAkB,EAC1B,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,kBAAkB,CAAC,CAoI7B"}
|