@oma3/omatrust 0.1.0-alpha.10 → 0.1.0-alpha.12

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.
Files changed (48) hide show
  1. package/README.md +3 -0
  2. package/dist/app-registry/index.cjs +53 -0
  3. package/dist/app-registry/index.cjs.map +1 -1
  4. package/dist/app-registry/index.js +53 -0
  5. package/dist/app-registry/index.js.map +1 -1
  6. package/dist/identity/index.cjs +1028 -6
  7. package/dist/identity/index.cjs.map +1 -1
  8. package/dist/identity/index.d.cts +2 -1
  9. package/dist/identity/index.d.ts +2 -1
  10. package/dist/identity/index.js +984 -7
  11. package/dist/identity/index.js.map +1 -1
  12. package/dist/index-B5OC9_8B.d.cts +480 -0
  13. package/dist/index-Bu-xxcv9.d.ts +407 -0
  14. package/dist/index-C6WNgPRx.d.ts +480 -0
  15. package/dist/index-C7odEbp6.d.cts +407 -0
  16. package/dist/index.cjs +2498 -373
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +4 -3
  19. package/dist/index.d.ts +4 -3
  20. package/dist/index.js +2342 -236
  21. package/dist/index.js.map +1 -1
  22. package/dist/reputation/index.browser.cjs +949 -67
  23. package/dist/reputation/index.browser.cjs.map +1 -1
  24. package/dist/reputation/index.browser.d.cts +2 -2
  25. package/dist/reputation/index.browser.d.ts +2 -2
  26. package/dist/reputation/index.browser.js +947 -67
  27. package/dist/reputation/index.browser.js.map +1 -1
  28. package/dist/reputation/index.cjs +1745 -232
  29. package/dist/reputation/index.cjs.map +1 -1
  30. package/dist/reputation/index.d.cts +3 -2
  31. package/dist/reputation/index.d.ts +3 -2
  32. package/dist/reputation/index.js +1727 -232
  33. package/dist/reputation/index.js.map +1 -1
  34. package/dist/{subject-ownership-CXvzEjpH.d.cts → subject-ownership-B7cFlm8c.d.cts} +256 -26
  35. package/dist/{subject-ownership-CXvzEjpH.d.ts → subject-ownership-B7cFlm8c.d.ts} +256 -26
  36. package/dist/types-Dn0OwaNj.d.cts +307 -0
  37. package/dist/types-Dn0OwaNj.d.ts +307 -0
  38. package/dist/widgets/index.cjs +70 -27
  39. package/dist/widgets/index.cjs.map +1 -1
  40. package/dist/widgets/index.d.cts +45 -18
  41. package/dist/widgets/index.d.ts +45 -18
  42. package/dist/widgets/index.js +67 -26
  43. package/dist/widgets/index.js.map +1 -1
  44. package/package.json +5 -2
  45. package/dist/index-B9KW02US.d.cts +0 -119
  46. package/dist/index-DXrwBex9.d.ts +0 -119
  47. package/dist/index-QZDExA4I.d.cts +0 -90
  48. package/dist/index-QZDExA4I.d.ts +0 -90
@@ -0,0 +1,307 @@
1
+ /**
2
+ * JWK and did:jwk Helpers — Phase 2
3
+ *
4
+ * Provides conversion between public JWKs and did:jwk DIDs,
5
+ * deterministic JWK comparison, and public JWK validation.
6
+ *
7
+ * did:jwk is the preferred durable DID representation for JWS/JWK public key
8
+ * material. It is immutable (the DID IS the key) and should be used as the
9
+ * controllerDid for authorization checks.
10
+ *
11
+ * Uses the `jose` library for base64url encoding/decoding and JWK thumbprints.
12
+ */
13
+ /** Minimal public JWK structure */
14
+ interface PublicJwk {
15
+ kty: string;
16
+ [key: string]: unknown;
17
+ }
18
+ /** Result of JWK validation */
19
+ interface JwkValidationResult {
20
+ valid: boolean;
21
+ error?: string;
22
+ }
23
+ /**
24
+ * Validate that a JWK object is a well-formed public key.
25
+ *
26
+ * Requirements:
27
+ * - Must be a non-null object
28
+ * - Must have a valid `kty` (EC, OKP, RSA)
29
+ * - Must have required public key fields for its key type
30
+ * - Must NOT contain private key material (d, p, q, dp, dq, qi, oth)
31
+ */
32
+ declare function validatePublicJwk(jwk: unknown): JwkValidationResult;
33
+ /**
34
+ * Convert a public JWK to a did:jwk DID.
35
+ *
36
+ * Uses deterministic (sorted-key) JSON serialization and base64url encoding.
37
+ * Rejects JWKs containing private key material.
38
+ *
39
+ * @param jwk - A public JWK object
40
+ * @returns The did:jwk DID string
41
+ * @throws OmaTrustError if the JWK is invalid or contains private key material
42
+ */
43
+ declare function jwkToDidJwk(jwk: unknown): string;
44
+ /**
45
+ * Convert a did:jwk DID back to a public JWK object.
46
+ *
47
+ * Validates the DID structure, decodes the base64url payload,
48
+ * parses JSON, and validates the resulting JWK.
49
+ *
50
+ * @param didJwk - A did:jwk DID string
51
+ * @returns The decoded public JWK object
52
+ * @throws OmaTrustError if the DID is malformed or contains private key material
53
+ */
54
+ declare function didJwkToJwk(didJwk: string): PublicJwk;
55
+ /**
56
+ * Compare two public JWKs for equality.
57
+ *
58
+ * Compares only the public key material fields (kty, crv, x, y, n, e, etc.).
59
+ * Ignores property order, metadata fields (kid, use, alg, key_ops, ext),
60
+ * and rejects/strips private key fields before comparison.
61
+ *
62
+ * @param a - First public JWK
63
+ * @param b - Second public JWK
64
+ * @returns true if both JWKs represent the same public key
65
+ * @throws OmaTrustError if either JWK contains private key material
66
+ */
67
+ declare function publicJwkEquals(a: unknown, b: unknown): boolean;
68
+ /**
69
+ * Compute an RFC 7638 JWK Thumbprint for a public JWK.
70
+ *
71
+ * Returns the base64url-encoded SHA-256 thumbprint. This is a compact,
72
+ * deterministic fingerprint of the public key material.
73
+ *
74
+ * Used in OMATrust DNS TXT records as: `jkt=S256:<thumbprint>`
75
+ *
76
+ * @param jwk - A public JWK object
77
+ * @param digestAlgorithm - Hash algorithm (default: "sha256")
78
+ * @returns base64url-encoded thumbprint string
79
+ * @throws OmaTrustError if the JWK is invalid or contains private key material
80
+ */
81
+ declare function computeJwkThumbprint(jwk: unknown, digestAlgorithm?: "sha256" | "sha384" | "sha512"): Promise<string>;
82
+ /**
83
+ * Format a JWK thumbprint as an OMATrust DNS TXT `jkt` value.
84
+ *
85
+ * Format: `jkt=S256:<base64url-thumbprint>`
86
+ *
87
+ * @param jwk - A public JWK object
88
+ * @returns Formatted jkt string for DNS TXT records
89
+ */
90
+ declare function formatJktValue(jwk: unknown): Promise<string>;
91
+
92
+ /**
93
+ * DID URL Key Resolution — Phase 3
94
+ *
95
+ * Resolves DID URL key references (e.g. did:web:api.example.com#key-1) to
96
+ * public key material and derives durable did:jwk controller DIDs.
97
+ *
98
+ * DID URLs are mutable key references. This module resolves them to the
99
+ * actual public key material they currently point to, then converts that
100
+ * material into an immutable did:jwk for use as a controller DID.
101
+ */
102
+
103
+ /** Result of resolving a DID URL to public key material */
104
+ interface ResolvedPublicKey {
105
+ /** The original DID URL */
106
+ didUrl: string;
107
+ /** The base DID (without fragment) */
108
+ did: string;
109
+ /** The fragment identifier */
110
+ fragment: string | null;
111
+ /** The resolved public JWK */
112
+ publicKeyJwk: PublicJwk;
113
+ /** The verification method ID that matched */
114
+ verificationMethodId: string;
115
+ }
116
+ /** Result of resolving a DID URL to a durable controller DID */
117
+ interface ResolvedControllerDid extends ResolvedPublicKey {
118
+ /** The durable did:jwk derived from the resolved public key */
119
+ controllerDid: string;
120
+ }
121
+ /** Options for DID URL key resolution */
122
+ interface ResolveKeyOptions {
123
+ /**
124
+ * Custom DID document fetcher. If not provided, uses the shared
125
+ * fetchDidDocument which fetches from `/.well-known/did.json`.
126
+ */
127
+ fetchDidDocument?: (domain: string) => Promise<Record<string, unknown>>;
128
+ }
129
+ /**
130
+ * Resolve a DID URL to public key material.
131
+ *
132
+ * Currently supports:
133
+ * - did:web with fragment (e.g. did:web:api.example.com#key-1)
134
+ *
135
+ * Resolution steps:
136
+ * 1. Parse the DID URL
137
+ * 2. Resolve the base DID (fetch DID document)
138
+ * 3. Find the matching verification method
139
+ * 4. Extract and validate publicKeyJwk
140
+ *
141
+ * This function only obtains key material. It does not make authorization
142
+ * decisions or check Controller Witness / Key Binding records.
143
+ *
144
+ * @param didUrl - A DID URL string (e.g. "did:web:api.example.com#key-1")
145
+ * @param options - Optional configuration (custom fetcher, etc.)
146
+ * @returns Resolved public key information
147
+ * @throws OmaTrustError if resolution fails
148
+ */
149
+ declare function resolveDidUrlToPublicKey(didUrl: string, options?: ResolveKeyOptions): Promise<ResolvedPublicKey>;
150
+ /**
151
+ * Resolve a DID URL to a durable controller DID.
152
+ *
153
+ * This wraps resolveDidUrlToPublicKey and adds the did:jwk conversion step.
154
+ * The returned controllerDid is the durable DID that callers should pass
155
+ * to getControllerAuthorization.
156
+ *
157
+ * @param didUrl - A DID URL string (e.g. "did:web:api.example.com#key-1")
158
+ * @param options - Optional configuration (custom fetcher, etc.)
159
+ * @returns Resolved public key plus derived did:jwk controller DID
160
+ * @throws OmaTrustError if resolution fails
161
+ */
162
+ declare function resolveDidUrlToControllerDid(didUrl: string, options?: ResolveKeyOptions): Promise<ResolvedControllerDid>;
163
+
164
+ /**
165
+ * Identity Types — Phase 4
166
+ *
167
+ * Types for JWS verification results and authorization metadata.
168
+ * These define the contract between signature verification and
169
+ * downstream authorization checks via getControllerAuthorization.
170
+ */
171
+
172
+ /** Source of the public key used for JWS signature verification */
173
+ type PublicKeySource = "embedded-jwk" | "kid-resolution";
174
+ /**
175
+ * Structured result of JWS signature verification.
176
+ *
177
+ * This result is NOT an authorization result. It does not determine whether
178
+ * the signing key was authorized to act for the service identified by resourceUrl.
179
+ *
180
+ * It provides enough information for callers to perform downstream authorization
181
+ * checks via getControllerAuthorization:
182
+ * - publicKeyDid (did:jwk) is the durable controller DID
183
+ * - resourceUrl identifies the service subject
184
+ * - issuedAt enables authorization-window checks for receipts
185
+ */
186
+ interface JwsVerificationResult {
187
+ /** Whether the JWS signature is cryptographically valid */
188
+ valid: boolean;
189
+ /** Decoded JWS protected header */
190
+ header: Record<string, unknown>;
191
+ /** Decoded JWS payload */
192
+ payload: Record<string, unknown>;
193
+ /** kid from the JWS header (a key reference, NOT a controller DID) */
194
+ kid: string | null;
195
+ /** The public JWK used for signature verification */
196
+ publicKeyJwk: PublicJwk;
197
+ /** How the public key was obtained */
198
+ publicKeySource: PublicKeySource;
199
+ /**
200
+ * The durable did:jwk derived from the public key.
201
+ * This is the controller DID for downstream authorization checks.
202
+ * Pass this as controllerDid to getControllerAuthorization.
203
+ */
204
+ publicKeyDid: string;
205
+ /** Error details when valid is false */
206
+ error?: JwsVerificationError;
207
+ }
208
+ /** Error details for failed JWS verification */
209
+ interface JwsVerificationError {
210
+ code: string;
211
+ message: string;
212
+ }
213
+ /**
214
+ * Failed JWS verification result.
215
+ * Returned when parsing, decoding, or signature verification fails.
216
+ */
217
+ interface JwsVerificationFailure {
218
+ valid: false;
219
+ error: JwsVerificationError;
220
+ header?: Record<string, unknown>;
221
+ payload?: Record<string, unknown>;
222
+ kid?: string | null;
223
+ publicKeyJwk?: PublicJwk;
224
+ publicKeySource?: PublicKeySource;
225
+ publicKeyDid?: string;
226
+ }
227
+ /**
228
+ * Authorization metadata extracted from a verified x402 artifact.
229
+ *
230
+ * This is the information a caller needs to perform an authorization check
231
+ * after signature verification succeeds (JWS or EIP-712).
232
+ *
233
+ * Usage:
234
+ * 1. Verify artifact → get JwsVerificationResult or Eip712VerificationResult
235
+ * 2. Extract AuthorizationMetadata from the result
236
+ * 3. Call getControllerAuthorization({ subjectDid, controllerDid, purpose })
237
+ * 4. Evaluate the returned authorization window against policy
238
+ */
239
+ interface AuthorizationMetadata {
240
+ /**
241
+ * The durable controller DID derived from the verified key material.
242
+ * - JWS: did:jwk derived from the public key
243
+ * - EIP-712: did:pkh:eip155:1:<signer-address>
244
+ * Pass this as controllerDid to getControllerAuthorization.
245
+ */
246
+ controllerDid: string;
247
+ /**
248
+ * The subject DID derived from resourceUrl.
249
+ * For x402 artifacts, this is typically did:web:<domain-from-resourceUrl>.
250
+ * Pass this as subjectDid to getControllerAuthorization.
251
+ */
252
+ subjectDid: string | null;
253
+ /**
254
+ * The resourceUrl from the signed payload.
255
+ * Identifies the service/resource the artifact is associated with.
256
+ */
257
+ resourceUrl: string | null;
258
+ /**
259
+ * The issuedAt timestamp from the signed payload (receipts).
260
+ * Used for authorization-window checks — was the controller authorized at this time?
261
+ * May be a string (ISO) or number (unix seconds) depending on the payload.
262
+ */
263
+ issuedAt: string | number | null;
264
+ /**
265
+ * The kid from the JWS header (mutable key reference).
266
+ * Useful for key-pinning lookups but NOT a controller DID.
267
+ * Null for EIP-712 artifacts.
268
+ */
269
+ kid: string | null;
270
+ /**
271
+ * The public JWK used for signature verification.
272
+ * Present for JWS artifacts, null for EIP-712.
273
+ */
274
+ publicKeyJwk: PublicJwk | null;
275
+ /**
276
+ * The recovered signer address (checksummed).
277
+ * Present for EIP-712 artifacts, null for JWS.
278
+ */
279
+ signer: string | null;
280
+ }
281
+ /**
282
+ * Input for extractAuthorizationMetadata.
283
+ * Accepts either a JwsVerificationResult or an Eip712VerificationResult.
284
+ */
285
+ type VerificationResultInput = JwsVerificationResult | {
286
+ valid: true;
287
+ payload: Record<string, unknown>;
288
+ signer: string;
289
+ artifactType: string;
290
+ };
291
+ /**
292
+ * Extract authorization metadata from a successful verification result.
293
+ *
294
+ * Works with both JWS and EIP-712 verification results:
295
+ * - JWS: controllerDid is did:jwk, publicKeyJwk is populated, kid may be present
296
+ * - EIP-712: controllerDid is did:pkh:eip155:1:<signer>, signer is populated
297
+ *
298
+ * Derives the subject DID from resourceUrl when possible (assumes did:web
299
+ * for HTTPS URLs). Returns null for subjectDid if resourceUrl is missing
300
+ * or cannot be parsed.
301
+ *
302
+ * @param result - A successful verification result (valid === true)
303
+ * @returns Authorization metadata for downstream getControllerAuthorization calls
304
+ */
305
+ declare function extractAuthorizationMetadata(result: VerificationResultInput): AuthorizationMetadata;
306
+
307
+ export { type AuthorizationMetadata as A, type JwkValidationResult as J, type PublicJwk as P, type ResolveKeyOptions as R, type VerificationResultInput as V, type JwsVerificationError as a, type JwsVerificationFailure as b, type JwsVerificationResult as c, type PublicKeySource as d, type ResolvedControllerDid as e, type ResolvedPublicKey as f, computeJwkThumbprint as g, didJwkToJwk as h, extractAuthorizationMetadata as i, formatJktValue as j, jwkToDidJwk as k, resolveDidUrlToPublicKey as l, publicJwkEquals as p, resolveDidUrlToControllerDid as r, validatePublicJwk as v };
@@ -7,35 +7,76 @@ var OMATRUST_SIGN_TYPED_DATA = "omatrust:signTypedData";
7
7
  var OMATRUST_SIGNATURE = "omatrust:signature";
8
8
  var OMATRUST_SIGNATURE_ERROR = "omatrust:signatureError";
9
9
 
10
- // src/widgets/trust-policy.ts
11
- var DEFAULT_TRUST_POLICY_URL = "https://api.omatrust.org/v1/trust-policy";
12
- var TRUST_POLICY_URL = DEFAULT_TRUST_POLICY_URL;
13
- var cachedPolicy = null;
10
+ // src/shared/errors.ts
11
+ var OmaTrustError = class extends Error {
12
+ code;
13
+ details;
14
+ constructor(code, message, details) {
15
+ super(message);
16
+ this.name = "OmaTrustError";
17
+ this.code = code;
18
+ this.details = details;
19
+ }
20
+ };
21
+
22
+ // src/shared/trust-anchors.ts
23
+ var DEFAULT_TRUST_ANCHORS_URL = "https://api.omatrust.org/v1/trust-anchors";
24
+ var TRUST_ANCHORS_URL = DEFAULT_TRUST_ANCHORS_URL;
25
+ var cachedAnchors = null;
14
26
  var cacheTimestamp = 0;
15
27
  var CACHE_TTL_MS = 5 * 60 * 1e3;
16
- async function fetchTrustPolicy(url) {
28
+ async function fetchTrustAnchors(url) {
17
29
  const now = Date.now();
18
- if (cachedPolicy && now - cacheTimestamp < CACHE_TTL_MS) {
19
- return cachedPolicy;
30
+ if (cachedAnchors && now - cacheTimestamp < CACHE_TTL_MS) {
31
+ return cachedAnchors;
32
+ }
33
+ let res;
34
+ try {
35
+ res = await fetch(url ?? TRUST_ANCHORS_URL);
36
+ } catch (err) {
37
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to fetch trust anchors", { err });
20
38
  }
21
- const res = await fetch(url ?? TRUST_POLICY_URL);
22
39
  if (!res.ok) {
23
- throw new Error(`Failed to fetch trust policy: ${res.status} ${res.statusText}`);
40
+ throw new OmaTrustError("NETWORK_ERROR", `Failed to fetch trust anchors: ${res.status} ${res.statusText}`);
24
41
  }
25
- const policy = await res.json();
26
- if (!policy.version || !policy.chains || typeof policy.chains !== "object") {
27
- throw new Error("Invalid trust policy format");
42
+ const anchors = await res.json();
43
+ if (!anchors.version || !anchors.chains || typeof anchors.chains !== "object") {
44
+ throw new OmaTrustError("INVALID_INPUT", "Invalid trust anchors format");
28
45
  }
29
- cachedPolicy = policy;
46
+ cachedAnchors = anchors;
30
47
  cacheTimestamp = now;
31
- return policy;
48
+ return anchors;
32
49
  }
33
- function extractAllowlists(policy) {
50
+ function getChainAnchors(anchors, caip2) {
51
+ const chain = anchors.chains[caip2];
52
+ if (!chain) {
53
+ throw new OmaTrustError("UNSUPPORTED_CHAIN", `Chain ${caip2} is not in the trust anchors`, {
54
+ caip2,
55
+ supportedChains: Object.keys(anchors.chains)
56
+ });
57
+ }
58
+ return chain;
59
+ }
60
+ function getSchemaAnchor(anchors, caip2, schemaName) {
61
+ const chain = getChainAnchors(anchors, caip2);
62
+ const uid = chain.schemas[schemaName];
63
+ if (!uid) {
64
+ throw new OmaTrustError("INVALID_INPUT", `Schema "${schemaName}" not found in trust anchors for chain ${caip2}`, {
65
+ caip2,
66
+ schemaName,
67
+ availableSchemas: Object.keys(chain.schemas)
68
+ });
69
+ }
70
+ return uid;
71
+ }
72
+ function extractAllowlists(anchors) {
34
73
  const contracts = [];
35
74
  const schemas = [];
36
- for (const chain of Object.values(policy.chains)) {
75
+ for (const chain of Object.values(anchors.chains)) {
37
76
  if (chain.easContract) contracts.push(chain.easContract);
38
- if (chain.schemas) schemas.push(...chain.schemas);
77
+ if (chain.schemas && typeof chain.schemas === "object") {
78
+ schemas.push(...Object.values(chain.schemas));
79
+ }
39
80
  }
40
81
  return {
41
82
  allowedContracts: [...new Set(contracts)],
@@ -46,7 +87,7 @@ function extractAllowlists(policy) {
46
87
  // src/widgets/bridge.ts
47
88
  function getTrustedBaseDomain() {
48
89
  try {
49
- const hostname = new URL(TRUST_POLICY_URL).hostname;
90
+ const hostname = new URL(TRUST_ANCHORS_URL).hostname;
50
91
  const parts = hostname.split(".");
51
92
  return parts.length >= 2 ? parts.slice(-2).join(".") : hostname;
52
93
  } catch {
@@ -89,7 +130,7 @@ function validateEasSigningRequest(data, allowedSchemas, allowedContracts) {
89
130
  }
90
131
  const contractLower = d.verifyingContract.toLowerCase();
91
132
  if (!allowedContracts.some((c) => c.toLowerCase() === contractLower)) {
92
- return { valid: false, reason: `Contract ${d.verifyingContract} is not in the OMA3 trust policy` };
133
+ return { valid: false, reason: `Contract ${d.verifyingContract} is not in the OMA3 trust anchors` };
93
134
  }
94
135
  if (!types || typeof types !== "object") {
95
136
  return { valid: false, reason: "Missing types object" };
@@ -103,7 +144,7 @@ function validateEasSigningRequest(data, allowedSchemas, allowedContracts) {
103
144
  }
104
145
  const schemaLower = m.schema.toLowerCase();
105
146
  if (!allowedSchemas.some((s) => s.toLowerCase() === schemaLower)) {
106
- return { valid: false, reason: `Schema ${m.schema} is not in the OMA3 trust policy` };
147
+ return { valid: false, reason: `Schema ${m.schema} is not in the OMA3 trust anchors` };
107
148
  }
108
149
  if (typeof m.attester !== "string" || !HEX_ADDRESS_RE.test(m.attester)) {
109
150
  return { valid: false, reason: `Invalid attester address: ${m.attester}` };
@@ -120,18 +161,18 @@ function validateEasSigningRequest(data, allowedSchemas, allowedContracts) {
120
161
  }
121
162
  async function createSigningBridge(options) {
122
163
  const { iframeId, signTypedData, devOriginOverride } = options;
123
- const policy = await fetchTrustPolicy();
124
- const { allowedContracts, allowedSchemas } = extractAllowlists(policy);
164
+ const anchors = await fetchTrustAnchors();
165
+ const { allowedContracts, allowedSchemas } = extractAllowlists(anchors);
125
166
  if (allowedContracts.length === 0 || allowedSchemas.length === 0) {
126
- throw new Error("Trust policy contains no allowed contracts or schemas");
167
+ throw new Error("Trust anchors contain no allowed contracts or schemas");
127
168
  }
128
169
  const baseDomain = getTrustedBaseDomain();
129
- const policyOrigins = policy.widgetOrigins ?? [];
170
+ const anchorOrigins = anchors.widgetOrigins ?? [];
130
171
  async function handleMessage(event) {
131
172
  const data = event.data;
132
173
  if (!data || typeof data !== "object" || typeof data.type !== "string") return;
133
174
  if (!String(data.type).startsWith("omatrust:")) return;
134
- if (!isOriginTrusted(event.origin, baseDomain, policyOrigins, devOriginOverride)) {
175
+ if (!isOriginTrusted(event.origin, baseDomain, anchorOrigins, devOriginOverride)) {
135
176
  return;
136
177
  }
137
178
  const iframe = document.getElementById(iframeId);
@@ -187,9 +228,11 @@ exports.OMATRUST_READY = OMATRUST_READY;
187
228
  exports.OMATRUST_SIGNATURE = OMATRUST_SIGNATURE;
188
229
  exports.OMATRUST_SIGNATURE_ERROR = OMATRUST_SIGNATURE_ERROR;
189
230
  exports.OMATRUST_SIGN_TYPED_DATA = OMATRUST_SIGN_TYPED_DATA;
190
- exports.TRUST_POLICY_URL = TRUST_POLICY_URL;
231
+ exports.TRUST_ANCHORS_URL = TRUST_ANCHORS_URL;
191
232
  exports.createSigningBridge = createSigningBridge;
192
233
  exports.extractAllowlists = extractAllowlists;
193
- exports.fetchTrustPolicy = fetchTrustPolicy;
234
+ exports.fetchTrustAnchors = fetchTrustAnchors;
235
+ exports.getChainAnchors = getChainAnchors;
236
+ exports.getSchemaAnchor = getSchemaAnchor;
194
237
  //# sourceMappingURL=index.cjs.map
195
238
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/widgets/protocol.ts","../../src/widgets/trust-policy.ts","../../src/widgets/bridge.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * postMessage protocol constants and types for the OMATrust widget bridge.\n *\n * Widget (iframe) → Host:\n * omatrust:ready — widget loaded, requesting handshake\n * omatrust:signTypedData — widget requests EIP-712 signature\n *\n * Host → Widget (iframe):\n * omatrust:hostReady — host acknowledges the widget\n * omatrust:signature — host returns a signature\n * omatrust:signatureError — host reports a signing failure\n */\n\nexport const OMATRUST_READY = \"omatrust:ready\" as const;\nexport const OMATRUST_HOST_READY = \"omatrust:hostReady\" as const;\nexport const OMATRUST_SIGN_TYPED_DATA = \"omatrust:signTypedData\" as const;\nexport const OMATRUST_SIGNATURE = \"omatrust:signature\" as const;\nexport const OMATRUST_SIGNATURE_ERROR = \"omatrust:signatureError\" as const;\n\nexport type OmaTrustReadyMessage = {\n type: typeof OMATRUST_READY;\n};\n\nexport type OmaTrustHostReadyMessage = {\n type: typeof OMATRUST_HOST_READY;\n};\n\nexport type OmaTrustSignTypedDataMessage = {\n type: typeof OMATRUST_SIGN_TYPED_DATA;\n id: string;\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n message: Record<string, unknown>;\n};\n\nexport type OmaTrustSignatureMessage = {\n type: typeof OMATRUST_SIGNATURE;\n id: string;\n signature: string;\n};\n\nexport type OmaTrustSignatureErrorMessage = {\n type: typeof OMATRUST_SIGNATURE_ERROR;\n id: string;\n error: string;\n};\n\nexport type OmaTrustMessage =\n | OmaTrustReadyMessage\n | OmaTrustHostReadyMessage\n | OmaTrustSignTypedDataMessage\n | OmaTrustSignatureMessage\n | OmaTrustSignatureErrorMessage;\n","/**\n * Trust policy: fetches the OMA3 allowlist of EAS contracts and schemas.\n *\n * The bridge uses this to validate signing requests automatically.\n * Developers don't need to maintain their own allowlists.\n */\n\nconst DEFAULT_TRUST_POLICY_URL = \"https://api.omatrust.org/v1/trust-policy\";\n\nexport const TRUST_POLICY_URL = DEFAULT_TRUST_POLICY_URL;\n\nexport type ChainPolicy = {\n name: string;\n easContract: string;\n schemas: string[];\n};\n\nexport type TrustPolicy = {\n version: number;\n updatedAt: string;\n widgetOrigins?: string[];\n chains: Record<string, ChainPolicy>;\n};\n\nlet cachedPolicy: TrustPolicy | null = null;\nlet cacheTimestamp = 0;\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Fetch the trust policy from the OMA3 API gateway.\n * Caches the result for 5 minutes.\n *\n * @param url Override the trust policy URL (for testing or custom deployments)\n */\nexport async function fetchTrustPolicy(url?: string): Promise<TrustPolicy> {\n const now = Date.now();\n if (cachedPolicy && now - cacheTimestamp < CACHE_TTL_MS) {\n return cachedPolicy;\n }\n\n const res = await fetch(url ?? TRUST_POLICY_URL);\n if (!res.ok) {\n throw new Error(`Failed to fetch trust policy: ${res.status} ${res.statusText}`);\n }\n\n const policy: TrustPolicy = await res.json();\n\n if (!policy.version || !policy.chains || typeof policy.chains !== \"object\") {\n throw new Error(\"Invalid trust policy format\");\n }\n\n cachedPolicy = policy;\n cacheTimestamp = now;\n return policy;\n}\n\n/**\n * Extract the allowed contracts and schemas from a trust policy.\n * Returns all contracts and schemas across all chains.\n */\nexport function extractAllowlists(policy: TrustPolicy): {\n allowedContracts: string[];\n allowedSchemas: string[];\n} {\n const contracts: string[] = [];\n const schemas: string[] = [];\n\n for (const chain of Object.values(policy.chains)) {\n if (chain.easContract) contracts.push(chain.easContract);\n if (chain.schemas) schemas.push(...chain.schemas);\n }\n\n return {\n allowedContracts: [...new Set(contracts)],\n allowedSchemas: [...new Set(schemas)],\n };\n}\n","/**\n * Host-side signing bridge for OMATrust widget iframes.\n *\n * Handles the postMessage protocol between a host page and an embedded\n * OMATrust widget. Validates incoming EAS signing requests against the\n * OMA3 trust policy before forwarding to the host's wallet.\n *\n * The bridge resolves the iframe element lazily by ID when messages arrive,\n * avoiding React ref timing issues with conditionally rendered iframes.\n *\n * Usage:\n * import { createSigningBridge } from \"@oma3/omatrust/widgets\";\n *\n * const bridge = await createSigningBridge({\n * iframeId: \"omatrust-widget\",\n * signTypedData: async (domain, types, message) => {\n * return await signer.signTypedData(domain, types, message);\n * },\n * });\n *\n * bridge.destroy();\n */\n\nimport {\n OMATRUST_READY,\n OMATRUST_HOST_READY,\n OMATRUST_SIGN_TYPED_DATA,\n OMATRUST_SIGNATURE,\n OMATRUST_SIGNATURE_ERROR,\n} from \"./protocol\";\nimport { fetchTrustPolicy, extractAllowlists, TRUST_POLICY_URL } from \"./trust-policy\";\n\nexport type SigningBridgeOptions = {\n /**\n * The ID of the iframe element containing the widget.\n * The bridge looks up the element by ID when messages arrive,\n * so the iframe doesn't need to exist when the bridge is created.\n */\n iframeId: string;\n\n /**\n * Callback to sign EIP-712 typed data using the host's wallet.\n * Must return the hex-encoded signature string.\n */\n signTypedData: (\n domain: Record<string, unknown>,\n types: Record<string, unknown>,\n message: Record<string, unknown>\n ) => Promise<string>;\n\n /**\n * Override the allowed widget origin for local development.\n * In production, the origin is derived from the trust policy domain\n * (*.omatrust.org) plus any widgetOrigins in the policy.\n * Only set this for local dev (e.g., \"http://localhost:3000\").\n */\n devOriginOverride?: string;\n};\n\nexport type SigningBridge = {\n /** Remove all event listeners and stop the bridge. */\n destroy: () => void;\n};\n\n// ---------------------------------------------------------------------------\n// Origin resolution\n// ---------------------------------------------------------------------------\n\nfunction getTrustedBaseDomain(): string {\n try {\n const hostname = new URL(TRUST_POLICY_URL).hostname;\n const parts = hostname.split(\".\");\n return parts.length >= 2 ? parts.slice(-2).join(\".\") : hostname;\n } catch {\n return \"omatrust.org\";\n }\n}\n\nfunction isOriginTrusted(\n messageOrigin: string,\n baseDomain: string,\n policyOrigins: string[],\n devOverride?: string\n): boolean {\n if (devOverride && messageOrigin === devOverride) return true;\n\n try {\n const hostname = new URL(messageOrigin).hostname;\n if (hostname === baseDomain || hostname.endsWith(`.${baseDomain}`)) return true;\n } catch {\n // Invalid origin\n }\n\n if (policyOrigins.includes(messageOrigin)) return true;\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// EAS request validation\n// ---------------------------------------------------------------------------\n\nconst HEX_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;\nconst BYTES32_RE = /^0x[a-fA-F0-9]{64}$/;\n\ntype ValidationResult =\n | { valid: true }\n | { valid: false; reason: string };\n\nfunction validateEasSigningRequest(\n data: Record<string, unknown>,\n allowedSchemas: string[],\n allowedContracts: string[]\n): ValidationResult {\n const { id, domain, types, message } = data;\n\n if (!id || typeof id !== \"string\") {\n return { valid: false, reason: \"Missing or invalid request id\" };\n }\n if (!domain || typeof domain !== \"object\") {\n return { valid: false, reason: \"Missing domain object\" };\n }\n\n const d = domain as Record<string, unknown>;\n\n if (d.name !== \"EAS\") {\n return { valid: false, reason: `Unexpected domain name: \"${d.name}\" (expected \"EAS\")` };\n }\n if (d.version !== \"1.4.0\") {\n return { valid: false, reason: `Unexpected domain version: \"${d.version}\" (expected \"1.4.0\")` };\n }\n const chainId = Number(d.chainId);\n if (!Number.isInteger(chainId) || chainId <= 0) {\n return { valid: false, reason: `Invalid domain chainId: ${d.chainId}` };\n }\n if (typeof d.verifyingContract !== \"string\" || !HEX_ADDRESS_RE.test(d.verifyingContract)) {\n return { valid: false, reason: `Invalid verifyingContract: ${d.verifyingContract}` };\n }\n\n const contractLower = (d.verifyingContract as string).toLowerCase();\n if (!allowedContracts.some(c => c.toLowerCase() === contractLower)) {\n return { valid: false, reason: `Contract ${d.verifyingContract} is not in the OMA3 trust policy` };\n }\n\n if (!types || typeof types !== \"object\") {\n return { valid: false, reason: \"Missing types object\" };\n }\n if (!message || typeof message !== \"object\") {\n return { valid: false, reason: \"Missing message object\" };\n }\n\n const m = message as Record<string, unknown>;\n\n if (typeof m.schema !== \"string\" || !BYTES32_RE.test(m.schema)) {\n return { valid: false, reason: `Invalid schema UID: ${m.schema}` };\n }\n\n const schemaLower = m.schema.toLowerCase();\n if (!allowedSchemas.some(s => s.toLowerCase() === schemaLower)) {\n return { valid: false, reason: `Schema ${m.schema} is not in the OMA3 trust policy` };\n }\n\n if (typeof m.attester !== \"string\" || !HEX_ADDRESS_RE.test(m.attester)) {\n return { valid: false, reason: `Invalid attester address: ${m.attester}` };\n }\n\n const deadline = Number(m.deadline);\n if (!Number.isFinite(deadline) || deadline <= 0) {\n return { valid: false, reason: `Invalid deadline: ${m.deadline}` };\n }\n const now = Math.floor(Date.now() / 1000);\n if (deadline <= now) {\n return { valid: false, reason: `Deadline has passed: ${deadline} <= ${now}` };\n }\n\n return { valid: true };\n}\n\n// ---------------------------------------------------------------------------\n// Bridge implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Create a signing bridge between the host page and an OMATrust widget iframe.\n *\n * The bridge resolves the iframe element by ID when messages arrive, not at\n * creation time. This avoids React ref timing issues — the bridge can be\n * created before the iframe is in the DOM.\n *\n * Fetches the OMA3 trust policy on creation. Fails closed if unavailable.\n */\nexport async function createSigningBridge(options: SigningBridgeOptions): Promise<SigningBridge> {\n const { iframeId, signTypedData, devOriginOverride } = options;\n\n // Fetch the trust policy — fail closed if unavailable\n const policy = await fetchTrustPolicy();\n const { allowedContracts, allowedSchemas } = extractAllowlists(policy);\n\n if (allowedContracts.length === 0 || allowedSchemas.length === 0) {\n throw new Error(\"Trust policy contains no allowed contracts or schemas\");\n }\n\n const baseDomain = getTrustedBaseDomain();\n const policyOrigins = policy.widgetOrigins ?? [];\n\n async function handleMessage(event: MessageEvent) {\n const data = event.data;\n if (!data || typeof data !== \"object\" || typeof data.type !== \"string\") return;\n if (!String(data.type).startsWith(\"omatrust:\")) return;\n\n // Origin check\n if (!isOriginTrusted(event.origin, baseDomain, policyOrigins, devOriginOverride)) {\n return;\n }\n\n // Resolve the iframe element lazily by ID.\n // This works even if the iframe was mounted after the bridge was created.\n const iframe = document.getElementById(iframeId) as HTMLIFrameElement | null;\n if (!iframe) return;\n\n // Source check — must come from this specific iframe\n if (event.source !== iframe.contentWindow) {\n return;\n }\n\n const source = event.source as WindowProxy;\n\n // Determine reply origin from the iframe's current src\n const replyOrigin = devOriginOverride ?? (() => {\n try { return new URL(iframe.src).origin; }\n catch { return \"*\"; }\n })();\n\n function reply(msg: Record<string, unknown>) {\n source.postMessage(msg, replyOrigin);\n }\n\n // Handshake\n if (data.type === OMATRUST_READY) {\n reply({ type: OMATRUST_HOST_READY });\n return;\n }\n\n // Signing request\n if (data.type === OMATRUST_SIGN_TYPED_DATA) {\n const { id, domain, types, message } = data;\n\n const validation = validateEasSigningRequest(data, allowedSchemas, allowedContracts);\n if (!validation.valid) {\n reply({\n type: OMATRUST_SIGNATURE_ERROR,\n id: id ?? \"unknown\",\n error: `Signing request rejected: ${validation.reason}`,\n });\n return;\n }\n\n try {\n const signature = await signTypedData(domain, types, message);\n reply({ type: OMATRUST_SIGNATURE, id, signature });\n } catch (err) {\n const error = err instanceof Error ? err.message : \"Signing failed\";\n reply({ type: OMATRUST_SIGNATURE_ERROR, id, error });\n }\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n\n return {\n destroy() {\n window.removeEventListener(\"message\", handleMessage);\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/widgets/protocol.ts","../../src/shared/errors.ts","../../src/shared/trust-anchors.ts","../../src/widgets/bridge.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * postMessage protocol constants and types for the OMATrust widget bridge.\n *\n * Widget (iframe) → Host:\n * omatrust:ready — widget loaded, requesting handshake\n * omatrust:signTypedData — widget requests EIP-712 signature\n *\n * Host → Widget (iframe):\n * omatrust:hostReady — host acknowledges the widget\n * omatrust:signature — host returns a signature\n * omatrust:signatureError — host reports a signing failure\n */\n\nexport const OMATRUST_READY = \"omatrust:ready\" as const;\nexport const OMATRUST_HOST_READY = \"omatrust:hostReady\" as const;\nexport const OMATRUST_SIGN_TYPED_DATA = \"omatrust:signTypedData\" as const;\nexport const OMATRUST_SIGNATURE = \"omatrust:signature\" as const;\nexport const OMATRUST_SIGNATURE_ERROR = \"omatrust:signatureError\" as const;\n\nexport type OmaTrustReadyMessage = {\n type: typeof OMATRUST_READY;\n};\n\nexport type OmaTrustHostReadyMessage = {\n type: typeof OMATRUST_HOST_READY;\n};\n\nexport type OmaTrustSignTypedDataMessage = {\n type: typeof OMATRUST_SIGN_TYPED_DATA;\n id: string;\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n message: Record<string, unknown>;\n};\n\nexport type OmaTrustSignatureMessage = {\n type: typeof OMATRUST_SIGNATURE;\n id: string;\n signature: string;\n};\n\nexport type OmaTrustSignatureErrorMessage = {\n type: typeof OMATRUST_SIGNATURE_ERROR;\n id: string;\n error: string;\n};\n\nexport type OmaTrustMessage =\n | OmaTrustReadyMessage\n | OmaTrustHostReadyMessage\n | OmaTrustSignTypedDataMessage\n | OmaTrustSignatureMessage\n | OmaTrustSignatureErrorMessage;\n","export class OmaTrustError extends Error {\n code: string;\n details?: unknown;\n\n constructor(code: string, message: string, details?: unknown) {\n super(message);\n this.name = \"OmaTrustError\";\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toOmaTrustError(\n code: string,\n message: string,\n details?: unknown\n): OmaTrustError {\n return new OmaTrustError(code, message, details);\n}\n","/**\n * Trust anchors: fetches the OMA3 allowlist of EAS contracts and schemas.\n *\n * Used by the widget signing bridge for request validation and by the\n * reputation module for chain/contract resolution.\n *\n * Chain keys use CAIP-2 identifiers (e.g., \"eip155:66238\").\n */\n\nimport { OmaTrustError } from \"./errors\";\n\nconst DEFAULT_TRUST_ANCHORS_URL = \"https://api.omatrust.org/v1/trust-anchors\";\n\nexport const TRUST_ANCHORS_URL = DEFAULT_TRUST_ANCHORS_URL;\n\nexport type ChainAnchors = {\n name: string;\n easContract: string;\n /** Schema name → schema UID mapping */\n schemas: Record<string, string>;\n};\n\nexport type ApprovedIssuer = {\n address: string;\n label: string;\n schemas: string[];\n status: \"active\" | \"revoked\";\n validFrom: string;\n revokedAt?: string;\n};\n\nexport type TrustAnchors = {\n version: number;\n updatedAt: string;\n widgetOrigins?: string[];\n /** CAIP-2 chain identifier → chain-specific trust anchors */\n chains: Record<string, ChainAnchors>;\n registries?: Array<{\n type: \"approved-issuers\";\n issuers: ApprovedIssuer[];\n }>;\n};\n\nlet cachedAnchors: TrustAnchors | null = null;\nlet cacheTimestamp = 0;\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Fetch the trust anchors from the OMA3 API gateway.\n * Caches the result for 5 minutes.\n *\n * @param url Override the trust anchors URL (for testing or custom deployments)\n */\nexport async function fetchTrustAnchors(url?: string): Promise<TrustAnchors> {\n const now = Date.now();\n if (cachedAnchors && now - cacheTimestamp < CACHE_TTL_MS) {\n return cachedAnchors;\n }\n\n let res: Response;\n try {\n res = await fetch(url ?? TRUST_ANCHORS_URL);\n } catch (err) {\n throw new OmaTrustError(\"NETWORK_ERROR\", \"Failed to fetch trust anchors\", { err });\n }\n\n if (!res.ok) {\n throw new OmaTrustError(\"NETWORK_ERROR\", `Failed to fetch trust anchors: ${res.status} ${res.statusText}`);\n }\n\n const anchors: TrustAnchors = await res.json();\n\n if (!anchors.version || !anchors.chains || typeof anchors.chains !== \"object\") {\n throw new OmaTrustError(\"INVALID_INPUT\", \"Invalid trust anchors format\");\n }\n\n cachedAnchors = anchors;\n cacheTimestamp = now;\n return anchors;\n}\n\n/**\n * Look up chain anchors by CAIP-2 identifier.\n * Throws UNSUPPORTED_CHAIN if the chain is not in the trust anchors.\n */\nexport function getChainAnchors(anchors: TrustAnchors, caip2: string): ChainAnchors {\n const chain = anchors.chains[caip2];\n if (!chain) {\n throw new OmaTrustError(\"UNSUPPORTED_CHAIN\", `Chain ${caip2} is not in the trust anchors`, {\n caip2,\n supportedChains: Object.keys(anchors.chains),\n });\n }\n return chain;\n}\n\n/**\n * Look up a schema UID by name for a given chain.\n * Throws UNSUPPORTED_CHAIN if the chain is not in the trust anchors.\n * Throws INVALID_INPUT if the schema is not deployed on this chain.\n */\nexport function getSchemaAnchor(anchors: TrustAnchors, caip2: string, schemaName: string): string {\n const chain = getChainAnchors(anchors, caip2);\n const uid = chain.schemas[schemaName];\n if (!uid) {\n throw new OmaTrustError(\"INVALID_INPUT\", `Schema \"${schemaName}\" not found in trust anchors for chain ${caip2}`, {\n caip2,\n schemaName,\n availableSchemas: Object.keys(chain.schemas),\n });\n }\n return uid;\n}\n\n/**\n * Extract the allowed contracts and schema UIDs from trust anchors.\n * Returns all contracts and schema UIDs across all chains.\n */\nexport function extractAllowlists(anchors: TrustAnchors): {\n allowedContracts: string[];\n allowedSchemas: string[];\n} {\n const contracts: string[] = [];\n const schemas: string[] = [];\n\n for (const chain of Object.values(anchors.chains)) {\n if (chain.easContract) contracts.push(chain.easContract);\n if (chain.schemas && typeof chain.schemas === \"object\") {\n schemas.push(...Object.values(chain.schemas));\n }\n }\n\n return {\n allowedContracts: [...new Set(contracts)],\n allowedSchemas: [...new Set(schemas)],\n };\n}\n","/**\n * Host-side signing bridge for OMATrust widget iframes.\n *\n * Handles the postMessage protocol between a host page and an embedded\n * OMATrust widget. Validates incoming EAS signing requests against the\n * OMA3 trust anchors before forwarding to the host's wallet.\n *\n * The bridge resolves the iframe element lazily by ID when messages arrive,\n * avoiding React ref timing issues with conditionally rendered iframes.\n *\n * Usage:\n * import { createSigningBridge } from \"@oma3/omatrust/widgets\";\n *\n * const bridge = await createSigningBridge({\n * iframeId: \"omatrust-widget\",\n * signTypedData: async (domain, types, message) => {\n * return await signer.signTypedData(domain, types, message);\n * },\n * });\n *\n * bridge.destroy();\n */\n\nimport {\n OMATRUST_READY,\n OMATRUST_HOST_READY,\n OMATRUST_SIGN_TYPED_DATA,\n OMATRUST_SIGNATURE,\n OMATRUST_SIGNATURE_ERROR,\n} from \"./protocol\";\nimport { fetchTrustAnchors, extractAllowlists, TRUST_ANCHORS_URL } from \"../shared/trust-anchors\";\n\nexport type SigningBridgeOptions = {\n /**\n * The ID of the iframe element containing the widget.\n * The bridge looks up the element by ID when messages arrive,\n * so the iframe doesn't need to exist when the bridge is created.\n */\n iframeId: string;\n\n /**\n * Callback to sign EIP-712 typed data using the host's wallet.\n * Must return the hex-encoded signature string.\n */\n signTypedData: (\n domain: Record<string, unknown>,\n types: Record<string, unknown>,\n message: Record<string, unknown>\n ) => Promise<string>;\n\n /**\n * Override the allowed widget origin for local development.\n * In production, the origin is derived from the trust anchors domain\n * (*.omatrust.org) plus any widgetOrigins in the trust anchors.\n * Only set this for local dev (e.g., \"http://localhost:3000\").\n */\n devOriginOverride?: string;\n};\n\nexport type SigningBridge = {\n /** Remove all event listeners and stop the bridge. */\n destroy: () => void;\n};\n\n// ---------------------------------------------------------------------------\n// Origin resolution\n// ---------------------------------------------------------------------------\n\nfunction getTrustedBaseDomain(): string {\n try {\n const hostname = new URL(TRUST_ANCHORS_URL).hostname;\n const parts = hostname.split(\".\");\n return parts.length >= 2 ? parts.slice(-2).join(\".\") : hostname;\n } catch {\n return \"omatrust.org\";\n }\n}\n\nfunction isOriginTrusted(\n messageOrigin: string,\n baseDomain: string,\n policyOrigins: string[],\n devOverride?: string\n): boolean {\n if (devOverride && messageOrigin === devOverride) return true;\n\n try {\n const hostname = new URL(messageOrigin).hostname;\n if (hostname === baseDomain || hostname.endsWith(`.${baseDomain}`)) return true;\n } catch {\n // Invalid origin\n }\n\n if (policyOrigins.includes(messageOrigin)) return true;\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// EAS request validation\n// ---------------------------------------------------------------------------\n\nconst HEX_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;\nconst BYTES32_RE = /^0x[a-fA-F0-9]{64}$/;\n\ntype ValidationResult =\n | { valid: true }\n | { valid: false; reason: string };\n\nfunction validateEasSigningRequest(\n data: Record<string, unknown>,\n allowedSchemas: string[],\n allowedContracts: string[]\n): ValidationResult {\n const { id, domain, types, message } = data;\n\n if (!id || typeof id !== \"string\") {\n return { valid: false, reason: \"Missing or invalid request id\" };\n }\n if (!domain || typeof domain !== \"object\") {\n return { valid: false, reason: \"Missing domain object\" };\n }\n\n const d = domain as Record<string, unknown>;\n\n if (d.name !== \"EAS\") {\n return { valid: false, reason: `Unexpected domain name: \"${d.name}\" (expected \"EAS\")` };\n }\n if (d.version !== \"1.4.0\") {\n return { valid: false, reason: `Unexpected domain version: \"${d.version}\" (expected \"1.4.0\")` };\n }\n const chainId = Number(d.chainId);\n if (!Number.isInteger(chainId) || chainId <= 0) {\n return { valid: false, reason: `Invalid domain chainId: ${d.chainId}` };\n }\n if (typeof d.verifyingContract !== \"string\" || !HEX_ADDRESS_RE.test(d.verifyingContract)) {\n return { valid: false, reason: `Invalid verifyingContract: ${d.verifyingContract}` };\n }\n\n const contractLower = (d.verifyingContract as string).toLowerCase();\n if (!allowedContracts.some(c => c.toLowerCase() === contractLower)) {\n return { valid: false, reason: `Contract ${d.verifyingContract} is not in the OMA3 trust anchors` };\n }\n\n if (!types || typeof types !== \"object\") {\n return { valid: false, reason: \"Missing types object\" };\n }\n if (!message || typeof message !== \"object\") {\n return { valid: false, reason: \"Missing message object\" };\n }\n\n const m = message as Record<string, unknown>;\n\n if (typeof m.schema !== \"string\" || !BYTES32_RE.test(m.schema)) {\n return { valid: false, reason: `Invalid schema UID: ${m.schema}` };\n }\n\n const schemaLower = m.schema.toLowerCase();\n if (!allowedSchemas.some(s => s.toLowerCase() === schemaLower)) {\n return { valid: false, reason: `Schema ${m.schema} is not in the OMA3 trust anchors` };\n }\n\n if (typeof m.attester !== \"string\" || !HEX_ADDRESS_RE.test(m.attester)) {\n return { valid: false, reason: `Invalid attester address: ${m.attester}` };\n }\n\n const deadline = Number(m.deadline);\n if (!Number.isFinite(deadline) || deadline <= 0) {\n return { valid: false, reason: `Invalid deadline: ${m.deadline}` };\n }\n const now = Math.floor(Date.now() / 1000);\n if (deadline <= now) {\n return { valid: false, reason: `Deadline has passed: ${deadline} <= ${now}` };\n }\n\n return { valid: true };\n}\n\n// ---------------------------------------------------------------------------\n// Bridge implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Create a signing bridge between the host page and an OMATrust widget iframe.\n *\n * The bridge resolves the iframe element by ID when messages arrive, not at\n * creation time. This avoids React ref timing issues — the bridge can be\n * created before the iframe is in the DOM.\n *\n * Fetches the OMA3 trust anchors on creation. Fails closed if unavailable.\n */\nexport async function createSigningBridge(options: SigningBridgeOptions): Promise<SigningBridge> {\n const { iframeId, signTypedData, devOriginOverride } = options;\n\n // Fetch the trust anchors: fail closed if unavailable.\n const anchors = await fetchTrustAnchors();\n const { allowedContracts, allowedSchemas } = extractAllowlists(anchors);\n\n if (allowedContracts.length === 0 || allowedSchemas.length === 0) {\n throw new Error(\"Trust anchors contain no allowed contracts or schemas\");\n }\n\n const baseDomain = getTrustedBaseDomain();\n const anchorOrigins = anchors.widgetOrigins ?? [];\n\n async function handleMessage(event: MessageEvent) {\n const data = event.data;\n if (!data || typeof data !== \"object\" || typeof data.type !== \"string\") return;\n if (!String(data.type).startsWith(\"omatrust:\")) return;\n\n // Origin check\n if (!isOriginTrusted(event.origin, baseDomain, anchorOrigins, devOriginOverride)) {\n return;\n }\n\n // Resolve the iframe element lazily by ID.\n // This works even if the iframe was mounted after the bridge was created.\n const iframe = document.getElementById(iframeId) as HTMLIFrameElement | null;\n if (!iframe) return;\n\n // Source check — must come from this specific iframe\n if (event.source !== iframe.contentWindow) {\n return;\n }\n\n const source = event.source as WindowProxy;\n\n // Determine reply origin from the iframe's current src\n const replyOrigin = devOriginOverride ?? (() => {\n try { return new URL(iframe.src).origin; }\n catch { return \"*\"; }\n })();\n\n function reply(msg: Record<string, unknown>) {\n source.postMessage(msg, replyOrigin);\n }\n\n // Handshake\n if (data.type === OMATRUST_READY) {\n reply({ type: OMATRUST_HOST_READY });\n return;\n }\n\n // Signing request\n if (data.type === OMATRUST_SIGN_TYPED_DATA) {\n const { id, domain, types, message } = data;\n\n const validation = validateEasSigningRequest(data, allowedSchemas, allowedContracts);\n if (!validation.valid) {\n reply({\n type: OMATRUST_SIGNATURE_ERROR,\n id: id ?? \"unknown\",\n error: `Signing request rejected: ${validation.reason}`,\n });\n return;\n }\n\n try {\n const signature = await signTypedData(domain, types, message);\n reply({ type: OMATRUST_SIGNATURE, id, signature });\n } catch (err) {\n const error = err instanceof Error ? err.message : \"Signing failed\";\n reply({ type: OMATRUST_SIGNATURE_ERROR, id, error });\n }\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n\n return {\n destroy() {\n window.removeEventListener(\"message\", handleMessage);\n },\n };\n}\n"]}