@reclaimprotocol/attestor-core 5.0.1-beta.2 → 5.0.1-beta.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/browser/resources/attestor-browser.min.mjs +4512 -0
- package/lib/avs/abis/avsDirectoryABI.js +338 -341
- package/lib/avs/abis/delegationABI.js +1 -4
- package/lib/avs/abis/registryABI.js +719 -722
- package/lib/avs/client/create-claim-on-avs.js +129 -157
- package/lib/avs/config.js +18 -24
- package/lib/avs/contracts/ReclaimServiceManager.js +1 -0
- package/lib/avs/contracts/common.js +1 -0
- package/lib/avs/contracts/factories/ReclaimServiceManager__factory.js +1139 -1156
- package/lib/avs/contracts/factories/index.js +4 -4
- package/lib/avs/contracts/index.js +2 -6
- package/lib/avs/types/index.js +1 -0
- package/lib/avs/utils/contracts.js +30 -50
- package/lib/avs/utils/register.js +75 -70
- package/lib/avs/utils/tasks.js +38 -45
- package/lib/client/create-claim.js +402 -431
- package/lib/client/tunnels/make-rpc-tcp-tunnel.js +46 -48
- package/lib/client/tunnels/make-rpc-tls-tunnel.js +125 -121
- package/lib/client/utils/attestor-pool.js +23 -22
- package/lib/client/utils/client-socket.js +86 -109
- package/lib/client/utils/message-handler.js +79 -89
- package/lib/config/index.js +40 -58
- package/lib/external-rpc/benchmark.js +61 -74
- package/lib/external-rpc/event-bus.js +12 -15
- package/lib/external-rpc/handle-incoming-msg.js +216 -225
- package/lib/external-rpc/jsc-polyfills/1.js +70 -68
- package/lib/external-rpc/jsc-polyfills/2.js +17 -12
- package/lib/external-rpc/jsc-polyfills/event.js +10 -15
- package/lib/external-rpc/jsc-polyfills/index.js +2 -2
- package/lib/external-rpc/jsc-polyfills/ws.js +77 -79
- package/lib/external-rpc/setup-browser.js +28 -28
- package/lib/external-rpc/setup-jsc.js +17 -17
- package/lib/external-rpc/types.js +1 -0
- package/lib/external-rpc/utils.js +89 -89
- package/lib/external-rpc/zk.js +55 -50
- package/lib/index.js +2 -6
- package/lib/mechain/abis/governanceABI.js +457 -460
- package/lib/mechain/abis/taskABI.js +502 -505
- package/lib/mechain/client/create-claim-on-mechain.js +24 -29
- package/lib/mechain/constants/index.js +3 -8
- package/lib/mechain/types/index.js +1 -0
- package/lib/proto/api.js +4200 -4087
- package/lib/proto/tee-bundle.js +1261 -1241
- package/lib/providers/http/index.js +616 -603
- package/lib/providers/http/patch-parse5-tree.js +27 -29
- package/lib/providers/http/utils.js +289 -248
- package/lib/providers/index.js +3 -6
- package/lib/server/create-server.js +89 -91
- package/lib/server/handlers/claimTeeBundle.js +231 -211
- package/lib/server/handlers/claimTunnel.js +66 -73
- package/lib/server/handlers/completeClaimOnChain.js +20 -25
- package/lib/server/handlers/createClaimOnChain.js +21 -27
- package/lib/server/handlers/createTaskOnMechain.js +40 -50
- package/lib/server/handlers/createTunnel.js +85 -90
- package/lib/server/handlers/disconnectTunnel.js +4 -7
- package/lib/server/handlers/fetchCertificateBytes.js +37 -53
- package/lib/server/handlers/index.js +21 -24
- package/lib/server/handlers/init.js +27 -28
- package/lib/server/handlers/toprf.js +13 -16
- package/lib/server/socket.js +97 -100
- package/lib/server/tunnels/make-tcp-tunnel.js +161 -186
- package/lib/server/utils/apm.js +32 -25
- package/lib/server/utils/assert-valid-claim-request.js +305 -334
- package/lib/server/utils/config-env.js +2 -2
- package/lib/server/utils/dns.js +12 -18
- package/lib/server/utils/gcp-attestation.js +233 -181
- package/lib/server/utils/generics.d.ts +1 -1
- package/lib/server/utils/generics.js +43 -37
- package/lib/server/utils/iso.js +253 -256
- package/lib/server/utils/keep-alive.js +36 -36
- package/lib/server/utils/nitro-attestation.js +295 -220
- package/lib/server/utils/oprf-raw.js +48 -55
- package/lib/server/utils/process-handshake.js +200 -218
- package/lib/server/utils/proxy-session.js +5 -5
- package/lib/server/utils/tee-oprf-mpc-verification.js +82 -78
- package/lib/server/utils/tee-oprf-verification.js +165 -142
- package/lib/server/utils/tee-transcript-reconstruction.js +176 -129
- package/lib/server/utils/tee-verification.js +397 -334
- package/lib/server/utils/validation.js +30 -37
- package/lib/types/bgp.js +1 -0
- package/lib/types/claims.js +1 -0
- package/lib/types/client.js +1 -0
- package/lib/types/general.js +1 -0
- package/lib/types/handlers.js +1 -0
- package/lib/types/providers.d.ts +3 -2
- package/lib/types/providers.gen.js +9 -15
- package/lib/types/providers.js +1 -0
- package/lib/types/rpc.js +1 -0
- package/lib/types/signatures.d.ts +1 -2
- package/lib/types/signatures.js +1 -0
- package/lib/types/tunnel.js +1 -0
- package/lib/types/zk.js +1 -0
- package/lib/utils/auth.js +54 -66
- package/lib/utils/b64-json.js +15 -15
- package/lib/utils/bgp-listener.js +107 -111
- package/lib/utils/claims.js +89 -80
- package/lib/utils/env.js +13 -17
- package/lib/utils/error.js +43 -47
- package/lib/utils/generics.js +284 -235
- package/lib/utils/http-parser.js +232 -187
- package/lib/utils/logger.js +80 -71
- package/lib/utils/prepare-packets.js +69 -67
- package/lib/utils/redactions.js +163 -121
- package/lib/utils/retries.js +22 -24
- package/lib/utils/signatures/eth.js +29 -28
- package/lib/utils/signatures/index.js +5 -10
- package/lib/utils/socket-base.js +84 -88
- package/lib/utils/tls.js +28 -28
- package/lib/utils/ws.js +19 -19
- package/lib/utils/zk.js +542 -582
- package/package.json +12 -5
- package/lib/external-rpc/global.d.js +0 -0
- package/lib/scripts/build-browser.d.ts +0 -1
- package/lib/scripts/build-jsc.d.ts +0 -1
- package/lib/scripts/build-lib.d.ts +0 -1
- package/lib/scripts/check-avs-registration.d.ts +0 -1
- package/lib/scripts/check-avs-registration.js +0 -28
- package/lib/scripts/fallbacks/crypto.d.ts +0 -1
- package/lib/scripts/fallbacks/crypto.js +0 -4
- package/lib/scripts/fallbacks/empty.d.ts +0 -3
- package/lib/scripts/fallbacks/empty.js +0 -4
- package/lib/scripts/fallbacks/re2.d.ts +0 -1
- package/lib/scripts/fallbacks/re2.js +0 -7
- package/lib/scripts/fallbacks/snarkjs.d.ts +0 -1
- package/lib/scripts/fallbacks/snarkjs.js +0 -10
- package/lib/scripts/fallbacks/stwo.d.ts +0 -6
- package/lib/scripts/fallbacks/stwo.js +0 -159
- package/lib/scripts/generate-provider-types.d.ts +0 -5
- package/lib/scripts/generate-provider-types.js +0 -101
- package/lib/scripts/generate-receipt.d.ts +0 -9
- package/lib/scripts/generate-receipt.js +0 -101
- package/lib/scripts/generate-toprf-keys.d.ts +0 -1
- package/lib/scripts/generate-toprf-keys.js +0 -24
- package/lib/scripts/jsc-cli-rpc.d.ts +0 -1
- package/lib/scripts/jsc-cli-rpc.js +0 -35
- package/lib/scripts/register-avs-operator.d.ts +0 -1
- package/lib/scripts/register-avs-operator.js +0 -3
- package/lib/scripts/start-server.d.ts +0 -1
- package/lib/scripts/start-server.js +0 -11
- package/lib/scripts/update-avs-metadata.d.ts +0 -1
- package/lib/scripts/update-avs-metadata.js +0 -20
- package/lib/scripts/utils.d.ts +0 -1
- package/lib/scripts/utils.js +0 -10
- package/lib/scripts/whitelist-operator.d.ts +0 -1
- package/lib/scripts/whitelist-operator.js +0 -16
package/lib/server/socket.js
CHANGED
|
@@ -1,112 +1,109 @@
|
|
|
1
|
-
import { promisify } from
|
|
1
|
+
import { promisify } from 'util';
|
|
2
2
|
import { handleMessage } from "../client/utils/message-handler.js";
|
|
3
3
|
import { DEFAULT_RPC_TIMEOUT_MS } from "../config/index.js";
|
|
4
|
-
import { HANDLERS } from "
|
|
5
|
-
import { getApm } from "
|
|
6
|
-
import { getInitialMessagesFromQuery } from "
|
|
4
|
+
import { HANDLERS } from "./handlers/index.js";
|
|
5
|
+
import { getApm } from "./utils/apm.js";
|
|
6
|
+
import { getInitialMessagesFromQuery } from "./utils/generics.js";
|
|
7
7
|
import { AttestorError, generateSessionId } from "../utils/index.js";
|
|
8
8
|
import { AttestorSocket } from "../utils/socket-base.js";
|
|
9
|
-
class AttestorServerSocket extends AttestorSocket {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
export class AttestorServerSocket extends AttestorSocket {
|
|
10
|
+
tunnels = {};
|
|
11
|
+
sessionId;
|
|
12
|
+
bgpListener;
|
|
13
|
+
constructor(socket, sessionId, bgpListener, logger) {
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
super(socket, {}, logger);
|
|
16
|
+
this.sessionId = sessionId;
|
|
17
|
+
this.bgpListener = bgpListener;
|
|
18
|
+
// handle RPC requests
|
|
19
|
+
this.addEventListener('rpc-request', handleRpcRequest.bind(this));
|
|
20
|
+
// forward packets to the appropriate tunnel
|
|
21
|
+
this.addEventListener('tunnel-message', handleTunnelMessage.bind(this));
|
|
22
|
+
// close all tunnels when the connection is terminated
|
|
23
|
+
// since this tunnel can no longer be written to
|
|
24
|
+
this.addEventListener('connection-terminated', () => {
|
|
25
|
+
for (const tunnelId in this.tunnels) {
|
|
26
|
+
const tunnel = this.tunnels[tunnelId];
|
|
27
|
+
void tunnel.close(new Error('WS session terminated'));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
getTunnel(tunnelId) {
|
|
21
32
|
const tunnel = this.tunnels[tunnelId];
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
getTunnel(tunnelId) {
|
|
27
|
-
const tunnel = this.tunnels[tunnelId];
|
|
28
|
-
if (!tunnel) {
|
|
29
|
-
throw new AttestorError(
|
|
30
|
-
"ERROR_NOT_FOUND",
|
|
31
|
-
`Tunnel "${tunnelId}" not found`
|
|
32
|
-
);
|
|
33
|
+
if (!tunnel) {
|
|
34
|
+
throw new AttestorError('ERROR_NOT_FOUND', `Tunnel "${tunnelId}" not found`);
|
|
35
|
+
}
|
|
36
|
+
return tunnel;
|
|
33
37
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
await client.terminateConnection(
|
|
64
|
-
err instanceof AttestorError ? err : AttestorError.badRequest(err.message)
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
return;
|
|
38
|
+
removeTunnel(tunnelId) {
|
|
39
|
+
delete this.tunnels[tunnelId];
|
|
40
|
+
}
|
|
41
|
+
static async acceptConnection(socket, { req, logger, bgpListener }) {
|
|
42
|
+
// promisify ws.send -- so the sendMessage method correctly
|
|
43
|
+
// awaits the send operation
|
|
44
|
+
const bindSend = socket.send.bind(socket);
|
|
45
|
+
socket.send = promisify(bindSend);
|
|
46
|
+
const sessionId = generateSessionId();
|
|
47
|
+
logger = logger.child({ sessionId });
|
|
48
|
+
const client = new AttestorServerSocket(socket, sessionId, bgpListener, logger);
|
|
49
|
+
try {
|
|
50
|
+
const initMsgs = getInitialMessagesFromQuery(req);
|
|
51
|
+
logger.trace({ initMsgs: initMsgs.length }, 'new connection, validating...');
|
|
52
|
+
for (const msg of initMsgs) {
|
|
53
|
+
await handleMessage.call(client, msg);
|
|
54
|
+
}
|
|
55
|
+
logger.debug('connection accepted');
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
logger.error({ err }, 'error in new connection');
|
|
59
|
+
if (client.isOpen) {
|
|
60
|
+
await client.terminateConnection(err instanceof AttestorError
|
|
61
|
+
? err
|
|
62
|
+
: AttestorError.badRequest(err.message));
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
return client;
|
|
68
67
|
}
|
|
69
|
-
return client;
|
|
70
|
-
}
|
|
71
68
|
}
|
|
72
69
|
async function handleTunnelMessage({ data: { tunnelId, message } }) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
try {
|
|
71
|
+
const tunnel = this.getTunnel(tunnelId);
|
|
72
|
+
await tunnel.write(message);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
this.logger?.error({ err, tunnelId }, 'error writing to tunnel');
|
|
76
|
+
}
|
|
79
77
|
}
|
|
80
78
|
async function handleRpcRequest({ data: { data, requestId, respond, type } }) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
79
|
+
const logger = this.logger.child({ rpc: type, requestId });
|
|
80
|
+
const apm = getApm();
|
|
81
|
+
const tx = apm?.startTransaction(type);
|
|
82
|
+
tx?.setLabel('requestId', requestId);
|
|
83
|
+
tx?.setLabel('sessionId', this.sessionId.toString());
|
|
84
|
+
const userId = this.metadata.auth?.data?.id;
|
|
85
|
+
if (userId) {
|
|
86
|
+
tx?.setLabel('authUserId', userId);
|
|
87
|
+
}
|
|
88
|
+
const timeout = setTimeout(() => {
|
|
89
|
+
logger.warn({ type, requestId }, 'RPC took too long to respond');
|
|
90
|
+
}, DEFAULT_RPC_TIMEOUT_MS);
|
|
91
|
+
try {
|
|
92
|
+
logger.debug({ data }, 'handling RPC request');
|
|
93
|
+
const handler = HANDLERS[type];
|
|
94
|
+
const res = await handler(data, { client: this, logger, tx });
|
|
95
|
+
respond(res);
|
|
96
|
+
logger.debug({ res }, 'handled RPC request');
|
|
97
|
+
tx?.setOutcome('success');
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
logger.error({ err }, 'error in RPC request');
|
|
101
|
+
respond(AttestorError.fromError(err));
|
|
102
|
+
tx?.setOutcome('failure');
|
|
103
|
+
apm?.captureError(err, { parent: tx });
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
clearTimeout(timeout);
|
|
107
|
+
tx?.end();
|
|
108
|
+
}
|
|
109
109
|
}
|
|
110
|
-
export {
|
|
111
|
-
AttestorServerSocket
|
|
112
|
-
};
|
|
@@ -1,202 +1,177 @@
|
|
|
1
|
-
import { HttpsProxyAgent } from
|
|
2
|
-
import { Socket } from
|
|
1
|
+
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
2
|
+
import { Socket } from 'net';
|
|
3
3
|
import { CONNECTION_TIMEOUT_MS } from "../../config/index.js";
|
|
4
|
-
import { resolveHostnames } from "
|
|
5
|
-
import { isValidCountryCode } from "
|
|
6
|
-
import { isValidProxySessionId } from "
|
|
4
|
+
import { resolveHostnames } from "../utils/dns.js";
|
|
5
|
+
import { isValidCountryCode } from "../utils/iso.js";
|
|
6
|
+
import { isValidProxySessionId } from "../utils/proxy-session.js";
|
|
7
7
|
import { getEnvVariable } from "../../utils/env.js";
|
|
8
8
|
import { AttestorError } from "../../utils/index.js";
|
|
9
|
-
const HTTPS_PROXY_URL = getEnvVariable(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
transcript
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
9
|
+
const HTTPS_PROXY_URL = getEnvVariable('HTTPS_PROXY_URL');
|
|
10
|
+
/**
|
|
11
|
+
* Builds a TCP tunnel to the given host and port.
|
|
12
|
+
* If a geolocation is provided -- an HTTPS proxy is used
|
|
13
|
+
* to connect to the host.
|
|
14
|
+
* If a proxySessionId is provided -- a static ip is used with HTTPS proxy
|
|
15
|
+
* across multiple requests with this same proxySessionId.
|
|
16
|
+
*
|
|
17
|
+
* HTTPS proxy essentially creates an opaque tunnel to the
|
|
18
|
+
* host using the CONNECT method. Any data can be sent through
|
|
19
|
+
* this tunnel to the end host.
|
|
20
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT
|
|
21
|
+
*
|
|
22
|
+
* The tunnel also retains a transcript of all messages sent and received.
|
|
23
|
+
*/
|
|
24
|
+
export const makeTcpTunnel = async ({ onClose, onMessage, logger, ...opts }) => {
|
|
25
|
+
const transcript = [];
|
|
26
|
+
const socket = await connectTcp({ ...opts, logger });
|
|
27
|
+
let closed = false;
|
|
28
|
+
socket.on('data', message => {
|
|
29
|
+
if (closed) {
|
|
30
|
+
logger.warn('socket is closed, dropping message');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
onMessage?.(message);
|
|
34
|
+
transcript.push({ sender: 'server', message });
|
|
35
|
+
});
|
|
36
|
+
// socket.once('error', onSocketClose)
|
|
37
|
+
socket.once('close', () => onSocketClose(undefined));
|
|
38
|
+
return {
|
|
39
|
+
socket,
|
|
40
|
+
transcript,
|
|
41
|
+
createRequest: opts,
|
|
42
|
+
async write(data) {
|
|
43
|
+
transcript.push({ sender: 'client', message: data });
|
|
44
|
+
await new Promise((resolve, reject) => {
|
|
45
|
+
socket.write(data, err => {
|
|
46
|
+
if (err) {
|
|
47
|
+
reject(err);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
resolve();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
close(err) {
|
|
56
|
+
if (closed) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
socket.destroy(err);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function onSocketClose(err) {
|
|
63
|
+
if (closed) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
logger.debug({ err }, 'closing socket');
|
|
67
|
+
closed = true;
|
|
68
|
+
onClose?.(err);
|
|
69
|
+
onClose = undefined;
|
|
54
70
|
}
|
|
55
|
-
logger.debug({ err }, "closing socket");
|
|
56
|
-
closed = true;
|
|
57
|
-
onClose?.(err);
|
|
58
|
-
onClose = void 0;
|
|
59
|
-
}
|
|
60
71
|
};
|
|
61
72
|
async function connectTcp({ host, port, geoLocation, proxySessionId, logger }) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
73
|
+
let connectTimeout;
|
|
74
|
+
let socket;
|
|
75
|
+
try {
|
|
76
|
+
await new Promise(async (resolve, reject) => {
|
|
77
|
+
try {
|
|
78
|
+
// add a timeout to ensure the connection doesn't hang
|
|
79
|
+
// and cause our gateway to send out a 504
|
|
80
|
+
connectTimeout = setTimeout(() => reject(new AttestorError('ERROR_NETWORK_ERROR', 'Server connection timed out')), CONNECTION_TIMEOUT_MS);
|
|
81
|
+
socket = await getSocket({
|
|
82
|
+
host,
|
|
83
|
+
port,
|
|
84
|
+
geoLocation,
|
|
85
|
+
proxySessionId,
|
|
86
|
+
logger
|
|
87
|
+
});
|
|
88
|
+
socket.once('connect', resolve);
|
|
89
|
+
socket.once('error', reject);
|
|
90
|
+
socket.once('end', () => (reject(new AttestorError('ERROR_NETWORK_ERROR', 'connection closed'))));
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
reject(err);
|
|
94
|
+
}
|
|
82
95
|
});
|
|
83
|
-
|
|
84
|
-
socket
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
logger.debug({ addr: `${host}:${port}` }, "connected");
|
|
96
|
-
return socket;
|
|
97
|
-
} catch (err) {
|
|
98
|
-
socket?.end();
|
|
99
|
-
throw err;
|
|
100
|
-
} finally {
|
|
101
|
-
clearTimeout(connectTimeout);
|
|
102
|
-
}
|
|
96
|
+
logger.debug({ addr: `${host}:${port}` }, 'connected');
|
|
97
|
+
return socket;
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
socket?.end();
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
clearTimeout(connectTimeout);
|
|
105
|
+
}
|
|
103
106
|
}
|
|
104
107
|
async function getSocket(opts) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
} catch (err) {
|
|
109
|
-
if (!(err instanceof AttestorError) || err.data?.code !== 403) {
|
|
110
|
-
throw err;
|
|
108
|
+
const { logger } = opts;
|
|
109
|
+
try {
|
|
110
|
+
return await _getSocket(opts);
|
|
111
111
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)
|
|
125
|
-
|
|
112
|
+
catch (err) {
|
|
113
|
+
// see if the proxy is blocking the connection
|
|
114
|
+
// due to their own arbitrary rules,
|
|
115
|
+
// if so -- we resolve hostname first &
|
|
116
|
+
// connect directly via address to
|
|
117
|
+
// avoid proxy knowing which host we're connecting to
|
|
118
|
+
if (!(err instanceof AttestorError)
|
|
119
|
+
|| err.data?.code !== 403) {
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
const addrs = await resolveHostnames(opts.host);
|
|
123
|
+
logger.info({ addrs, host: opts.host }, 'failed to connect due to restricted IP, trying via raw addr');
|
|
124
|
+
for (const addr of addrs) {
|
|
125
|
+
try {
|
|
126
|
+
return await _getSocket({ ...opts, host: addr });
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
logger.error({ addr, err }, 'failed to connect to host');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
throw err;
|
|
126
133
|
}
|
|
127
|
-
throw err;
|
|
128
|
-
}
|
|
129
134
|
}
|
|
130
|
-
async function _getSocket({
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
proxySessionId
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
if (proxySessionId && !isValidProxySessionId(proxySessionId)) {
|
|
157
|
-
throw AttestorError.badRequest(
|
|
158
|
-
`proxySessionId "${proxySessionId}" is invalid. Must be a lowercase alphanumeric string of length 8-14 characters. eg. "mystring12345", "something1234".`,
|
|
159
|
-
{ proxySessionId }
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
const agentUrl = HTTPS_PROXY_URL.replace(
|
|
163
|
-
"{{geoLocation}}",
|
|
164
|
-
geoLocation?.toLowerCase() || ""
|
|
165
|
-
).replace(
|
|
166
|
-
"{{proxySessionId}}",
|
|
167
|
-
proxySessionId ? `-session-${proxySessionId}` : ""
|
|
168
|
-
);
|
|
169
|
-
const agent = new HttpsProxyAgent(agentUrl);
|
|
170
|
-
const waitForProxyRes = new Promise((resolve) => {
|
|
171
|
-
socket.once("proxyConnect", resolve);
|
|
172
|
-
});
|
|
173
|
-
const proxySocket = await agent.connect(
|
|
135
|
+
async function _getSocket({ host, port, geoLocation, proxySessionId, logger }) {
|
|
136
|
+
const socket = new Socket();
|
|
137
|
+
if ((proxySessionId || geoLocation) && !HTTPS_PROXY_URL) {
|
|
138
|
+
logger.warn({ geoLocation, proxySessionId }, 'geoLocation or proxySessionId provided but no proxy URL found');
|
|
139
|
+
geoLocation = '';
|
|
140
|
+
proxySessionId = '';
|
|
141
|
+
}
|
|
142
|
+
if (!geoLocation && !proxySessionId) {
|
|
143
|
+
socket.connect({ host, port, });
|
|
144
|
+
return socket;
|
|
145
|
+
}
|
|
146
|
+
if (!isValidCountryCode(geoLocation)) {
|
|
147
|
+
throw AttestorError.badRequest(`Geolocation "${geoLocation}" is invalid. Must be 2 letter ISO country code`, { geoLocation });
|
|
148
|
+
}
|
|
149
|
+
if (proxySessionId && !isValidProxySessionId(proxySessionId)) {
|
|
150
|
+
throw AttestorError.badRequest(`proxySessionId "${proxySessionId}" is invalid. Must be a lowercase alphanumeric string of length 8-14 characters. eg. "mystring12345", "something1234".`, { proxySessionId });
|
|
151
|
+
}
|
|
152
|
+
const agentUrl = HTTPS_PROXY_URL.replace('{{geoLocation}}', geoLocation?.toLowerCase() || '').replace('{{proxySessionId}}', proxySessionId ? `-session-${proxySessionId}` : '');
|
|
153
|
+
const agent = new HttpsProxyAgent(agentUrl);
|
|
154
|
+
const waitForProxyRes = new Promise(resolve => {
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
socket.once('proxyConnect', resolve);
|
|
157
|
+
});
|
|
158
|
+
const proxySocket = await agent.connect(
|
|
174
159
|
// ignore, because https-proxy-agent
|
|
175
160
|
// expects an http request object
|
|
176
161
|
// @ts-ignore
|
|
177
|
-
socket,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
process.nextTick(() => {
|
|
196
|
-
proxySocket.emit("connect");
|
|
197
|
-
});
|
|
198
|
-
return proxySocket;
|
|
162
|
+
socket, { host, port, timeout: CONNECTION_TIMEOUT_MS });
|
|
163
|
+
const res = await waitForProxyRes;
|
|
164
|
+
if (res.statusCode !== 200) {
|
|
165
|
+
logger.error({ geoLocation, proxySessionId, res }, 'Proxy geo location or session id failed');
|
|
166
|
+
throw new AttestorError('ERROR_PROXY_ERROR', `Proxy via ${geoLocation ? `geo location "${geoLocation}"` : ''}${geoLocation && proxySessionId ? ', or ' : ''}${proxySessionId ? `session id "${proxySessionId}"` : ''} failed with status code: ${res.statusCode}, message: ${res.statusText}`, {
|
|
167
|
+
code: res.statusCode,
|
|
168
|
+
message: res.statusText,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
process.nextTick(() => {
|
|
172
|
+
// ensure connect event is emitted
|
|
173
|
+
// so it can be captured by the caller
|
|
174
|
+
proxySocket.emit('connect');
|
|
175
|
+
});
|
|
176
|
+
return proxySocket;
|
|
199
177
|
}
|
|
200
|
-
export {
|
|
201
|
-
makeTcpTunnel
|
|
202
|
-
};
|
package/lib/server/utils/apm.js
CHANGED
|
@@ -1,29 +1,36 @@
|
|
|
1
|
-
import ElasticAPM from
|
|
1
|
+
import ElasticAPM from 'elastic-apm-node';
|
|
2
2
|
import { getEnvVariable } from "../../utils/env.js";
|
|
3
3
|
import { logger } from "../../utils/logger.js";
|
|
4
4
|
let apm;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Initialises the APM agent if required,
|
|
7
|
+
* and returns it.
|
|
8
|
+
* If ELASTIC_APM_SERVER_URL & ELASTIC_APM_SECRET_TOKEN
|
|
9
|
+
* are not set will return undefined
|
|
10
|
+
*
|
|
11
|
+
* Utilises the standard env variables mentioned
|
|
12
|
+
* here: https://www.elastic.co/guide/en/apm/agent/nodejs/current/custom-stack.html#custom-stack-advanced-configuration
|
|
13
|
+
*/
|
|
14
|
+
export function getApm() {
|
|
15
|
+
if (!getEnvVariable('ELASTIC_APM_SERVER_URL')
|
|
16
|
+
|| !getEnvVariable('ELASTIC_APM_SECRET_TOKEN')) {
|
|
17
|
+
logger.info('ELASTIC_APM_SERVER_URL or ELASTIC_APM_SECRET_TOKEN not found'
|
|
18
|
+
+ ' in env, APM agent not initialised');
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
if (!apm) {
|
|
22
|
+
const sampleRate = +(getEnvVariable('ELASTIC_APM_SAMPLE_RATE')
|
|
23
|
+
|| '0.1');
|
|
24
|
+
apm = ElasticAPM.start({
|
|
25
|
+
serviceName: 'reclaim_attestor',
|
|
26
|
+
serviceVersion: '4.0.0',
|
|
27
|
+
transactionSampleRate: sampleRate,
|
|
28
|
+
instrumentIncomingHTTPRequests: true,
|
|
29
|
+
usePathAsTransactionName: true,
|
|
30
|
+
instrument: true,
|
|
31
|
+
captureHeaders: true,
|
|
32
|
+
});
|
|
33
|
+
logger.info('initialised APM agent');
|
|
34
|
+
}
|
|
35
|
+
return apm;
|
|
26
36
|
}
|
|
27
|
-
export {
|
|
28
|
-
getApm
|
|
29
|
-
};
|