@oma3/omatrust 0.1.0-alpha.7 → 0.1.0-alpha.8

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.
@@ -0,0 +1,207 @@
1
+ 'use strict';
2
+
3
+ // src/widgets/protocol.ts
4
+ var OMATRUST_READY = "omatrust:ready";
5
+ var OMATRUST_HOST_READY = "omatrust:hostReady";
6
+ var OMATRUST_SIGN_TYPED_DATA = "omatrust:signTypedData";
7
+ var OMATRUST_SIGNATURE = "omatrust:signature";
8
+ var OMATRUST_SIGNATURE_ERROR = "omatrust:signatureError";
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;
14
+ var cacheTimestamp = 0;
15
+ var CACHE_TTL_MS = 5 * 60 * 1e3;
16
+ async function fetchTrustPolicy(url) {
17
+ const now = Date.now();
18
+ if (cachedPolicy && now - cacheTimestamp < CACHE_TTL_MS) {
19
+ return cachedPolicy;
20
+ }
21
+ const res = await fetch(url ?? TRUST_POLICY_URL);
22
+ if (!res.ok) {
23
+ throw new Error(`Failed to fetch trust policy: ${res.status} ${res.statusText}`);
24
+ }
25
+ const policy = await res.json();
26
+ if (!policy.version || !policy.chains || typeof policy.chains !== "object") {
27
+ throw new Error("Invalid trust policy format");
28
+ }
29
+ cachedPolicy = policy;
30
+ cacheTimestamp = now;
31
+ return policy;
32
+ }
33
+ function extractAllowlists(policy) {
34
+ const contracts = [];
35
+ const schemas = [];
36
+ for (const chain of Object.values(policy.chains)) {
37
+ if (chain.easContract) contracts.push(chain.easContract);
38
+ if (chain.schemas) schemas.push(...chain.schemas);
39
+ }
40
+ return {
41
+ allowedContracts: [...new Set(contracts)],
42
+ allowedSchemas: [...new Set(schemas)]
43
+ };
44
+ }
45
+
46
+ // src/widgets/bridge.ts
47
+ function getTrustedBaseDomain() {
48
+ try {
49
+ const hostname = new URL(TRUST_POLICY_URL).hostname;
50
+ const parts = hostname.split(".");
51
+ return parts.length >= 2 ? parts.slice(-2).join(".") : hostname;
52
+ } catch {
53
+ return "omatrust.org";
54
+ }
55
+ }
56
+ function isOriginTrusted(messageOrigin, baseDomain, policyOrigins, devOverride) {
57
+ if (devOverride && messageOrigin === devOverride) return true;
58
+ try {
59
+ const hostname = new URL(messageOrigin).hostname;
60
+ if (hostname === baseDomain || hostname.endsWith(`.${baseDomain}`)) return true;
61
+ } catch {
62
+ }
63
+ if (policyOrigins.includes(messageOrigin)) return true;
64
+ return false;
65
+ }
66
+ var HEX_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
67
+ var BYTES32_RE = /^0x[a-fA-F0-9]{64}$/;
68
+ function validateEasSigningRequest(data, allowedSchemas, allowedContracts) {
69
+ const { id, domain, types, message } = data;
70
+ if (!id || typeof id !== "string") {
71
+ return { valid: false, reason: "Missing or invalid request id" };
72
+ }
73
+ if (!domain || typeof domain !== "object") {
74
+ return { valid: false, reason: "Missing domain object" };
75
+ }
76
+ const d = domain;
77
+ if (d.name !== "EAS") {
78
+ return { valid: false, reason: `Unexpected domain name: "${d.name}" (expected "EAS")` };
79
+ }
80
+ if (d.version !== "1.4.0") {
81
+ return { valid: false, reason: `Unexpected domain version: "${d.version}" (expected "1.4.0")` };
82
+ }
83
+ const chainId = Number(d.chainId);
84
+ if (!Number.isInteger(chainId) || chainId <= 0) {
85
+ return { valid: false, reason: `Invalid domain chainId: ${d.chainId}` };
86
+ }
87
+ if (typeof d.verifyingContract !== "string" || !HEX_ADDRESS_RE.test(d.verifyingContract)) {
88
+ return { valid: false, reason: `Invalid verifyingContract: ${d.verifyingContract}` };
89
+ }
90
+ const contractLower = d.verifyingContract.toLowerCase();
91
+ if (!allowedContracts.some((c) => c.toLowerCase() === contractLower)) {
92
+ return { valid: false, reason: `Contract ${d.verifyingContract} is not in the OMA3 trust policy` };
93
+ }
94
+ if (!types || typeof types !== "object") {
95
+ return { valid: false, reason: "Missing types object" };
96
+ }
97
+ if (!message || typeof message !== "object") {
98
+ return { valid: false, reason: "Missing message object" };
99
+ }
100
+ const m = message;
101
+ if (typeof m.schema !== "string" || !BYTES32_RE.test(m.schema)) {
102
+ return { valid: false, reason: `Invalid schema UID: ${m.schema}` };
103
+ }
104
+ const schemaLower = m.schema.toLowerCase();
105
+ if (!allowedSchemas.some((s) => s.toLowerCase() === schemaLower)) {
106
+ return { valid: false, reason: `Schema ${m.schema} is not in the OMA3 trust policy` };
107
+ }
108
+ if (typeof m.attester !== "string" || !HEX_ADDRESS_RE.test(m.attester)) {
109
+ return { valid: false, reason: `Invalid attester address: ${m.attester}` };
110
+ }
111
+ const deadline = Number(m.deadline);
112
+ if (!Number.isFinite(deadline) || deadline <= 0) {
113
+ return { valid: false, reason: `Invalid deadline: ${m.deadline}` };
114
+ }
115
+ const now = Math.floor(Date.now() / 1e3);
116
+ if (deadline <= now) {
117
+ return { valid: false, reason: `Deadline has passed: ${deadline} <= ${now}` };
118
+ }
119
+ return { valid: true };
120
+ }
121
+ async function createSigningBridge(options) {
122
+ const { iframe, signTypedData, devOriginOverride } = options;
123
+ const debug = typeof window !== "undefined" && window.__OMATRUST_DEBUG === true;
124
+ if (debug) console.log("[omatrust-bridge] fetching trust policy...");
125
+ const policy = await fetchTrustPolicy();
126
+ const { allowedContracts, allowedSchemas } = extractAllowlists(policy);
127
+ if (allowedContracts.length === 0 || allowedSchemas.length === 0) {
128
+ throw new Error("Trust policy contains no allowed contracts or schemas");
129
+ }
130
+ const baseDomain = getTrustedBaseDomain();
131
+ const policyOrigins = policy.widgetOrigins ?? [];
132
+ if (debug) {
133
+ console.log("[omatrust-bridge] trust policy loaded:", {
134
+ contracts: allowedContracts.length,
135
+ schemas: allowedSchemas.length,
136
+ baseDomain,
137
+ policyOrigins,
138
+ devOriginOverride
139
+ });
140
+ }
141
+ const replyOrigin = devOriginOverride ?? (() => {
142
+ try {
143
+ return new URL(iframe.src).origin;
144
+ } catch {
145
+ return "*";
146
+ }
147
+ })();
148
+ async function handleMessage(event) {
149
+ const data = event.data;
150
+ if (!data || typeof data !== "object" || typeof data.type !== "string") return;
151
+ if (!String(data.type).startsWith("omatrust:")) return;
152
+ if (debug) console.log("[omatrust-bridge] message:", data.type, "origin:", event.origin);
153
+ if (!isOriginTrusted(event.origin, baseDomain, policyOrigins, devOriginOverride)) {
154
+ if (debug) console.log("[omatrust-bridge] rejected: untrusted origin", event.origin);
155
+ return;
156
+ }
157
+ if (event.source !== iframe.contentWindow) {
158
+ if (debug) console.log("[omatrust-bridge] rejected: source !== iframe.contentWindow");
159
+ return;
160
+ }
161
+ const source = event.source;
162
+ function reply(msg) {
163
+ source.postMessage(msg, replyOrigin);
164
+ }
165
+ if (data.type === OMATRUST_READY) {
166
+ reply({ type: OMATRUST_HOST_READY });
167
+ return;
168
+ }
169
+ if (data.type === OMATRUST_SIGN_TYPED_DATA) {
170
+ const { id, domain, types, message } = data;
171
+ const validation = validateEasSigningRequest(data, allowedSchemas, allowedContracts);
172
+ if (!validation.valid) {
173
+ reply({
174
+ type: OMATRUST_SIGNATURE_ERROR,
175
+ id: id ?? "unknown",
176
+ error: `Signing request rejected: ${validation.reason}`
177
+ });
178
+ return;
179
+ }
180
+ try {
181
+ const signature = await signTypedData(domain, types, message);
182
+ reply({ type: OMATRUST_SIGNATURE, id, signature });
183
+ } catch (err) {
184
+ const error = err instanceof Error ? err.message : "Signing failed";
185
+ reply({ type: OMATRUST_SIGNATURE_ERROR, id, error });
186
+ }
187
+ }
188
+ }
189
+ window.addEventListener("message", handleMessage);
190
+ return {
191
+ destroy() {
192
+ window.removeEventListener("message", handleMessage);
193
+ }
194
+ };
195
+ }
196
+
197
+ exports.OMATRUST_HOST_READY = OMATRUST_HOST_READY;
198
+ exports.OMATRUST_READY = OMATRUST_READY;
199
+ exports.OMATRUST_SIGNATURE = OMATRUST_SIGNATURE;
200
+ exports.OMATRUST_SIGNATURE_ERROR = OMATRUST_SIGNATURE_ERROR;
201
+ exports.OMATRUST_SIGN_TYPED_DATA = OMATRUST_SIGN_TYPED_DATA;
202
+ exports.TRUST_POLICY_URL = TRUST_POLICY_URL;
203
+ exports.createSigningBridge = createSigningBridge;
204
+ exports.extractAllowlists = extractAllowlists;
205
+ exports.fetchTrustPolicy = fetchTrustPolicy;
206
+ //# sourceMappingURL=index.cjs.map
207
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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 * Security model:\n * - Trust policy: fetched from api.omatrust.org on bridge creation.\n * Only contracts and schemas in the policy are accepted for signing.\n * - Origin check: derived from the trust policy domain (*.omatrust.org)\n * plus any additional origins listed in the policy's widgetOrigins field.\n * - Source check: messages must come from the specific iframe's contentWindow\n * - EAS validation: domain, schema, attester, deadline are all checked\n *\n * Usage:\n * import { createSigningBridge } from \"@oma3/omatrust/widgets\";\n *\n * const bridge = await createSigningBridge({\n * iframe: document.getElementById(\"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 /** The iframe element containing the widget. */\n iframe: HTMLIFrameElement;\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\n/**\n * Derive the trusted base domain from the trust policy URL.\n * e.g., \"https://api.omatrust.org/v1/trust-policy\" → \"omatrust.org\"\n */\nfunction getTrustedBaseDomain(): string {\n try {\n const hostname = new URL(TRUST_POLICY_URL).hostname;\n // Extract the registrable domain (last two parts)\n const parts = hostname.split(\".\");\n return parts.length >= 2 ? parts.slice(-2).join(\".\") : hostname;\n } catch {\n return \"omatrust.org\";\n }\n}\n\n/**\n * Check if a message origin is trusted.\n *\n * @param messageOrigin - The origin from event.origin (set by the browser)\n * @param baseDomain - The registrable domain of the trust policy (e.g., \"omatrust.org\")\n * @param policyOrigins - Additional origins from the trust policy's widgetOrigins field\n * @param devOverride - Optional dev-only origin (e.g., \"http://localhost:3000\")\n */\nfunction isOriginTrusted(\n messageOrigin: string,\n baseDomain: string,\n policyOrigins: string[],\n devOverride?: string\n): boolean {\n // 1. Dev override — allows localhost during development\n if (devOverride && messageOrigin === devOverride) return true;\n\n // 2. Subdomain of the trust policy domain (e.g., *.omatrust.org)\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 // 3. Explicitly listed in the trust policy\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 * Fetches the OMA3 trust policy on creation to determine which contracts,\n * schemas, and origins are allowed. The bridge will not start if the trust\n * policy cannot be fetched (fail closed).\n */\nexport async function createSigningBridge(options: SigningBridgeOptions): Promise<SigningBridge> {\n const { iframe, signTypedData, devOriginOverride } = options;\n\n const debug = typeof window !== \"undefined\" && (window as unknown as Record<string, unknown>).__OMATRUST_DEBUG === true;\n\n // Fetch the trust policy — fail closed if unavailable\n if (debug) console.log(\"[omatrust-bridge] fetching trust policy...\");\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 // Resolve trusted origins\n const baseDomain = getTrustedBaseDomain();\n const policyOrigins = policy.widgetOrigins ?? [];\n\n if (debug) {\n console.log(\"[omatrust-bridge] trust policy loaded:\", {\n contracts: allowedContracts.length,\n schemas: allowedSchemas.length,\n baseDomain,\n policyOrigins,\n devOriginOverride,\n });\n }\n\n // Determine the target origin for replies\n const replyOrigin = devOriginOverride ?? (() => {\n try {\n return new URL(iframe.src).origin;\n } catch {\n return \"*\";\n }\n })();\n\n async function handleMessage(event: MessageEvent) {\n // Only look at omatrust messages\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 if (debug) console.log(\"[omatrust-bridge] message:\", data.type, \"origin:\", event.origin);\n\n // Origin check — must be a trusted origin\n if (!isOriginTrusted(event.origin, baseDomain, policyOrigins, devOriginOverride)) {\n if (debug) console.log(\"[omatrust-bridge] rejected: untrusted origin\", event.origin);\n return;\n }\n\n // Source check — must come from the specific iframe's contentWindow\n if (event.source !== iframe.contentWindow) {\n if (debug) console.log(\"[omatrust-bridge] rejected: source !== iframe.contentWindow\");\n return;\n }\n\n const source = event.source as WindowProxy;\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"]}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Host-side signing bridge for OMATrust widget iframes.
3
+ *
4
+ * Handles the postMessage protocol between a host page and an embedded
5
+ * OMATrust widget. Validates incoming EAS signing requests against the
6
+ * OMA3 trust policy before forwarding to the host's wallet.
7
+ *
8
+ * Security model:
9
+ * - Trust policy: fetched from api.omatrust.org on bridge creation.
10
+ * Only contracts and schemas in the policy are accepted for signing.
11
+ * - Origin check: derived from the trust policy domain (*.omatrust.org)
12
+ * plus any additional origins listed in the policy's widgetOrigins field.
13
+ * - Source check: messages must come from the specific iframe's contentWindow
14
+ * - EAS validation: domain, schema, attester, deadline are all checked
15
+ *
16
+ * Usage:
17
+ * import { createSigningBridge } from "@oma3/omatrust/widgets";
18
+ *
19
+ * const bridge = await createSigningBridge({
20
+ * iframe: document.getElementById("omatrust-widget"),
21
+ * signTypedData: async (domain, types, message) => {
22
+ * return await signer.signTypedData(domain, types, message);
23
+ * },
24
+ * });
25
+ *
26
+ * bridge.destroy();
27
+ */
28
+ type SigningBridgeOptions = {
29
+ /** The iframe element containing the widget. */
30
+ iframe: HTMLIFrameElement;
31
+ /**
32
+ * Callback to sign EIP-712 typed data using the host's wallet.
33
+ * Must return the hex-encoded signature string.
34
+ */
35
+ signTypedData: (domain: Record<string, unknown>, types: Record<string, unknown>, message: Record<string, unknown>) => Promise<string>;
36
+ /**
37
+ * Override the allowed widget origin for local development.
38
+ * In production, the origin is derived from the trust policy domain
39
+ * (*.omatrust.org) plus any widgetOrigins in the policy.
40
+ * Only set this for local dev (e.g., "http://localhost:3000").
41
+ */
42
+ devOriginOverride?: string;
43
+ };
44
+ type SigningBridge = {
45
+ /** Remove all event listeners and stop the bridge. */
46
+ destroy: () => void;
47
+ };
48
+ /**
49
+ * Create a signing bridge between the host page and an OMATrust widget iframe.
50
+ *
51
+ * Fetches the OMA3 trust policy on creation to determine which contracts,
52
+ * schemas, and origins are allowed. The bridge will not start if the trust
53
+ * policy cannot be fetched (fail closed).
54
+ */
55
+ declare function createSigningBridge(options: SigningBridgeOptions): Promise<SigningBridge>;
56
+
57
+ /**
58
+ * Trust policy: fetches the OMA3 allowlist of EAS contracts and schemas.
59
+ *
60
+ * The bridge uses this to validate signing requests automatically.
61
+ * Developers don't need to maintain their own allowlists.
62
+ */
63
+ declare const TRUST_POLICY_URL = "https://api.omatrust.org/v1/trust-policy";
64
+ type ChainPolicy = {
65
+ name: string;
66
+ easContract: string;
67
+ schemas: string[];
68
+ };
69
+ type TrustPolicy = {
70
+ version: number;
71
+ updatedAt: string;
72
+ widgetOrigins?: string[];
73
+ chains: Record<string, ChainPolicy>;
74
+ };
75
+ /**
76
+ * Fetch the trust policy from the OMA3 API gateway.
77
+ * Caches the result for 5 minutes.
78
+ *
79
+ * @param url Override the trust policy URL (for testing or custom deployments)
80
+ */
81
+ declare function fetchTrustPolicy(url?: string): Promise<TrustPolicy>;
82
+ /**
83
+ * Extract the allowed contracts and schemas from a trust policy.
84
+ * Returns all contracts and schemas across all chains.
85
+ */
86
+ declare function extractAllowlists(policy: TrustPolicy): {
87
+ allowedContracts: string[];
88
+ allowedSchemas: string[];
89
+ };
90
+
91
+ /**
92
+ * postMessage protocol constants and types for the OMATrust widget bridge.
93
+ *
94
+ * Widget (iframe) → Host:
95
+ * omatrust:ready — widget loaded, requesting handshake
96
+ * omatrust:signTypedData — widget requests EIP-712 signature
97
+ *
98
+ * Host → Widget (iframe):
99
+ * omatrust:hostReady — host acknowledges the widget
100
+ * omatrust:signature — host returns a signature
101
+ * omatrust:signatureError — host reports a signing failure
102
+ */
103
+ declare const OMATRUST_READY: "omatrust:ready";
104
+ declare const OMATRUST_HOST_READY: "omatrust:hostReady";
105
+ declare const OMATRUST_SIGN_TYPED_DATA: "omatrust:signTypedData";
106
+ declare const OMATRUST_SIGNATURE: "omatrust:signature";
107
+ declare const OMATRUST_SIGNATURE_ERROR: "omatrust:signatureError";
108
+ type OmaTrustReadyMessage = {
109
+ type: typeof OMATRUST_READY;
110
+ };
111
+ type OmaTrustHostReadyMessage = {
112
+ type: typeof OMATRUST_HOST_READY;
113
+ };
114
+ type OmaTrustSignTypedDataMessage = {
115
+ type: typeof OMATRUST_SIGN_TYPED_DATA;
116
+ id: string;
117
+ domain: Record<string, unknown>;
118
+ types: Record<string, unknown>;
119
+ message: Record<string, unknown>;
120
+ };
121
+ type OmaTrustSignatureMessage = {
122
+ type: typeof OMATRUST_SIGNATURE;
123
+ id: string;
124
+ signature: string;
125
+ };
126
+ type OmaTrustSignatureErrorMessage = {
127
+ type: typeof OMATRUST_SIGNATURE_ERROR;
128
+ id: string;
129
+ error: string;
130
+ };
131
+ type OmaTrustMessage = OmaTrustReadyMessage | OmaTrustHostReadyMessage | OmaTrustSignTypedDataMessage | OmaTrustSignatureMessage | OmaTrustSignatureErrorMessage;
132
+
133
+ export { type ChainPolicy, OMATRUST_HOST_READY, OMATRUST_READY, OMATRUST_SIGNATURE, OMATRUST_SIGNATURE_ERROR, OMATRUST_SIGN_TYPED_DATA, type OmaTrustHostReadyMessage, type OmaTrustMessage, type OmaTrustReadyMessage, type OmaTrustSignTypedDataMessage, type OmaTrustSignatureErrorMessage, type OmaTrustSignatureMessage, type SigningBridge, type SigningBridgeOptions, TRUST_POLICY_URL, type TrustPolicy, createSigningBridge, extractAllowlists, fetchTrustPolicy };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Host-side signing bridge for OMATrust widget iframes.
3
+ *
4
+ * Handles the postMessage protocol between a host page and an embedded
5
+ * OMATrust widget. Validates incoming EAS signing requests against the
6
+ * OMA3 trust policy before forwarding to the host's wallet.
7
+ *
8
+ * Security model:
9
+ * - Trust policy: fetched from api.omatrust.org on bridge creation.
10
+ * Only contracts and schemas in the policy are accepted for signing.
11
+ * - Origin check: derived from the trust policy domain (*.omatrust.org)
12
+ * plus any additional origins listed in the policy's widgetOrigins field.
13
+ * - Source check: messages must come from the specific iframe's contentWindow
14
+ * - EAS validation: domain, schema, attester, deadline are all checked
15
+ *
16
+ * Usage:
17
+ * import { createSigningBridge } from "@oma3/omatrust/widgets";
18
+ *
19
+ * const bridge = await createSigningBridge({
20
+ * iframe: document.getElementById("omatrust-widget"),
21
+ * signTypedData: async (domain, types, message) => {
22
+ * return await signer.signTypedData(domain, types, message);
23
+ * },
24
+ * });
25
+ *
26
+ * bridge.destroy();
27
+ */
28
+ type SigningBridgeOptions = {
29
+ /** The iframe element containing the widget. */
30
+ iframe: HTMLIFrameElement;
31
+ /**
32
+ * Callback to sign EIP-712 typed data using the host's wallet.
33
+ * Must return the hex-encoded signature string.
34
+ */
35
+ signTypedData: (domain: Record<string, unknown>, types: Record<string, unknown>, message: Record<string, unknown>) => Promise<string>;
36
+ /**
37
+ * Override the allowed widget origin for local development.
38
+ * In production, the origin is derived from the trust policy domain
39
+ * (*.omatrust.org) plus any widgetOrigins in the policy.
40
+ * Only set this for local dev (e.g., "http://localhost:3000").
41
+ */
42
+ devOriginOverride?: string;
43
+ };
44
+ type SigningBridge = {
45
+ /** Remove all event listeners and stop the bridge. */
46
+ destroy: () => void;
47
+ };
48
+ /**
49
+ * Create a signing bridge between the host page and an OMATrust widget iframe.
50
+ *
51
+ * Fetches the OMA3 trust policy on creation to determine which contracts,
52
+ * schemas, and origins are allowed. The bridge will not start if the trust
53
+ * policy cannot be fetched (fail closed).
54
+ */
55
+ declare function createSigningBridge(options: SigningBridgeOptions): Promise<SigningBridge>;
56
+
57
+ /**
58
+ * Trust policy: fetches the OMA3 allowlist of EAS contracts and schemas.
59
+ *
60
+ * The bridge uses this to validate signing requests automatically.
61
+ * Developers don't need to maintain their own allowlists.
62
+ */
63
+ declare const TRUST_POLICY_URL = "https://api.omatrust.org/v1/trust-policy";
64
+ type ChainPolicy = {
65
+ name: string;
66
+ easContract: string;
67
+ schemas: string[];
68
+ };
69
+ type TrustPolicy = {
70
+ version: number;
71
+ updatedAt: string;
72
+ widgetOrigins?: string[];
73
+ chains: Record<string, ChainPolicy>;
74
+ };
75
+ /**
76
+ * Fetch the trust policy from the OMA3 API gateway.
77
+ * Caches the result for 5 minutes.
78
+ *
79
+ * @param url Override the trust policy URL (for testing or custom deployments)
80
+ */
81
+ declare function fetchTrustPolicy(url?: string): Promise<TrustPolicy>;
82
+ /**
83
+ * Extract the allowed contracts and schemas from a trust policy.
84
+ * Returns all contracts and schemas across all chains.
85
+ */
86
+ declare function extractAllowlists(policy: TrustPolicy): {
87
+ allowedContracts: string[];
88
+ allowedSchemas: string[];
89
+ };
90
+
91
+ /**
92
+ * postMessage protocol constants and types for the OMATrust widget bridge.
93
+ *
94
+ * Widget (iframe) → Host:
95
+ * omatrust:ready — widget loaded, requesting handshake
96
+ * omatrust:signTypedData — widget requests EIP-712 signature
97
+ *
98
+ * Host → Widget (iframe):
99
+ * omatrust:hostReady — host acknowledges the widget
100
+ * omatrust:signature — host returns a signature
101
+ * omatrust:signatureError — host reports a signing failure
102
+ */
103
+ declare const OMATRUST_READY: "omatrust:ready";
104
+ declare const OMATRUST_HOST_READY: "omatrust:hostReady";
105
+ declare const OMATRUST_SIGN_TYPED_DATA: "omatrust:signTypedData";
106
+ declare const OMATRUST_SIGNATURE: "omatrust:signature";
107
+ declare const OMATRUST_SIGNATURE_ERROR: "omatrust:signatureError";
108
+ type OmaTrustReadyMessage = {
109
+ type: typeof OMATRUST_READY;
110
+ };
111
+ type OmaTrustHostReadyMessage = {
112
+ type: typeof OMATRUST_HOST_READY;
113
+ };
114
+ type OmaTrustSignTypedDataMessage = {
115
+ type: typeof OMATRUST_SIGN_TYPED_DATA;
116
+ id: string;
117
+ domain: Record<string, unknown>;
118
+ types: Record<string, unknown>;
119
+ message: Record<string, unknown>;
120
+ };
121
+ type OmaTrustSignatureMessage = {
122
+ type: typeof OMATRUST_SIGNATURE;
123
+ id: string;
124
+ signature: string;
125
+ };
126
+ type OmaTrustSignatureErrorMessage = {
127
+ type: typeof OMATRUST_SIGNATURE_ERROR;
128
+ id: string;
129
+ error: string;
130
+ };
131
+ type OmaTrustMessage = OmaTrustReadyMessage | OmaTrustHostReadyMessage | OmaTrustSignTypedDataMessage | OmaTrustSignatureMessage | OmaTrustSignatureErrorMessage;
132
+
133
+ export { type ChainPolicy, OMATRUST_HOST_READY, OMATRUST_READY, OMATRUST_SIGNATURE, OMATRUST_SIGNATURE_ERROR, OMATRUST_SIGN_TYPED_DATA, type OmaTrustHostReadyMessage, type OmaTrustMessage, type OmaTrustReadyMessage, type OmaTrustSignTypedDataMessage, type OmaTrustSignatureErrorMessage, type OmaTrustSignatureMessage, type SigningBridge, type SigningBridgeOptions, TRUST_POLICY_URL, type TrustPolicy, createSigningBridge, extractAllowlists, fetchTrustPolicy };
@@ -0,0 +1,197 @@
1
+ // src/widgets/protocol.ts
2
+ var OMATRUST_READY = "omatrust:ready";
3
+ var OMATRUST_HOST_READY = "omatrust:hostReady";
4
+ var OMATRUST_SIGN_TYPED_DATA = "omatrust:signTypedData";
5
+ var OMATRUST_SIGNATURE = "omatrust:signature";
6
+ var OMATRUST_SIGNATURE_ERROR = "omatrust:signatureError";
7
+
8
+ // src/widgets/trust-policy.ts
9
+ var DEFAULT_TRUST_POLICY_URL = "https://api.omatrust.org/v1/trust-policy";
10
+ var TRUST_POLICY_URL = DEFAULT_TRUST_POLICY_URL;
11
+ var cachedPolicy = null;
12
+ var cacheTimestamp = 0;
13
+ var CACHE_TTL_MS = 5 * 60 * 1e3;
14
+ async function fetchTrustPolicy(url) {
15
+ const now = Date.now();
16
+ if (cachedPolicy && now - cacheTimestamp < CACHE_TTL_MS) {
17
+ return cachedPolicy;
18
+ }
19
+ const res = await fetch(url ?? TRUST_POLICY_URL);
20
+ if (!res.ok) {
21
+ throw new Error(`Failed to fetch trust policy: ${res.status} ${res.statusText}`);
22
+ }
23
+ const policy = await res.json();
24
+ if (!policy.version || !policy.chains || typeof policy.chains !== "object") {
25
+ throw new Error("Invalid trust policy format");
26
+ }
27
+ cachedPolicy = policy;
28
+ cacheTimestamp = now;
29
+ return policy;
30
+ }
31
+ function extractAllowlists(policy) {
32
+ const contracts = [];
33
+ const schemas = [];
34
+ for (const chain of Object.values(policy.chains)) {
35
+ if (chain.easContract) contracts.push(chain.easContract);
36
+ if (chain.schemas) schemas.push(...chain.schemas);
37
+ }
38
+ return {
39
+ allowedContracts: [...new Set(contracts)],
40
+ allowedSchemas: [...new Set(schemas)]
41
+ };
42
+ }
43
+
44
+ // src/widgets/bridge.ts
45
+ function getTrustedBaseDomain() {
46
+ try {
47
+ const hostname = new URL(TRUST_POLICY_URL).hostname;
48
+ const parts = hostname.split(".");
49
+ return parts.length >= 2 ? parts.slice(-2).join(".") : hostname;
50
+ } catch {
51
+ return "omatrust.org";
52
+ }
53
+ }
54
+ function isOriginTrusted(messageOrigin, baseDomain, policyOrigins, devOverride) {
55
+ if (devOverride && messageOrigin === devOverride) return true;
56
+ try {
57
+ const hostname = new URL(messageOrigin).hostname;
58
+ if (hostname === baseDomain || hostname.endsWith(`.${baseDomain}`)) return true;
59
+ } catch {
60
+ }
61
+ if (policyOrigins.includes(messageOrigin)) return true;
62
+ return false;
63
+ }
64
+ var HEX_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
65
+ var BYTES32_RE = /^0x[a-fA-F0-9]{64}$/;
66
+ function validateEasSigningRequest(data, allowedSchemas, allowedContracts) {
67
+ const { id, domain, types, message } = data;
68
+ if (!id || typeof id !== "string") {
69
+ return { valid: false, reason: "Missing or invalid request id" };
70
+ }
71
+ if (!domain || typeof domain !== "object") {
72
+ return { valid: false, reason: "Missing domain object" };
73
+ }
74
+ const d = domain;
75
+ if (d.name !== "EAS") {
76
+ return { valid: false, reason: `Unexpected domain name: "${d.name}" (expected "EAS")` };
77
+ }
78
+ if (d.version !== "1.4.0") {
79
+ return { valid: false, reason: `Unexpected domain version: "${d.version}" (expected "1.4.0")` };
80
+ }
81
+ const chainId = Number(d.chainId);
82
+ if (!Number.isInteger(chainId) || chainId <= 0) {
83
+ return { valid: false, reason: `Invalid domain chainId: ${d.chainId}` };
84
+ }
85
+ if (typeof d.verifyingContract !== "string" || !HEX_ADDRESS_RE.test(d.verifyingContract)) {
86
+ return { valid: false, reason: `Invalid verifyingContract: ${d.verifyingContract}` };
87
+ }
88
+ const contractLower = d.verifyingContract.toLowerCase();
89
+ if (!allowedContracts.some((c) => c.toLowerCase() === contractLower)) {
90
+ return { valid: false, reason: `Contract ${d.verifyingContract} is not in the OMA3 trust policy` };
91
+ }
92
+ if (!types || typeof types !== "object") {
93
+ return { valid: false, reason: "Missing types object" };
94
+ }
95
+ if (!message || typeof message !== "object") {
96
+ return { valid: false, reason: "Missing message object" };
97
+ }
98
+ const m = message;
99
+ if (typeof m.schema !== "string" || !BYTES32_RE.test(m.schema)) {
100
+ return { valid: false, reason: `Invalid schema UID: ${m.schema}` };
101
+ }
102
+ const schemaLower = m.schema.toLowerCase();
103
+ if (!allowedSchemas.some((s) => s.toLowerCase() === schemaLower)) {
104
+ return { valid: false, reason: `Schema ${m.schema} is not in the OMA3 trust policy` };
105
+ }
106
+ if (typeof m.attester !== "string" || !HEX_ADDRESS_RE.test(m.attester)) {
107
+ return { valid: false, reason: `Invalid attester address: ${m.attester}` };
108
+ }
109
+ const deadline = Number(m.deadline);
110
+ if (!Number.isFinite(deadline) || deadline <= 0) {
111
+ return { valid: false, reason: `Invalid deadline: ${m.deadline}` };
112
+ }
113
+ const now = Math.floor(Date.now() / 1e3);
114
+ if (deadline <= now) {
115
+ return { valid: false, reason: `Deadline has passed: ${deadline} <= ${now}` };
116
+ }
117
+ return { valid: true };
118
+ }
119
+ async function createSigningBridge(options) {
120
+ const { iframe, signTypedData, devOriginOverride } = options;
121
+ const debug = typeof window !== "undefined" && window.__OMATRUST_DEBUG === true;
122
+ if (debug) console.log("[omatrust-bridge] fetching trust policy...");
123
+ const policy = await fetchTrustPolicy();
124
+ const { allowedContracts, allowedSchemas } = extractAllowlists(policy);
125
+ if (allowedContracts.length === 0 || allowedSchemas.length === 0) {
126
+ throw new Error("Trust policy contains no allowed contracts or schemas");
127
+ }
128
+ const baseDomain = getTrustedBaseDomain();
129
+ const policyOrigins = policy.widgetOrigins ?? [];
130
+ if (debug) {
131
+ console.log("[omatrust-bridge] trust policy loaded:", {
132
+ contracts: allowedContracts.length,
133
+ schemas: allowedSchemas.length,
134
+ baseDomain,
135
+ policyOrigins,
136
+ devOriginOverride
137
+ });
138
+ }
139
+ const replyOrigin = devOriginOverride ?? (() => {
140
+ try {
141
+ return new URL(iframe.src).origin;
142
+ } catch {
143
+ return "*";
144
+ }
145
+ })();
146
+ async function handleMessage(event) {
147
+ const data = event.data;
148
+ if (!data || typeof data !== "object" || typeof data.type !== "string") return;
149
+ if (!String(data.type).startsWith("omatrust:")) return;
150
+ if (debug) console.log("[omatrust-bridge] message:", data.type, "origin:", event.origin);
151
+ if (!isOriginTrusted(event.origin, baseDomain, policyOrigins, devOriginOverride)) {
152
+ if (debug) console.log("[omatrust-bridge] rejected: untrusted origin", event.origin);
153
+ return;
154
+ }
155
+ if (event.source !== iframe.contentWindow) {
156
+ if (debug) console.log("[omatrust-bridge] rejected: source !== iframe.contentWindow");
157
+ return;
158
+ }
159
+ const source = event.source;
160
+ function reply(msg) {
161
+ source.postMessage(msg, replyOrigin);
162
+ }
163
+ if (data.type === OMATRUST_READY) {
164
+ reply({ type: OMATRUST_HOST_READY });
165
+ return;
166
+ }
167
+ if (data.type === OMATRUST_SIGN_TYPED_DATA) {
168
+ const { id, domain, types, message } = data;
169
+ const validation = validateEasSigningRequest(data, allowedSchemas, allowedContracts);
170
+ if (!validation.valid) {
171
+ reply({
172
+ type: OMATRUST_SIGNATURE_ERROR,
173
+ id: id ?? "unknown",
174
+ error: `Signing request rejected: ${validation.reason}`
175
+ });
176
+ return;
177
+ }
178
+ try {
179
+ const signature = await signTypedData(domain, types, message);
180
+ reply({ type: OMATRUST_SIGNATURE, id, signature });
181
+ } catch (err) {
182
+ const error = err instanceof Error ? err.message : "Signing failed";
183
+ reply({ type: OMATRUST_SIGNATURE_ERROR, id, error });
184
+ }
185
+ }
186
+ }
187
+ window.addEventListener("message", handleMessage);
188
+ return {
189
+ destroy() {
190
+ window.removeEventListener("message", handleMessage);
191
+ }
192
+ };
193
+ }
194
+
195
+ export { OMATRUST_HOST_READY, OMATRUST_READY, OMATRUST_SIGNATURE, OMATRUST_SIGNATURE_ERROR, OMATRUST_SIGN_TYPED_DATA, TRUST_POLICY_URL, createSigningBridge, extractAllowlists, fetchTrustPolicy };
196
+ //# sourceMappingURL=index.js.map
197
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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.js","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 * Security model:\n * - Trust policy: fetched from api.omatrust.org on bridge creation.\n * Only contracts and schemas in the policy are accepted for signing.\n * - Origin check: derived from the trust policy domain (*.omatrust.org)\n * plus any additional origins listed in the policy's widgetOrigins field.\n * - Source check: messages must come from the specific iframe's contentWindow\n * - EAS validation: domain, schema, attester, deadline are all checked\n *\n * Usage:\n * import { createSigningBridge } from \"@oma3/omatrust/widgets\";\n *\n * const bridge = await createSigningBridge({\n * iframe: document.getElementById(\"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 /** The iframe element containing the widget. */\n iframe: HTMLIFrameElement;\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\n/**\n * Derive the trusted base domain from the trust policy URL.\n * e.g., \"https://api.omatrust.org/v1/trust-policy\" → \"omatrust.org\"\n */\nfunction getTrustedBaseDomain(): string {\n try {\n const hostname = new URL(TRUST_POLICY_URL).hostname;\n // Extract the registrable domain (last two parts)\n const parts = hostname.split(\".\");\n return parts.length >= 2 ? parts.slice(-2).join(\".\") : hostname;\n } catch {\n return \"omatrust.org\";\n }\n}\n\n/**\n * Check if a message origin is trusted.\n *\n * @param messageOrigin - The origin from event.origin (set by the browser)\n * @param baseDomain - The registrable domain of the trust policy (e.g., \"omatrust.org\")\n * @param policyOrigins - Additional origins from the trust policy's widgetOrigins field\n * @param devOverride - Optional dev-only origin (e.g., \"http://localhost:3000\")\n */\nfunction isOriginTrusted(\n messageOrigin: string,\n baseDomain: string,\n policyOrigins: string[],\n devOverride?: string\n): boolean {\n // 1. Dev override — allows localhost during development\n if (devOverride && messageOrigin === devOverride) return true;\n\n // 2. Subdomain of the trust policy domain (e.g., *.omatrust.org)\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 // 3. Explicitly listed in the trust policy\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 * Fetches the OMA3 trust policy on creation to determine which contracts,\n * schemas, and origins are allowed. The bridge will not start if the trust\n * policy cannot be fetched (fail closed).\n */\nexport async function createSigningBridge(options: SigningBridgeOptions): Promise<SigningBridge> {\n const { iframe, signTypedData, devOriginOverride } = options;\n\n const debug = typeof window !== \"undefined\" && (window as unknown as Record<string, unknown>).__OMATRUST_DEBUG === true;\n\n // Fetch the trust policy — fail closed if unavailable\n if (debug) console.log(\"[omatrust-bridge] fetching trust policy...\");\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 // Resolve trusted origins\n const baseDomain = getTrustedBaseDomain();\n const policyOrigins = policy.widgetOrigins ?? [];\n\n if (debug) {\n console.log(\"[omatrust-bridge] trust policy loaded:\", {\n contracts: allowedContracts.length,\n schemas: allowedSchemas.length,\n baseDomain,\n policyOrigins,\n devOriginOverride,\n });\n }\n\n // Determine the target origin for replies\n const replyOrigin = devOriginOverride ?? (() => {\n try {\n return new URL(iframe.src).origin;\n } catch {\n return \"*\";\n }\n })();\n\n async function handleMessage(event: MessageEvent) {\n // Only look at omatrust messages\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 if (debug) console.log(\"[omatrust-bridge] message:\", data.type, \"origin:\", event.origin);\n\n // Origin check — must be a trusted origin\n if (!isOriginTrusted(event.origin, baseDomain, policyOrigins, devOriginOverride)) {\n if (debug) console.log(\"[omatrust-bridge] rejected: untrusted origin\", event.origin);\n return;\n }\n\n // Source check — must come from the specific iframe's contentWindow\n if (event.source !== iframe.contentWindow) {\n if (debug) console.log(\"[omatrust-bridge] rejected: source !== iframe.contentWindow\");\n return;\n }\n\n const source = event.source as WindowProxy;\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oma3/omatrust",
3
- "version": "0.1.0-alpha.7",
3
+ "version": "0.1.0-alpha.8",
4
4
  "description": "Framework-agnostic TypeScript SDK for OMATrust",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,6 +44,14 @@
44
44
  "import": "./dist/app-registry/index.js",
45
45
  "require": "./dist/app-registry/index.cjs"
46
46
  },
47
+ "./widgets": {
48
+ "types": {
49
+ "import": "./dist/widgets/index.d.ts",
50
+ "require": "./dist/widgets/index.d.cts"
51
+ },
52
+ "import": "./dist/widgets/index.js",
53
+ "require": "./dist/widgets/index.cjs"
54
+ },
47
55
  "./package.json": "./package.json"
48
56
  },
49
57
  "files": [
@@ -56,7 +64,8 @@
56
64
  "build": "tsup",
57
65
  "clean": "rm -rf dist",
58
66
  "typecheck": "tsc --noEmit",
59
- "test": "vitest run"
67
+ "test": "vitest run",
68
+ "test:ci": "npm run typecheck && npm run test"
60
69
  },
61
70
  "dependencies": {
62
71
  "canonicalize": "^2.1.0"
@@ -73,6 +82,7 @@
73
82
  "devDependencies": {
74
83
  "@ethereum-attestation-service/eas-sdk": "^2.9.0",
75
84
  "@types/node": "^22.10.2",
85
+ "@vitest/coverage-v8": "^2.1.9",
76
86
  "ethers": "^6.16.0",
77
87
  "tsup": "^8.3.5",
78
88
  "typescript": "^5.7.2",