@keytrace/claims 0.0.5 → 0.0.10

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/dist/types.d.ts CHANGED
@@ -121,5 +121,7 @@ export interface VerifyOptions {
121
121
  plcDirectoryUrl?: string;
122
122
  /** Public ATProto API URL for handle resolution (default: https://public.api.bsky.app) */
123
123
  publicApiUrl?: string;
124
+ /** Trusted signer handles whose signing keys are accepted (default: ["keytrace.dev"]) */
125
+ trustedSigners?: string[];
124
126
  }
125
127
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoF,kBAAkB,EAAoB,aAAa,EAAE,MAAM,YAAY,CAAC;AAKxK,YAAY,EACV,aAAa,EACb,WAAW,EACX,cAAc,EACd,uBAAuB,EACvB,cAAc,EACd,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAQ7G;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkCvG"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoF,kBAAkB,EAAoB,aAAa,EAAE,MAAM,YAAY,CAAC;AAQxK,YAAY,EACV,aAAa,EACb,WAAW,EACX,cAAc,EACd,uBAAuB,EACvB,cAAc,EACd,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAQ7G;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsCvG"}
package/dist/verify.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { resolveHandle, resolvePds, listClaimRecords, getRecordByUri } from "./atproto.js";
2
2
  import { verifyES256Signature } from "./crypto/signature.js";
3
+ /** Default trusted signer handles */
4
+ const DEFAULT_TRUSTED_SIGNERS = ["keytrace.dev"];
3
5
  /**
4
6
  * Verify all keytrace claims for a handle.
5
7
  *
@@ -23,6 +25,9 @@ export async function getClaimsForHandle(handle, options) {
23
25
  * @returns Verification results for all claims
24
26
  */
25
27
  export async function getClaimsForDid(did, options) {
28
+ // Resolve trusted signer handles to DIDs once for the whole batch
29
+ const trustedSigners = options?.trustedSigners ?? DEFAULT_TRUSTED_SIGNERS;
30
+ const trustedDids = await resolveTrustedDids(trustedSigners, options);
26
31
  // Resolve PDS for the user
27
32
  const pdsUrl = await resolvePds(did, options);
28
33
  // Fetch all claim records
@@ -41,7 +46,7 @@ export async function getClaimsForDid(did, options) {
41
46
  // Verify each claim
42
47
  const claimResults = [];
43
48
  for (const record of claimRecords) {
44
- const result = await verifySingleClaim(did, record.uri, record.rkey, record.value, options);
49
+ const result = await verifySingleClaim(did, record.uri, record.rkey, record.value, trustedDids, options);
45
50
  claimResults.push(result);
46
51
  }
47
52
  return {
@@ -57,7 +62,7 @@ export async function getClaimsForDid(did, options) {
57
62
  /**
58
63
  * Verify a single claim's signature.
59
64
  */
60
- async function verifySingleClaim(did, uri, rkey, claim, options) {
65
+ async function verifySingleClaim(did, uri, rkey, claim, trustedDids, options) {
61
66
  const steps = [];
62
67
  try {
63
68
  // Step 1: Validate claim structure
@@ -70,7 +75,15 @@ async function verifySingleClaim(did, uri, rkey, claim, options) {
70
75
  return buildResult(uri, rkey, claim, false, steps, "Missing signature fields");
71
76
  }
72
77
  steps.push({ step: "validate_claim", success: true, detail: "Claim structure valid" });
73
- // Step 2: Fetch the signing key
78
+ // Step 2: Validate signing key is from a trusted signer
79
+ const signerDid = extractDidFromAtUri(claim.sig.src);
80
+ if (!signerDid || !trustedDids.has(signerDid)) {
81
+ const error = `Signing key is not from a trusted signer (source: ${claim.sig.src})`;
82
+ steps.push({ step: "validate_signer", success: false, error });
83
+ return buildResult(uri, rkey, claim, false, steps, error);
84
+ }
85
+ steps.push({ step: "validate_signer", success: true, detail: `Signing key from trusted signer (${signerDid})` });
86
+ // Step 3: Fetch the signing key
74
87
  let keyRecord;
75
88
  try {
76
89
  keyRecord = await getRecordByUri(claim.sig.src, options);
@@ -81,7 +94,7 @@ async function verifySingleClaim(did, uri, rkey, claim, options) {
81
94
  steps.push({ step: "fetch_key", success: false, error });
82
95
  return buildResult(uri, rkey, claim, false, steps, error);
83
96
  }
84
- // Step 3: Parse the public JWK
97
+ // Step 4: Parse the public JWK
85
98
  let publicJwk;
86
99
  try {
87
100
  publicJwk = JSON.parse(keyRecord.publicJwk);
@@ -95,7 +108,7 @@ async function verifySingleClaim(did, uri, rkey, claim, options) {
95
108
  steps.push({ step: "parse_key", success: false, error });
96
109
  return buildResult(uri, rkey, claim, false, steps, error);
97
110
  }
98
- // Step 4: Reconstruct the signed claim data
111
+ // Step 5: Reconstruct the signed claim data
99
112
  const signedData = {
100
113
  did,
101
114
  subject: claim.identity.subject,
@@ -107,7 +120,7 @@ async function verifySingleClaim(did, uri, rkey, claim, options) {
107
120
  success: true,
108
121
  detail: `Reconstructed signed data for ${claim.type}:${claim.identity.subject}`,
109
122
  });
110
- // Step 5: Verify the signature
123
+ // Step 6: Verify the signature
111
124
  const isValid = await verifyES256Signature(signedData, claim.sig.attestation, publicJwk);
112
125
  if (isValid) {
113
126
  steps.push({ step: "verify_signature", success: true, detail: "Signature verified" });
@@ -140,4 +153,27 @@ function buildResult(uri, rkey, claim, verified, steps, error) {
140
153
  claim,
141
154
  };
142
155
  }
156
+ /**
157
+ * Extract the DID from an AT URI (at://did/collection/rkey)
158
+ */
159
+ function extractDidFromAtUri(atUri) {
160
+ const match = atUri.match(/^at:\/\/([^/]+)\//);
161
+ return match?.[1] ?? null;
162
+ }
163
+ /**
164
+ * Resolve an array of handles to their DIDs.
165
+ */
166
+ async function resolveTrustedDids(handles, options) {
167
+ const dids = new Set();
168
+ await Promise.all(handles.map(async (handle) => {
169
+ try {
170
+ const did = await resolveHandle(handle, options);
171
+ dids.add(did);
172
+ }
173
+ catch {
174
+ // Skip handles that fail to resolve
175
+ }
176
+ }));
177
+ return dids;
178
+ }
143
179
  //# sourceMappingURL=verify.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keytrace/claims",
3
- "version": "0.0.5",
3
+ "version": "0.0.10",
4
4
  "description": "Verify keytrace identity claims",
5
5
  "files": [
6
6
  "src",
@@ -30,6 +30,11 @@
30
30
  "typescript": "^5.7.0",
31
31
  "vitest": "^2.1.0"
32
32
  },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/orta/keytrace",
36
+ "directory": "packages/claims"
37
+ },
33
38
  "engines": {
34
39
  "node": ">=18"
35
40
  }
package/src/types.ts CHANGED
@@ -130,4 +130,6 @@ export interface VerifyOptions {
130
130
  plcDirectoryUrl?: string;
131
131
  /** Public ATProto API URL for handle resolution (default: https://public.api.bsky.app) */
132
132
  publicApiUrl?: string;
133
+ /** Trusted signer handles whose signing keys are accepted (default: ["keytrace.dev"]) */
134
+ trustedSigners?: string[];
133
135
  }
package/src/verify.ts CHANGED
@@ -2,6 +2,9 @@ import type { ClaimRecord, ClaimVerificationResult, ES256PublicJwk, KeyRecord, S
2
2
  import { resolveHandle, resolvePds, listClaimRecords, getRecordByUri } from "./atproto.js";
3
3
  import { verifyES256Signature } from "./crypto/signature.js";
4
4
 
5
+ /** Default trusted signer handles */
6
+ const DEFAULT_TRUSTED_SIGNERS = ["keytrace.dev"];
7
+
5
8
  // Re-export types for convenience
6
9
  export type {
7
10
  ClaimIdentity,
@@ -41,6 +44,10 @@ export async function getClaimsForHandle(handle: string, options?: VerifyOptions
41
44
  * @returns Verification results for all claims
42
45
  */
43
46
  export async function getClaimsForDid(did: string, options?: VerifyOptions): Promise<VerificationResult> {
47
+ // Resolve trusted signer handles to DIDs once for the whole batch
48
+ const trustedSigners = options?.trustedSigners ?? DEFAULT_TRUSTED_SIGNERS;
49
+ const trustedDids = await resolveTrustedDids(trustedSigners, options);
50
+
44
51
  // Resolve PDS for the user
45
52
  const pdsUrl = await resolvePds(did, options);
46
53
 
@@ -61,7 +68,7 @@ export async function getClaimsForDid(did: string, options?: VerifyOptions): Pro
61
68
  const claimResults: ClaimVerificationResult[] = [];
62
69
 
63
70
  for (const record of claimRecords) {
64
- const result = await verifySingleClaim(did, record.uri, record.rkey, record.value, options);
71
+ const result = await verifySingleClaim(did, record.uri, record.rkey, record.value, trustedDids, options);
65
72
  claimResults.push(result);
66
73
  }
67
74
 
@@ -79,7 +86,7 @@ export async function getClaimsForDid(did: string, options?: VerifyOptions): Pro
79
86
  /**
80
87
  * Verify a single claim's signature.
81
88
  */
82
- async function verifySingleClaim(did: string, uri: string, rkey: string, claim: ClaimRecord, options?: VerifyOptions): Promise<ClaimVerificationResult> {
89
+ async function verifySingleClaim(did: string, uri: string, rkey: string, claim: ClaimRecord, trustedDids: Set<string>, options?: VerifyOptions): Promise<ClaimVerificationResult> {
83
90
  const steps: VerificationStep[] = [];
84
91
 
85
92
  try {
@@ -94,7 +101,16 @@ async function verifySingleClaim(did: string, uri: string, rkey: string, claim:
94
101
  }
95
102
  steps.push({ step: "validate_claim", success: true, detail: "Claim structure valid" });
96
103
 
97
- // Step 2: Fetch the signing key
104
+ // Step 2: Validate signing key is from a trusted signer
105
+ const signerDid = extractDidFromAtUri(claim.sig.src);
106
+ if (!signerDid || !trustedDids.has(signerDid)) {
107
+ const error = `Signing key is not from a trusted signer (source: ${claim.sig.src})`;
108
+ steps.push({ step: "validate_signer", success: false, error });
109
+ return buildResult(uri, rkey, claim, false, steps, error);
110
+ }
111
+ steps.push({ step: "validate_signer", success: true, detail: `Signing key from trusted signer (${signerDid})` });
112
+
113
+ // Step 3: Fetch the signing key
98
114
  let keyRecord: KeyRecord;
99
115
  try {
100
116
  keyRecord = await getRecordByUri<KeyRecord>(claim.sig.src, options);
@@ -105,7 +121,7 @@ async function verifySingleClaim(did: string, uri: string, rkey: string, claim:
105
121
  return buildResult(uri, rkey, claim, false, steps, error);
106
122
  }
107
123
 
108
- // Step 3: Parse the public JWK
124
+ // Step 4: Parse the public JWK
109
125
  let publicJwk: ES256PublicJwk;
110
126
  try {
111
127
  publicJwk = JSON.parse(keyRecord.publicJwk) as ES256PublicJwk;
@@ -119,7 +135,7 @@ async function verifySingleClaim(did: string, uri: string, rkey: string, claim:
119
135
  return buildResult(uri, rkey, claim, false, steps, error);
120
136
  }
121
137
 
122
- // Step 4: Reconstruct the signed claim data
138
+ // Step 5: Reconstruct the signed claim data
123
139
  const signedData: SignedClaimData = {
124
140
  did,
125
141
  subject: claim.identity.subject,
@@ -132,7 +148,7 @@ async function verifySingleClaim(did: string, uri: string, rkey: string, claim:
132
148
  detail: `Reconstructed signed data for ${claim.type}:${claim.identity.subject}`,
133
149
  });
134
150
 
135
- // Step 5: Verify the signature
151
+ // Step 6: Verify the signature
136
152
  const isValid = await verifyES256Signature(signedData, claim.sig.attestation, publicJwk);
137
153
 
138
154
  if (isValid) {
@@ -165,3 +181,29 @@ function buildResult(uri: string, rkey: string, claim: ClaimRecord, verified: bo
165
181
  claim,
166
182
  };
167
183
  }
184
+
185
+ /**
186
+ * Extract the DID from an AT URI (at://did/collection/rkey)
187
+ */
188
+ function extractDidFromAtUri(atUri: string): string | null {
189
+ const match = atUri.match(/^at:\/\/([^/]+)\//);
190
+ return match?.[1] ?? null;
191
+ }
192
+
193
+ /**
194
+ * Resolve an array of handles to their DIDs.
195
+ */
196
+ async function resolveTrustedDids(handles: string[], options?: VerifyOptions): Promise<Set<string>> {
197
+ const dids = new Set<string>();
198
+ await Promise.all(
199
+ handles.map(async (handle) => {
200
+ try {
201
+ const did = await resolveHandle(handle, options);
202
+ dids.add(did);
203
+ } catch {
204
+ // Skip handles that fail to resolve
205
+ }
206
+ }),
207
+ );
208
+ return dids;
209
+ }