@reclaimprotocol/attestor-core 5.0.1-beta.1 → 5.0.1-beta.2

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 (261) hide show
  1. package/lib/avs/abis/avsDirectoryABI.d.ts +60 -0
  2. package/lib/avs/abis/avsDirectoryABI.js +343 -0
  3. package/lib/avs/abis/delegationABI.d.ts +126 -0
  4. package/lib/avs/abis/delegationABI.js +4 -0
  5. package/lib/avs/abis/registryABI.d.ts +136 -0
  6. package/lib/avs/abis/registryABI.js +728 -0
  7. package/lib/avs/client/create-claim-on-avs.d.ts +12 -0
  8. package/lib/avs/client/create-claim-on-avs.js +168 -0
  9. package/lib/avs/config.d.ts +7 -0
  10. package/lib/avs/config.js +26 -0
  11. package/lib/avs/contracts/ReclaimServiceManager.d.ts +601 -0
  12. package/lib/avs/contracts/ReclaimServiceManager.js +0 -0
  13. package/lib/avs/contracts/common.d.ts +50 -0
  14. package/lib/avs/contracts/common.js +0 -0
  15. package/lib/avs/contracts/factories/ReclaimServiceManager__factory.d.ts +890 -0
  16. package/lib/avs/contracts/factories/ReclaimServiceManager__factory.js +1183 -0
  17. package/lib/avs/contracts/factories/index.d.ts +1 -0
  18. package/lib/avs/contracts/factories/index.js +4 -0
  19. package/lib/avs/contracts/index.d.ts +3 -0
  20. package/lib/avs/contracts/index.js +6 -0
  21. package/lib/avs/types/index.d.ts +55 -0
  22. package/lib/avs/types/index.js +0 -0
  23. package/lib/avs/utils/contracts.d.ts +21 -0
  24. package/lib/avs/utils/contracts.js +53 -0
  25. package/lib/avs/utils/register.d.ts +27 -0
  26. package/lib/avs/utils/register.js +74 -0
  27. package/lib/avs/utils/tasks.d.ts +22 -0
  28. package/lib/avs/utils/tasks.js +48 -0
  29. package/lib/client/create-claim.d.ts +5 -0
  30. package/lib/client/create-claim.js +461 -0
  31. package/lib/client/index.d.ts +3 -0
  32. package/lib/client/index.js +3 -0
  33. package/lib/client/tunnels/make-rpc-tcp-tunnel.d.ts +16 -0
  34. package/lib/client/tunnels/make-rpc-tcp-tunnel.js +53 -0
  35. package/lib/client/tunnels/make-rpc-tls-tunnel.d.ts +26 -0
  36. package/lib/client/tunnels/make-rpc-tls-tunnel.js +127 -0
  37. package/lib/client/utils/attestor-pool.d.ts +8 -0
  38. package/lib/client/utils/attestor-pool.js +24 -0
  39. package/lib/client/utils/client-socket.d.ts +11 -0
  40. package/lib/client/utils/client-socket.js +120 -0
  41. package/lib/client/utils/message-handler.d.ts +4 -0
  42. package/lib/client/utils/message-handler.js +97 -0
  43. package/lib/config/index.d.ts +31 -0
  44. package/lib/config/index.js +62 -0
  45. package/lib/external-rpc/benchmark.d.ts +1 -0
  46. package/lib/external-rpc/benchmark.js +82 -0
  47. package/lib/external-rpc/event-bus.d.ts +7 -0
  48. package/lib/external-rpc/event-bus.js +17 -0
  49. package/lib/external-rpc/global.d.js +0 -0
  50. package/lib/external-rpc/handle-incoming-msg.d.ts +2 -0
  51. package/lib/external-rpc/handle-incoming-msg.js +241 -0
  52. package/lib/external-rpc/index.d.ts +3 -0
  53. package/lib/external-rpc/index.js +3 -0
  54. package/lib/external-rpc/jsc-polyfills/1.d.ts +14 -0
  55. package/lib/external-rpc/jsc-polyfills/1.js +80 -0
  56. package/lib/external-rpc/jsc-polyfills/2.d.ts +1 -0
  57. package/lib/external-rpc/jsc-polyfills/2.js +15 -0
  58. package/lib/external-rpc/jsc-polyfills/event.d.ts +10 -0
  59. package/lib/external-rpc/jsc-polyfills/event.js +19 -0
  60. package/lib/external-rpc/jsc-polyfills/index.d.ts +2 -0
  61. package/lib/external-rpc/jsc-polyfills/index.js +2 -0
  62. package/lib/external-rpc/jsc-polyfills/ws.d.ts +21 -0
  63. package/lib/external-rpc/jsc-polyfills/ws.js +83 -0
  64. package/lib/external-rpc/setup-browser.d.ts +6 -0
  65. package/lib/external-rpc/setup-browser.js +33 -0
  66. package/lib/external-rpc/setup-jsc.d.ts +24 -0
  67. package/lib/external-rpc/setup-jsc.js +22 -0
  68. package/lib/external-rpc/types.d.ts +213 -0
  69. package/lib/external-rpc/types.js +0 -0
  70. package/lib/external-rpc/utils.d.ts +20 -0
  71. package/lib/external-rpc/utils.js +100 -0
  72. package/lib/external-rpc/zk.d.ts +14 -0
  73. package/lib/external-rpc/zk.js +58 -0
  74. package/lib/index.d.ts +9 -0
  75. package/lib/index.js +13 -0
  76. package/lib/mechain/abis/governanceABI.d.ts +50 -0
  77. package/lib/mechain/abis/governanceABI.js +461 -0
  78. package/lib/mechain/abis/taskABI.d.ts +157 -0
  79. package/lib/mechain/abis/taskABI.js +512 -0
  80. package/lib/mechain/client/create-claim-on-mechain.d.ts +10 -0
  81. package/lib/mechain/client/create-claim-on-mechain.js +33 -0
  82. package/lib/mechain/client/index.d.ts +1 -0
  83. package/lib/mechain/client/index.js +1 -0
  84. package/lib/mechain/constants/index.d.ts +3 -0
  85. package/lib/mechain/constants/index.js +8 -0
  86. package/lib/mechain/index.d.ts +2 -0
  87. package/lib/mechain/index.js +2 -0
  88. package/lib/mechain/types/index.d.ts +23 -0
  89. package/lib/mechain/types/index.js +0 -0
  90. package/lib/proto/api.d.ts +651 -0
  91. package/lib/proto/api.js +4250 -0
  92. package/lib/proto/tee-bundle.d.ts +156 -0
  93. package/lib/proto/tee-bundle.js +1296 -0
  94. package/lib/providers/http/index.d.ts +18 -0
  95. package/lib/providers/http/index.js +640 -0
  96. package/lib/providers/http/patch-parse5-tree.d.ts +6 -0
  97. package/lib/providers/http/patch-parse5-tree.js +34 -0
  98. package/lib/providers/http/utils.d.ts +77 -0
  99. package/lib/providers/http/utils.js +283 -0
  100. package/lib/providers/index.d.ts +4 -0
  101. package/lib/providers/index.js +7 -0
  102. package/lib/scripts/build-browser.d.ts +1 -0
  103. package/lib/scripts/build-jsc.d.ts +1 -0
  104. package/lib/scripts/build-lib.d.ts +1 -0
  105. package/lib/scripts/check-avs-registration.d.ts +1 -0
  106. package/lib/scripts/check-avs-registration.js +28 -0
  107. package/lib/scripts/fallbacks/crypto.d.ts +1 -0
  108. package/lib/scripts/fallbacks/crypto.js +4 -0
  109. package/lib/scripts/fallbacks/empty.d.ts +3 -0
  110. package/lib/scripts/fallbacks/empty.js +4 -0
  111. package/lib/scripts/fallbacks/re2.d.ts +1 -0
  112. package/lib/scripts/fallbacks/re2.js +7 -0
  113. package/lib/scripts/fallbacks/snarkjs.d.ts +1 -0
  114. package/lib/scripts/fallbacks/snarkjs.js +10 -0
  115. package/lib/scripts/fallbacks/stwo.d.ts +6 -0
  116. package/lib/scripts/fallbacks/stwo.js +159 -0
  117. package/lib/scripts/generate-provider-types.d.ts +5 -0
  118. package/lib/scripts/generate-provider-types.js +101 -0
  119. package/lib/scripts/generate-receipt.d.ts +9 -0
  120. package/lib/scripts/generate-receipt.js +101 -0
  121. package/lib/scripts/generate-toprf-keys.d.ts +1 -0
  122. package/lib/scripts/generate-toprf-keys.js +24 -0
  123. package/lib/scripts/jsc-cli-rpc.d.ts +1 -0
  124. package/lib/scripts/jsc-cli-rpc.js +35 -0
  125. package/lib/scripts/register-avs-operator.d.ts +1 -0
  126. package/lib/scripts/register-avs-operator.js +3 -0
  127. package/lib/scripts/start-server.d.ts +1 -0
  128. package/lib/scripts/start-server.js +11 -0
  129. package/lib/scripts/update-avs-metadata.d.ts +1 -0
  130. package/lib/scripts/update-avs-metadata.js +20 -0
  131. package/lib/scripts/utils.d.ts +1 -0
  132. package/lib/scripts/utils.js +10 -0
  133. package/lib/scripts/whitelist-operator.d.ts +1 -0
  134. package/lib/scripts/whitelist-operator.js +16 -0
  135. package/lib/server/create-server.d.ts +8 -0
  136. package/lib/server/create-server.js +105 -0
  137. package/lib/server/handlers/claimTeeBundle.d.ts +6 -0
  138. package/lib/server/handlers/claimTeeBundle.js +232 -0
  139. package/lib/server/handlers/claimTunnel.d.ts +2 -0
  140. package/lib/server/handlers/claimTunnel.js +80 -0
  141. package/lib/server/handlers/completeClaimOnChain.d.ts +2 -0
  142. package/lib/server/handlers/completeClaimOnChain.js +29 -0
  143. package/lib/server/handlers/createClaimOnChain.d.ts +2 -0
  144. package/lib/server/handlers/createClaimOnChain.js +32 -0
  145. package/lib/server/handlers/createTaskOnMechain.d.ts +2 -0
  146. package/lib/server/handlers/createTaskOnMechain.js +57 -0
  147. package/lib/server/handlers/createTunnel.d.ts +2 -0
  148. package/lib/server/handlers/createTunnel.js +98 -0
  149. package/lib/server/handlers/disconnectTunnel.d.ts +2 -0
  150. package/lib/server/handlers/disconnectTunnel.js +8 -0
  151. package/lib/server/handlers/fetchCertificateBytes.d.ts +2 -0
  152. package/lib/server/handlers/fetchCertificateBytes.js +57 -0
  153. package/lib/server/handlers/index.d.ts +4 -0
  154. package/lib/server/handlers/index.js +25 -0
  155. package/lib/server/handlers/init.d.ts +2 -0
  156. package/lib/server/handlers/init.js +33 -0
  157. package/lib/server/handlers/toprf.d.ts +2 -0
  158. package/lib/server/handlers/toprf.js +19 -0
  159. package/lib/server/index.d.ts +4 -0
  160. package/lib/server/index.js +4 -0
  161. package/lib/server/socket.d.ts +13 -0
  162. package/lib/server/socket.js +112 -0
  163. package/lib/server/tunnels/make-tcp-tunnel.d.ts +22 -0
  164. package/lib/server/tunnels/make-tcp-tunnel.js +202 -0
  165. package/lib/server/utils/apm.d.ts +11 -0
  166. package/lib/server/utils/apm.js +29 -0
  167. package/lib/server/utils/assert-valid-claim-request.d.ts +31 -0
  168. package/lib/server/utils/assert-valid-claim-request.js +354 -0
  169. package/lib/server/utils/config-env.d.ts +1 -0
  170. package/lib/server/utils/config-env.js +4 -0
  171. package/lib/server/utils/dns.d.ts +1 -0
  172. package/lib/server/utils/dns.js +24 -0
  173. package/lib/server/utils/gcp-attestation.d.ts +17 -0
  174. package/lib/server/utils/gcp-attestation.js +237 -0
  175. package/lib/server/utils/generics.d.ts +22 -0
  176. package/lib/server/utils/generics.js +45 -0
  177. package/lib/server/utils/iso.d.ts +1 -0
  178. package/lib/server/utils/iso.js +259 -0
  179. package/lib/server/utils/keep-alive.d.ts +7 -0
  180. package/lib/server/utils/keep-alive.js +38 -0
  181. package/lib/server/utils/nitro-attestation.d.ts +33 -0
  182. package/lib/server/utils/nitro-attestation.js +249 -0
  183. package/lib/server/utils/oprf-raw.d.ts +21 -0
  184. package/lib/server/utils/oprf-raw.js +61 -0
  185. package/lib/server/utils/process-handshake.d.ts +13 -0
  186. package/lib/server/utils/process-handshake.js +233 -0
  187. package/lib/server/utils/proxy-session.d.ts +1 -0
  188. package/lib/server/utils/proxy-session.js +6 -0
  189. package/lib/server/utils/tee-oprf-mpc-verification.d.ts +16 -0
  190. package/lib/server/utils/tee-oprf-mpc-verification.js +86 -0
  191. package/lib/server/utils/tee-oprf-verification.d.ts +24 -0
  192. package/lib/server/utils/tee-oprf-verification.js +151 -0
  193. package/lib/server/utils/tee-transcript-reconstruction.d.ts +24 -0
  194. package/lib/server/utils/tee-transcript-reconstruction.js +140 -0
  195. package/lib/server/utils/tee-verification.d.ts +28 -0
  196. package/lib/server/utils/tee-verification.js +358 -0
  197. package/lib/server/utils/validation.d.ts +2 -0
  198. package/lib/server/utils/validation.js +45 -0
  199. package/lib/types/bgp.d.ts +11 -0
  200. package/lib/types/bgp.js +0 -0
  201. package/lib/types/claims.d.ts +70 -0
  202. package/lib/types/claims.js +0 -0
  203. package/lib/types/client.d.ts +163 -0
  204. package/lib/types/client.js +0 -0
  205. package/lib/types/general.d.ts +76 -0
  206. package/lib/types/general.js +0 -0
  207. package/lib/types/handlers.d.ts +10 -0
  208. package/lib/types/handlers.js +0 -0
  209. package/lib/types/index.d.ts +10 -0
  210. package/lib/types/index.js +10 -0
  211. package/lib/types/providers.d.ts +161 -0
  212. package/lib/types/providers.gen.d.ts +443 -0
  213. package/lib/types/providers.gen.js +16 -0
  214. package/lib/types/providers.js +0 -0
  215. package/lib/types/rpc.d.ts +35 -0
  216. package/lib/types/rpc.js +0 -0
  217. package/lib/types/signatures.d.ts +28 -0
  218. package/lib/types/signatures.js +0 -0
  219. package/lib/types/tunnel.d.ts +18 -0
  220. package/lib/types/tunnel.js +0 -0
  221. package/lib/types/zk.d.ts +38 -0
  222. package/lib/types/zk.js +0 -0
  223. package/lib/utils/auth.d.ts +8 -0
  224. package/lib/utils/auth.js +71 -0
  225. package/lib/utils/b64-json.d.ts +2 -0
  226. package/lib/utils/b64-json.js +17 -0
  227. package/lib/utils/bgp-listener.d.ts +7 -0
  228. package/lib/utils/bgp-listener.js +123 -0
  229. package/lib/utils/claims.d.ts +33 -0
  230. package/lib/utils/claims.js +89 -0
  231. package/lib/utils/env.d.ts +3 -0
  232. package/lib/utils/env.js +19 -0
  233. package/lib/utils/error.d.ts +26 -0
  234. package/lib/utils/error.js +54 -0
  235. package/lib/utils/generics.d.ts +114 -0
  236. package/lib/utils/generics.js +268 -0
  237. package/lib/utils/http-parser.d.ts +59 -0
  238. package/lib/utils/http-parser.js +201 -0
  239. package/lib/utils/index.d.ts +13 -0
  240. package/lib/utils/index.js +13 -0
  241. package/lib/utils/logger.d.ts +13 -0
  242. package/lib/utils/logger.js +82 -0
  243. package/lib/utils/prepare-packets.d.ts +16 -0
  244. package/lib/utils/prepare-packets.js +69 -0
  245. package/lib/utils/redactions.d.ts +73 -0
  246. package/lib/utils/redactions.js +135 -0
  247. package/lib/utils/retries.d.ts +12 -0
  248. package/lib/utils/retries.js +26 -0
  249. package/lib/utils/signatures/eth.d.ts +2 -0
  250. package/lib/utils/signatures/eth.js +31 -0
  251. package/lib/utils/signatures/index.d.ts +5 -0
  252. package/lib/utils/signatures/index.js +12 -0
  253. package/lib/utils/socket-base.d.ts +23 -0
  254. package/lib/utils/socket-base.js +96 -0
  255. package/lib/utils/tls.d.ts +2 -0
  256. package/lib/utils/tls.js +58 -0
  257. package/lib/utils/ws.d.ts +7 -0
  258. package/lib/utils/ws.js +22 -0
  259. package/lib/utils/zk.d.ts +71 -0
  260. package/lib/utils/zk.js +625 -0
  261. package/package.json +2 -2
@@ -0,0 +1,232 @@
1
+ import { ClaimTeeBundleResponse } from "../../proto/api.js";
2
+ import { VerificationBundle } from "../../proto/tee-bundle.js";
3
+ import { substituteParamValues } from "../../providers/http/index.js";
4
+ import { assertValidProviderTranscript } from "../../server/utils/assert-valid-claim-request.js";
5
+ import { getAttestorAddress, niceParseJsonObject, signAsAttestor } from "../../server/utils/generics.js";
6
+ import { verifyOprfMpcOutputs } from "../../server/utils/tee-oprf-mpc-verification.js";
7
+ import { verifyOprfProofs } from "../../server/utils/tee-oprf-verification.js";
8
+ import { reconstructTlsTranscript } from "../../server/utils/tee-transcript-reconstruction.js";
9
+ import { verifyTeeBundle } from "../../server/utils/tee-verification.js";
10
+ import { AttestorError } from "../../utils/error.js";
11
+ import { createSignDataForClaim, getIdentifierFromClaimInfo } from "../../utils/index.js";
12
+ const claimTeeBundle = async (teeBundleRequest, { logger, client }) => {
13
+ const {
14
+ verificationBundle,
15
+ data
16
+ } = teeBundleRequest;
17
+ const res = ClaimTeeBundleResponse.create({ request: teeBundleRequest });
18
+ logger.info("Starting TEE bundle verification");
19
+ const teeData = await verifyTeeBundle(verificationBundle, logger);
20
+ const timestampS = Math.floor(teeData.kOutputPayload.timestampMs / 1e3);
21
+ logger.info("Verifying OPRF proofs");
22
+ const bundle = VerificationBundle.decode(verificationBundle);
23
+ const zkOprfResults = await verifyOprfProofs(
24
+ { ...teeData, oprfVerifications: bundle.oprfVerifications },
25
+ logger
26
+ );
27
+ logger.info("Verifying OPRF MPC outputs");
28
+ const oprfMpcResults = verifyOprfMpcOutputs(
29
+ teeData.kOutputPayload,
30
+ teeData.tOutputPayload,
31
+ logger
32
+ );
33
+ const allOprfResults = validateAndCombineOprfResults(zkOprfResults, oprfMpcResults, logger);
34
+ logger.info("Starting TLS transcript reconstruction with OPRF replacements");
35
+ const transcriptData = await reconstructTlsTranscript(teeData, logger, allOprfResults);
36
+ logger.info("Creating plaintext transcript from TEE data");
37
+ const plaintextTranscript = createPlaintextTranscriptFromTeeData(transcriptData, logger);
38
+ logger.info("Running direct provider validation on TEE reconstructed data");
39
+ if (!data) {
40
+ throw new AttestorError("ERROR_INVALID_CLAIM", "No claim data provided in TEE bundle request");
41
+ }
42
+ const validatedClaim = await validateTeeProviderReceipt(
43
+ plaintextTranscript,
44
+ data,
45
+ logger,
46
+ { version: client.metadata.clientVersion },
47
+ transcriptData.certificateInfo
48
+ );
49
+ const ctx = niceParseJsonObject(validatedClaim.context, "context");
50
+ ctx.pcr0_k = teeData.teekPcr0;
51
+ ctx.pcr0_t = teeData.teetPcr0;
52
+ ctx.tee_session_id = teeData.teeSessionId;
53
+ validatedClaim.context = JSON.stringify(ctx);
54
+ res.claim = {
55
+ ...validatedClaim,
56
+ identifier: getIdentifierFromClaimInfo(validatedClaim),
57
+ // Use timestampS from TEE_K bundle for claim signing
58
+ timestampS,
59
+ // hardcode for compatibility with V1 claims
60
+ epoch: 1
61
+ };
62
+ logger.info({ claim: res.claim }, "TEE bundle claim validation successful");
63
+ res.signatures = {
64
+ attestorAddress: getAttestorAddress(
65
+ client.metadata.signatureType
66
+ ),
67
+ claimSignature: res.claim ? await signAsAttestor(
68
+ createSignDataForClaim(res.claim),
69
+ client.metadata.signatureType
70
+ ) : new Uint8Array(),
71
+ resultSignature: await signAsAttestor(
72
+ ClaimTeeBundleResponse.encode(res).finish(),
73
+ client.metadata.signatureType
74
+ )
75
+ };
76
+ logger.info("TEE bundle claim processing completed");
77
+ return res;
78
+ };
79
+ function createPlaintextTranscriptFromTeeData(transcriptData, logger) {
80
+ const transcript = [];
81
+ if (transcriptData.revealedRequest && transcriptData.revealedRequest.length > 0) {
82
+ transcript.push({
83
+ sender: "client",
84
+ message: transcriptData.revealedRequest
85
+ });
86
+ logger.debug("Added TEE revealed request to plaintext transcript", {
87
+ length: transcriptData.revealedRequest.length
88
+ });
89
+ }
90
+ if (transcriptData.reconstructedResponse && transcriptData.reconstructedResponse.length > 0) {
91
+ transcript.push({
92
+ sender: "server",
93
+ message: transcriptData.reconstructedResponse
94
+ });
95
+ logger.debug("Added TEE consolidated response to plaintext transcript", {
96
+ length: transcriptData.reconstructedResponse.length
97
+ });
98
+ }
99
+ if (transcriptData.certificateInfo) {
100
+ logger.info("Certificate information available for validation", {
101
+ commonName: transcriptData.certificateInfo.commonName,
102
+ issuerCommonName: transcriptData.certificateInfo.issuerCommonName,
103
+ dnsNames: transcriptData.certificateInfo.dnsNames,
104
+ notBefore: new Date(transcriptData.certificateInfo.notBeforeUnix * 1e3).toISOString(),
105
+ notAfter: new Date(transcriptData.certificateInfo.notAfterUnix * 1e3).toISOString()
106
+ });
107
+ }
108
+ logger.info("Created plaintext transcript from TEE data", {
109
+ totalMessages: transcript.length,
110
+ hasRequest: !!transcriptData.revealedRequest?.length,
111
+ hasResponse: !!transcriptData.reconstructedResponse?.length,
112
+ hasCertificateInfo: !!transcriptData.certificateInfo
113
+ });
114
+ return transcript;
115
+ }
116
+ async function validateTeeProviderReceipt(plaintextTranscript, claimInfo, logger, providerCtx, certificateInfo) {
117
+ logger.info("Starting direct TEE provider validation", {
118
+ provider: claimInfo.provider,
119
+ transcriptMessages: plaintextTranscript.length,
120
+ hasCertificateInfo: !!certificateInfo
121
+ });
122
+ if (certificateInfo) {
123
+ validateTlsCertificate(claimInfo, certificateInfo, logger);
124
+ }
125
+ const validatedClaim = await assertValidProviderTranscript(
126
+ plaintextTranscript,
127
+ claimInfo,
128
+ logger,
129
+ providerCtx
130
+ );
131
+ logger.info("TEE provider validation completed successfully", {
132
+ provider: validatedClaim.provider,
133
+ owner: validatedClaim.owner || "unknown"
134
+ });
135
+ return validatedClaim;
136
+ }
137
+ function isHostnameValidForCertificate(hostname, certName) {
138
+ if (hostname === certName) {
139
+ return true;
140
+ }
141
+ if (certName.startsWith("*.")) {
142
+ const wildcardDomain = certName.slice(2);
143
+ if (hostname.endsWith(wildcardDomain)) {
144
+ const subdomainPart = hostname.slice(0, -wildcardDomain.length);
145
+ if (subdomainPart.endsWith(".")) {
146
+ const subdomain = subdomainPart.slice(0, -1);
147
+ return !subdomain.includes(".");
148
+ }
149
+ }
150
+ }
151
+ return false;
152
+ }
153
+ function validateTlsCertificate(claimInfo, certificateInfo, logger) {
154
+ let claimedHostname;
155
+ const paramsWithTemplates = niceParseJsonObject(claimInfo.parameters, "params");
156
+ const params = substituteParamValues(paramsWithTemplates, void 0, true).newParams;
157
+ if ("url" in params && typeof params.url === "string") {
158
+ claimedHostname = new URL(params.url).hostname;
159
+ }
160
+ if (!claimedHostname) {
161
+ logger.warn("Could not extract hostname from claim for certificate validation", {
162
+ provider: claimInfo.provider
163
+ });
164
+ throw new AttestorError(
165
+ "ERROR_INVALID_CLAIM",
166
+ "Certificate validation failed: hostname not found"
167
+ );
168
+ }
169
+ logger.info("Validating TLS certificate for claimed hostname", {
170
+ claimedHostname,
171
+ certificateCommonName: certificateInfo.commonName,
172
+ certificateDnsNames: certificateInfo.dnsNames
173
+ });
174
+ const isValidForHostname = isHostnameValidForCertificate(claimedHostname, certificateInfo.commonName) || certificateInfo.dnsNames.some((name) => isHostnameValidForCertificate(claimedHostname, name));
175
+ if (!isValidForHostname) {
176
+ throw new AttestorError(
177
+ "ERROR_INVALID_CLAIM",
178
+ `Certificate validation failed: hostname '${claimedHostname}' not valid for certificate (CN: ${certificateInfo.commonName}, SANs: ${certificateInfo.dnsNames.join(", ")})`
179
+ );
180
+ }
181
+ const now = Date.now() / 1e3;
182
+ if (now < certificateInfo.notBeforeUnix || now > certificateInfo.notAfterUnix) {
183
+ throw new AttestorError(
184
+ "ERROR_INVALID_CLAIM",
185
+ `Certificate validation failed: certificate not valid at current time (valid from ${new Date(certificateInfo.notBeforeUnix * 1e3).toISOString()} to ${new Date(certificateInfo.notAfterUnix * 1e3).toISOString()})`
186
+ );
187
+ }
188
+ logger.info("TLS certificate validation passed", {
189
+ claimedHostname,
190
+ validatedAgainst: isHostnameValidForCertificate(claimedHostname, certificateInfo.commonName) ? `CommonName: ${certificateInfo.commonName}` : `SAN: ${certificateInfo.dnsNames.find((name) => isHostnameValidForCertificate(claimedHostname, name))}`
191
+ });
192
+ }
193
+ function validateAndCombineOprfResults(zkOprfResults, oprfMpcResults, logger) {
194
+ const allOprfResults = [...zkOprfResults, ...oprfMpcResults];
195
+ if (allOprfResults.length === 0) {
196
+ return allOprfResults;
197
+ }
198
+ logger.info(`Combined ${zkOprfResults.length} ZK OPRF + ${oprfMpcResults.length} OPRF MPC results`);
199
+ const seen = {};
200
+ for (const result of zkOprfResults) {
201
+ seen[result.position] = { length: result.length, source: "zk" };
202
+ }
203
+ for (const result of oprfMpcResults) {
204
+ const existing = seen[result.position];
205
+ if (existing) {
206
+ if (existing.length !== result.length) {
207
+ throw new AttestorError(
208
+ "ERROR_INVALID_CLAIM",
209
+ `OPRF range conflict at position ${result.position}: ZK length ${existing.length} vs MPC length ${result.length}`
210
+ );
211
+ }
212
+ logger.warn(`Duplicate OPRF range at position ${result.position} from both ZK and MPC - using MPC result`);
213
+ }
214
+ for (const [pos, data] of Object.entries(seen)) {
215
+ const position = Number(pos);
216
+ const existingEnd = position + data.length;
217
+ const newEnd = result.position + result.length;
218
+ const overlaps = result.position < existingEnd && newEnd > position && result.position !== position;
219
+ if (overlaps) {
220
+ throw new AttestorError(
221
+ "ERROR_INVALID_CLAIM",
222
+ `Overlapping OPRF ranges: [${position}:${existingEnd}] (${data.source}) and [${result.position}:${newEnd}] (mpc)`
223
+ );
224
+ }
225
+ }
226
+ seen[result.position] = { length: result.length, source: "mpc" };
227
+ }
228
+ return allOprfResults;
229
+ }
230
+ export {
231
+ claimTeeBundle
232
+ };
@@ -0,0 +1,2 @@
1
+ import type { RPCHandler } from '#src/types/index.ts';
2
+ export declare const claimTunnel: RPCHandler<'claimTunnel'>;
@@ -0,0 +1,80 @@
1
+ import { MAX_CLAIM_TIMESTAMP_DIFF_S } from "../../config/index.js";
2
+ import { ClaimTunnelResponse } from "../../proto/api.js";
3
+ import { getApm } from "../../server/utils/apm.js";
4
+ import { assertTranscriptsMatch, assertValidClaimRequest } from "../../server/utils/assert-valid-claim-request.js";
5
+ import { getAttestorAddress, signAsAttestor } from "../../server/utils/generics.js";
6
+ import { AttestorError, createSignDataForClaim, getIdentifierFromClaimInfo, unixTimestampSeconds } from "../../utils/index.js";
7
+ const claimTunnel = async (claimRequest, { tx, logger, client }) => {
8
+ const {
9
+ request,
10
+ data: { timestampS } = {}
11
+ } = claimRequest;
12
+ const tunnel = client.getTunnel(request?.id);
13
+ try {
14
+ await tunnel.close();
15
+ } catch (err) {
16
+ logger.debug({ err }, "error closing tunnel");
17
+ }
18
+ if (tx) {
19
+ const transcriptBytes = tunnel.transcript.reduce(
20
+ (acc, { message }) => acc + message.length,
21
+ 0
22
+ );
23
+ tx?.setLabel("transcriptBytes", transcriptBytes.toString());
24
+ }
25
+ if (tunnel.createRequest?.host !== request?.host || tunnel.createRequest?.port !== request?.port || tunnel.createRequest?.geoLocation !== request?.geoLocation || tunnel.createRequest?.proxySessionId !== request?.proxySessionId) {
26
+ throw AttestorError.badRequest("Tunnel request does not match");
27
+ }
28
+ assertTranscriptsMatch(claimRequest.transcript, tunnel.transcript);
29
+ const res = ClaimTunnelResponse.create({ request: claimRequest });
30
+ try {
31
+ const now = unixTimestampSeconds();
32
+ if (Math.floor(timestampS - now) > MAX_CLAIM_TIMESTAMP_DIFF_S) {
33
+ throw new AttestorError(
34
+ "ERROR_INVALID_CLAIM",
35
+ `Timestamp provided ${timestampS} is too far off. Current time is ${now}`
36
+ );
37
+ }
38
+ const assertTx = getApm()?.startTransaction("assertValidClaimRequest", { childOf: tx });
39
+ try {
40
+ const claim = await assertValidClaimRequest(
41
+ claimRequest,
42
+ client.metadata,
43
+ logger
44
+ );
45
+ res.claim = {
46
+ ...claim,
47
+ identifier: getIdentifierFromClaimInfo(claim),
48
+ // hardcode for compatibility with V1 claims
49
+ epoch: 1
50
+ };
51
+ } catch (err) {
52
+ assertTx?.setOutcome("failure");
53
+ throw err;
54
+ } finally {
55
+ assertTx?.end();
56
+ }
57
+ } catch (err) {
58
+ logger.error({ err }, "invalid claim request");
59
+ const attestorErr = AttestorError.fromError(err, "ERROR_INVALID_CLAIM");
60
+ res.error = attestorErr.toProto();
61
+ }
62
+ res.signatures = {
63
+ attestorAddress: getAttestorAddress(
64
+ client.metadata.signatureType
65
+ ),
66
+ claimSignature: res.claim ? await signAsAttestor(
67
+ createSignDataForClaim(res.claim),
68
+ client.metadata.signatureType
69
+ ) : new Uint8Array(),
70
+ resultSignature: await signAsAttestor(
71
+ ClaimTunnelResponse.encode(res).finish(),
72
+ client.metadata.signatureType
73
+ )
74
+ };
75
+ client.removeTunnel(request.id);
76
+ return res;
77
+ };
78
+ export {
79
+ claimTunnel
80
+ };
@@ -0,0 +1,2 @@
1
+ import type { RPCHandler } from '#src/types/index.ts';
2
+ export declare const completeClaimOnChain: RPCHandler<'completeClaimOnChain'>;
@@ -0,0 +1,29 @@
1
+ import { EventLog } from "ethers";
2
+ import { getContracts } from "../../avs/utils/contracts.js";
3
+ import { getEnvVariable } from "../../utils/env.js";
4
+ import { AttestorError, ethersStructToPlainObject } from "../../utils/index.js";
5
+ const ACCEPT_CLAIM_PAYMENT_REQUESTS = getEnvVariable("ACCEPT_CLAIM_PAYMENT_REQUESTS") === "1";
6
+ const completeClaimOnChain = async ({ chainId: chainIdNum, taskIndex, completedTaskJson }) => {
7
+ if (!ACCEPT_CLAIM_PAYMENT_REQUESTS) {
8
+ throw new AttestorError(
9
+ "ERROR_PAYMENT_REFUSED",
10
+ "Payment requests are not accepted at this time"
11
+ );
12
+ }
13
+ const chainId = chainIdNum.toString();
14
+ const { contract } = getContracts(chainId.toString());
15
+ const task = JSON.parse(completedTaskJson);
16
+ const tx = await contract.taskCompleted(task, taskIndex);
17
+ const rslt = await tx.wait();
18
+ const logs = rslt?.logs ?? [];
19
+ const eventLogs = logs.filter((log) => log instanceof EventLog);
20
+ const obj = eventLogs[0]?.args;
21
+ const plainObj = ethersStructToPlainObject(obj);
22
+ return {
23
+ txHash: rslt?.hash ?? "",
24
+ taskCompletedObjectJson: JSON.stringify(plainObj)
25
+ };
26
+ };
27
+ export {
28
+ completeClaimOnChain
29
+ };
@@ -0,0 +1,2 @@
1
+ import type { RPCHandler } from '#src/types/index.ts';
2
+ export declare const createClaimOnChain: RPCHandler<'createClaimOnChain'>;
@@ -0,0 +1,32 @@
1
+ import { getContracts } from "../../avs/utils/contracts.js";
2
+ import { createNewClaimRequestOnChain } from "../../avs/utils/tasks.js";
3
+ import { getEnvVariable } from "../../utils/env.js";
4
+ import { AttestorError, ethersStructToPlainObject } from "../../utils/index.js";
5
+ const ACCEPT_CLAIM_PAYMENT_REQUESTS = getEnvVariable("ACCEPT_CLAIM_PAYMENT_REQUESTS") === "1";
6
+ const createClaimOnChain = async ({ chainId: chainIdNum, jsonCreateClaimRequest, requestSignature }) => {
7
+ if (!ACCEPT_CLAIM_PAYMENT_REQUESTS) {
8
+ throw new AttestorError(
9
+ "ERROR_PAYMENT_REFUSED",
10
+ "Payment requests are not accepted at this time"
11
+ );
12
+ }
13
+ const chainId = chainIdNum.toString();
14
+ const { wallet } = getContracts(chainId.toString());
15
+ const request = JSON.parse(jsonCreateClaimRequest);
16
+ const { task, tx } = await createNewClaimRequestOnChain({
17
+ request,
18
+ owner: request.owner,
19
+ payer: wallet,
20
+ chainId,
21
+ requestSignature
22
+ });
23
+ const plainTask = ethersStructToPlainObject(task);
24
+ return {
25
+ txHash: tx?.hash ?? "",
26
+ taskIndex: Number(task.taskIndex),
27
+ jsonTask: JSON.stringify(plainTask)
28
+ };
29
+ };
30
+ export {
31
+ createClaimOnChain
32
+ };
@@ -0,0 +1,2 @@
1
+ import type { RPCHandler } from '#src/types/index.ts';
2
+ export declare const createTaskOnMechain: RPCHandler<'createTaskOnMechain'>;
@@ -0,0 +1,57 @@
1
+ import { Contract, JsonRpcProvider, randomBytes, Wallet } from "ethers";
2
+ import { governanceABI } from "../../mechain/abis/governanceABI.js";
3
+ import { taskABI } from "../../mechain/abis/taskABI.js";
4
+ import { GOVERNANCE_CONTRACT_ADDRESS, RPC_URL, TASK_CONTRACT_ADDRESS } from "../../mechain/constants/index.js";
5
+ import { getEnvVariable } from "../../utils/env.js";
6
+ const createTaskOnMechain = async ({
7
+ timestamp
8
+ }) => {
9
+ const { taskContract } = await getContracts();
10
+ const seed = randomBytes(32);
11
+ const result = await taskContract.createNewTaskRequest.staticCall(
12
+ seed,
13
+ timestamp
14
+ );
15
+ const taskId = result[0];
16
+ const requiredAttestors = await taskContract.requiredAttestors();
17
+ const hosts = [];
18
+ for (let i = 0; i < requiredAttestors; i++) {
19
+ hosts.push(result[1][i].host);
20
+ }
21
+ const tx = await taskContract.createNewTaskRequest(seed, timestamp);
22
+ await tx.wait();
23
+ return {
24
+ taskId,
25
+ requiredAttestors,
26
+ hosts
27
+ };
28
+ };
29
+ async function getContracts() {
30
+ const privateKey = getEnvVariable("MECHAIN_PRIVATE_KEY");
31
+ const taskContractAddress = getEnvVariable("TASK_CONTRACT_ADDRESS") || TASK_CONTRACT_ADDRESS;
32
+ const governanceContractAddress = getEnvVariable("GOVERNANCE_CONTRACT_ADDRESS") || GOVERNANCE_CONTRACT_ADDRESS;
33
+ if (!privateKey) {
34
+ throw new Error("MECHAIN_PRIVATE_KEY environment variable is not set");
35
+ }
36
+ try {
37
+ const provider = new JsonRpcProvider(RPC_URL);
38
+ await provider.getNetwork();
39
+ const signer = new Wallet(privateKey, provider);
40
+ const taskContract = new Contract(
41
+ taskContractAddress,
42
+ taskABI,
43
+ signer
44
+ );
45
+ const governanceContract = new Contract(
46
+ governanceContractAddress,
47
+ governanceABI,
48
+ signer
49
+ );
50
+ return { taskContract, governanceContract };
51
+ } catch (error) {
52
+ throw new Error(`Failed to initialize contracts: ${error.message || error}`);
53
+ }
54
+ }
55
+ export {
56
+ createTaskOnMechain
57
+ };
@@ -0,0 +1,2 @@
1
+ import type { RPCHandler } from '#src/types/index.ts';
2
+ export declare const createTunnel: RPCHandler<'createTunnel'>;
@@ -0,0 +1,98 @@
1
+ import { makeTcpTunnel } from "../../server/tunnels/make-tcp-tunnel.js";
2
+ import { getApm } from "../../server/utils/apm.js";
3
+ import { resolveHostnames } from "../../server/utils/dns.js";
4
+ import { AttestorError } from "../../utils/index.js";
5
+ const createTunnel = async ({ id, ...opts }, { tx, logger, client }) => {
6
+ if (client.tunnels[id]) {
7
+ throw AttestorError.badRequest(`Tunnel "${id}" already exists`);
8
+ }
9
+ const allowedHosts = client.metadata?.auth?.data?.hostWhitelist;
10
+ if (allowedHosts?.length && !allowedHosts.includes(opts.host)) {
11
+ throw AttestorError.badRequest(
12
+ `Host "${opts.host}" not allowed by auth request`
13
+ );
14
+ }
15
+ let cancelBgp;
16
+ const apm = getApm();
17
+ const sessionTx = apm?.startTransaction("tunnelConnection", { childOf: tx });
18
+ sessionTx?.setLabel("tunnelId", id.toString());
19
+ sessionTx?.setLabel("hostPort", `${opts.host}:${opts.port}`);
20
+ sessionTx?.setLabel("geoLocation", opts.geoLocation);
21
+ sessionTx?.setLabel("proxySessionId", opts.proxySessionId);
22
+ try {
23
+ const tunnel = await makeTcpTunnel({
24
+ ...opts,
25
+ logger,
26
+ onMessage(message) {
27
+ if (!client.isOpen) {
28
+ logger.warn("client is closed, dropping message");
29
+ return;
30
+ }
31
+ return client.sendMessage({ tunnelMessage: { tunnelId: id, message } });
32
+ },
33
+ onClose(err) {
34
+ cancelBgp?.();
35
+ if (err) {
36
+ apm?.captureError(err, { parent: sessionTx });
37
+ sessionTx?.setOutcome("failure");
38
+ } else {
39
+ sessionTx?.setOutcome("success");
40
+ }
41
+ sessionTx?.end();
42
+ if (!client.isOpen) {
43
+ return;
44
+ }
45
+ client.sendMessage({
46
+ tunnelDisconnectEvent: {
47
+ tunnelId: id,
48
+ error: err ? AttestorError.fromError(err).toProto() : void 0
49
+ }
50
+ }).catch((err2) => {
51
+ logger.error(
52
+ { err: err2 },
53
+ "failed to send tunnel disconnect event"
54
+ );
55
+ });
56
+ }
57
+ });
58
+ try {
59
+ await checkForBgp(tunnel);
60
+ } catch (err) {
61
+ logger.warn(
62
+ { err, host: opts.host },
63
+ "failed to start BGP overlap check"
64
+ );
65
+ }
66
+ client.tunnels[id] = tunnel;
67
+ return {};
68
+ } catch (err) {
69
+ apm?.captureError(err, { parent: sessionTx });
70
+ sessionTx?.setOutcome("failure");
71
+ sessionTx?.end();
72
+ cancelBgp?.();
73
+ throw err;
74
+ }
75
+ async function checkForBgp(tunnel) {
76
+ if (!client.bgpListener) {
77
+ return;
78
+ }
79
+ const ips = await resolveHostnames(opts.host);
80
+ cancelBgp = client.bgpListener.onOverlap(ips, (info) => {
81
+ logger.warn(
82
+ { info, host: opts.host },
83
+ "BGP announcement overlap detected"
84
+ );
85
+ sessionTx?.addLabels({ bgpOverlap: true, ...info });
86
+ void tunnel?.close(
87
+ new AttestorError(
88
+ "ERROR_BGP_ANNOUNCEMENT_OVERLAP",
89
+ `BGP announcement overlap detected for ${opts.host}`
90
+ )
91
+ );
92
+ });
93
+ logger.debug({ ips }, "checking for BGP overlap");
94
+ }
95
+ };
96
+ export {
97
+ createTunnel
98
+ };
@@ -0,0 +1,2 @@
1
+ import type { RPCHandler } from '#src/types/index.ts';
2
+ export declare const disconnectTunnel: RPCHandler<'disconnectTunnel'>;
@@ -0,0 +1,8 @@
1
+ const disconnectTunnel = async ({ id }, { client }) => {
2
+ const tunnel = client.getTunnel(id);
3
+ await tunnel.close();
4
+ return {};
5
+ };
6
+ export {
7
+ disconnectTunnel
8
+ };
@@ -0,0 +1,2 @@
1
+ import type { RPCHandler } from '#src/types/handlers.ts';
2
+ export declare const fetchCertificateBytes: RPCHandler<'fetchCertificateBytes'>;
@@ -0,0 +1,57 @@
1
+ import { concatenateUint8Arrays, loadX509FromPem } from "@reclaimprotocol/tls";
2
+ import { CERT_ALLOWED_MIMETYPES, MAX_CERT_SIZE_BYTES } from "../../config/index.js";
3
+ import { AttestorError } from "../../utils/error.js";
4
+ const fetchCertificateBytes = async ({ url }) => {
5
+ const res = await fetch(url, {
6
+ redirect: "follow",
7
+ signal: AbortSignal.timeout(1e4)
8
+ });
9
+ if (!res.ok) {
10
+ res.body?.cancel("Not ok");
11
+ throw new AttestorError(
12
+ "ERROR_CERTIFICATE_FETCH_FAILED",
13
+ `Failed to fetch certificate from URL: ${url}, status: ${res.status}`
14
+ );
15
+ }
16
+ const contentType = res.headers.get("content-type");
17
+ if (!contentType || !CERT_ALLOWED_MIMETYPES.includes(contentType)) {
18
+ res.body?.cancel("Mismatch");
19
+ throw new AttestorError(
20
+ "ERROR_CERTIFICATE_FETCH_FAILED",
21
+ `Invalid content-type when fetching certificate from URL: ${url}, content-type: ${contentType}`
22
+ );
23
+ }
24
+ if (!res.body) {
25
+ throw new AttestorError(
26
+ "ERROR_CERTIFICATE_FETCH_FAILED",
27
+ `No body in response when fetching certificate from URL: ${url}`
28
+ );
29
+ }
30
+ let total = 0;
31
+ const byteArr = [];
32
+ for await (const chunk of res.body) {
33
+ total += chunk.length;
34
+ if (total > MAX_CERT_SIZE_BYTES) {
35
+ res.body.cancel("Too many bytes");
36
+ throw new AttestorError(
37
+ "ERROR_CERTIFICATE_FETCH_FAILED",
38
+ `Certificate size exceeds maximum limit of ${MAX_CERT_SIZE_BYTES}b`
39
+ );
40
+ }
41
+ byteArr.push(chunk);
42
+ }
43
+ const bytes = concatenateUint8Arrays(byteArr);
44
+ try {
45
+ const cert = loadX509FromPem(bytes);
46
+ TLS_INTERMEDIATE_CA_CACHE[url] = cert;
47
+ } catch (err) {
48
+ throw new AttestorError(
49
+ "ERROR_CERTIFICATE_FETCH_FAILED",
50
+ `Failed to parse certificate, error: ${err.message}`
51
+ );
52
+ }
53
+ return { bytes: concatenateUint8Arrays(byteArr) };
54
+ };
55
+ export {
56
+ fetchCertificateBytes
57
+ };
@@ -0,0 +1,4 @@
1
+ import type { RPCHandler, RPCType } from '#src/types/index.ts';
2
+ export declare const HANDLERS: {
3
+ [T in RPCType]: RPCHandler<T>;
4
+ };
@@ -0,0 +1,25 @@
1
+ import { claimTeeBundle } from "../../server/handlers/claimTeeBundle.js";
2
+ import { claimTunnel } from "../../server/handlers/claimTunnel.js";
3
+ import { completeClaimOnChain } from "../../server/handlers/completeClaimOnChain.js";
4
+ import { createClaimOnChain } from "../../server/handlers/createClaimOnChain.js";
5
+ import { createTaskOnMechain } from "../../server/handlers/createTaskOnMechain.js";
6
+ import { createTunnel } from "../../server/handlers/createTunnel.js";
7
+ import { disconnectTunnel } from "../../server/handlers/disconnectTunnel.js";
8
+ import { fetchCertificateBytes } from "../../server/handlers/fetchCertificateBytes.js";
9
+ import { init } from "../../server/handlers/init.js";
10
+ import { toprf } from "../../server/handlers/toprf.js";
11
+ const HANDLERS = {
12
+ createTunnel,
13
+ disconnectTunnel,
14
+ claimTunnel,
15
+ claimTeeBundle,
16
+ init,
17
+ createClaimOnChain,
18
+ completeClaimOnChain,
19
+ toprf,
20
+ createTaskOnMechain,
21
+ fetchCertificateBytes
22
+ };
23
+ export {
24
+ HANDLERS
25
+ };
@@ -0,0 +1,2 @@
1
+ import type { RPCHandler } from '#src/types/index.ts';
2
+ export declare const init: RPCHandler<'init'>;