@openclaw/gateway-client 2026.8.1-beta.2 → 2026.8.1-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.mts +2 -2
- package/dist/browser.mjs +1 -1
- package/dist/index.d.mts +14 -3
- package/dist/index.mjs +345 -989
- package/dist/{readiness--KX7i8Mq.d.mts → readiness-JllUDKLg.d.mts} +6 -4
- package/dist/readiness.d.mts +1 -1
- package/dist/{session-subscriptions-BTNpXybo.d.mts → session-subscriptions-CKF7acYN.d.mts} +13 -10
- package/dist/{session-subscriptions-uKmTyc3P.mjs → session-subscriptions-OJnDJHPL.mjs} +113 -86
- package/package.json +5 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as resolveGatewayConnectScopes, D as buildDeviceAuthPayloadV3, E as buildDeviceAuthPayload, O as normalizeDeviceMetadataForAuth, S as buildGatewayConnectAuth, T as shouldRetryGatewayWithDeviceToken, _ as GatewayProtocolRequestError, a as createSessionProjection, b as gatewayOriginScope, c as
|
|
1
|
+
import { C as resolveGatewayConnectScopes, D as buildDeviceAuthPayloadV3, E as buildDeviceAuthPayload, O as normalizeDeviceMetadataForAuth, S as buildGatewayConnectAuth, T as shouldRetryGatewayWithDeviceToken, _ as GatewayProtocolRequestError, a as createSessionProjection, b as gatewayOriginScope, c as projectLiveSessionMessage, d as reduceSessionProjectionRunEvent, f as normalizeSessionProjectionRunId, g as GatewayProtocolClient, h as shouldPauseGatewayReconnect, i as resetGatewaySessionMessageSubscriptionCoordinator, l as reconcileSessionProjectionSnapshot, m as readSessionMessageSequence, n as getGatewaySessionMessageSubscriptionCoordinator, o as hasSessionProjectionAcceptedFinal, p as readSessionMessageIdentity, r as releaseGatewaySessionMessageSubscription, s as isLocallyOptimisticSessionMessage, t as GatewaySessionMessageSubscriptionCoordinator, u as reduceSessionProjection, v as GatewayProtocolRequestTimeoutError, w as selectGatewayConnectAuth, x as GatewayBrowserDeviceAuthLifecycle, y as gatewayCredentialScope } from "./session-subscriptions-OJnDJHPL.mjs";
|
|
2
2
|
import { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, getConnectChallengeTimeoutMsFromEnv, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, startGatewayConnectTimeout } from "./timeouts.mjs";
|
|
3
3
|
import { rawDataToString } from "./websocket-data.mjs";
|
|
4
4
|
import { n as startGatewayClientWithReadinessWait, r as waitForEventLoopReady, t as startGatewayClientWhenEventLoopReady } from "./readiness-CrWxd4TI.mjs";
|
|
@@ -9,29 +9,7 @@ import { resolveGatewayStartupRetryAfterMs } from "@openclaw/gateway-protocol/st
|
|
|
9
9
|
import { MIN_CLIENT_PROTOCOL_VERSION, MIN_NODE_PROTOCOL_VERSION, MIN_PROBE_PROTOCOL_VERSION, PROTOCOL_VERSION } from "@openclaw/gateway-protocol/version";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import { WebSocket } from "ws";
|
|
12
|
-
|
|
13
|
-
var __create = Object.create;
|
|
14
|
-
var __defProp = Object.defineProperty;
|
|
15
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
16
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
17
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
18
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
19
|
-
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
20
|
-
var __copyProps = (to, from, except, desc) => {
|
|
21
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
22
|
-
key = keys[i];
|
|
23
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
24
|
-
get: ((k) => from[k]).bind(null, key),
|
|
25
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
return to;
|
|
29
|
-
};
|
|
30
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
31
|
-
value: mod,
|
|
32
|
-
enumerable: true
|
|
33
|
-
}) : target, mod));
|
|
34
|
-
//#endregion
|
|
12
|
+
import ipaddr from "ipaddr.js";
|
|
35
13
|
//#region packages/normalization-core/src/string-coerce.ts
|
|
36
14
|
/** Trims string input and returns null for non-strings or empty strings. */
|
|
37
15
|
function normalizeNullableString(value) {
|
|
@@ -52,966 +30,315 @@ function normalizeLowercaseStringOrEmpty(value) {
|
|
|
52
30
|
return normalizeOptionalLowercaseString(value) ?? "";
|
|
53
31
|
}
|
|
54
32
|
//#endregion
|
|
55
|
-
//#region packages/net-policy/src/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
33
|
+
//#region packages/net-policy/src/redact-sensitive-url.ts
|
|
34
|
+
const SENSITIVE_URL_QUERY_PARAM_NAMES = /* @__PURE__ */ new Set([
|
|
35
|
+
"token",
|
|
36
|
+
"key",
|
|
37
|
+
"api_key",
|
|
38
|
+
"apikey",
|
|
39
|
+
"secret",
|
|
40
|
+
"access_token",
|
|
41
|
+
"auth_token",
|
|
42
|
+
"password",
|
|
43
|
+
"pass",
|
|
44
|
+
"passwd",
|
|
45
|
+
"auth",
|
|
46
|
+
"jwt",
|
|
47
|
+
"session",
|
|
48
|
+
"id_token",
|
|
49
|
+
"code",
|
|
50
|
+
"client_secret",
|
|
51
|
+
"app_secret",
|
|
52
|
+
"hook_token",
|
|
53
|
+
"refresh_token",
|
|
54
|
+
"signature",
|
|
55
|
+
"x_amz_signature",
|
|
56
|
+
"x_amz_security_token",
|
|
57
|
+
"private_key",
|
|
58
|
+
"credential",
|
|
59
|
+
"authorization",
|
|
60
|
+
"sig",
|
|
61
|
+
"x_api_key",
|
|
62
|
+
"x_access_token",
|
|
63
|
+
"x_auth_token"
|
|
64
|
+
]);
|
|
65
|
+
const URL_QUERY_NAME_SEPARATOR_RE = /[\p{C}\p{Z}\u115F\u1160\u3164\uFFA0+]/gu;
|
|
66
|
+
const SUFFIXED_OR_SCOPED_TOKEN_QUERY_PARAM_RE = /(?:^|_)token(?:_[a-f0-9]{16,})?$/u;
|
|
67
|
+
const TELEGRAM_BOT_TOKEN_PATH_RE = /\/bot\d{6,}(?::|%3[aA])[A-Za-z0-9_-]{20,}(?=\/|$)/giu;
|
|
68
|
+
const MAX_NESTED_URL_REDACTION_DEPTH = 8;
|
|
69
|
+
const URL_SCHEME_RE = /(?:^|[^a-z\d+.-])[a-z][a-z\d+.-]{0,31}:/iu;
|
|
70
|
+
const SPECIAL_SCHEME_AUTHORITY_RE = /\b(?:https?|wss?|ftp):[\\/]{0,2}[^\\/?#\s]*/giu;
|
|
71
|
+
const SPECIAL_SCHEME_SPILLED_USERINFO_RE = /\b(?:https?|wss?|ftp):[\\/]{0,2}[^\s]*@[^\\/?#\s]*/giu;
|
|
72
|
+
const PROTOCOL_RELATIVE_AUTHORITY_RE = /[\\/]{2,}[^\\/?#\s]*/gu;
|
|
73
|
+
function redactSensitiveUrlPath(value) {
|
|
74
|
+
return value.replace(TELEGRAM_BOT_TOKEN_PATH_RE, "/bot***");
|
|
75
|
+
}
|
|
76
|
+
function normalizeUrlQueryParamName(name) {
|
|
77
|
+
let current = name.replace(URL_QUERY_NAME_SEPARATOR_RE, "");
|
|
78
|
+
for (let depth = 0; depth <= MAX_NESTED_URL_REDACTION_DEPTH; depth += 1) {
|
|
79
|
+
let decoded;
|
|
80
|
+
try {
|
|
81
|
+
decoded = decodeURIComponent(current).replace(URL_QUERY_NAME_SEPARATOR_RE, "");
|
|
82
|
+
} catch {
|
|
102
83
|
return {
|
|
103
|
-
|
|
104
|
-
|
|
84
|
+
value: normalizeLowercaseStringOrEmpty(current).replaceAll("-", "_"),
|
|
85
|
+
unresolvedEncoding: current.includes("%")
|
|
105
86
|
};
|
|
106
87
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
88
|
+
if (decoded === current) return {
|
|
89
|
+
value: normalizeLowercaseStringOrEmpty(current).replaceAll("-", "_"),
|
|
90
|
+
unresolvedEncoding: false
|
|
91
|
+
};
|
|
92
|
+
current = decoded;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
value: normalizeLowercaseStringOrEmpty(current).replaceAll("-", "_"),
|
|
96
|
+
unresolvedEncoding: current.includes("%")
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function looksLikeNestedUrlValue(value) {
|
|
100
|
+
if (URL_SCHEME_RE.test(value)) return true;
|
|
101
|
+
const forwardAuthorityIndex = value.indexOf("//");
|
|
102
|
+
const backwardAuthorityIndex = value.indexOf("\\\\");
|
|
103
|
+
const authorityIndex = forwardAuthorityIndex < 0 ? backwardAuthorityIndex : backwardAuthorityIndex < 0 ? forwardAuthorityIndex : Math.min(forwardAuthorityIndex, backwardAuthorityIndex);
|
|
104
|
+
if (authorityIndex >= 0 && value.includes("@", authorityIndex + 2)) return true;
|
|
105
|
+
const queryIndex = value.search(/[?&]/u);
|
|
106
|
+
if (queryIndex >= 0 && value.includes("=", queryIndex + 1)) return true;
|
|
107
|
+
const fragmentIndex = value.indexOf("#");
|
|
108
|
+
if (fragmentIndex >= 0 && value.includes("=", fragmentIndex + 1)) return true;
|
|
109
|
+
return /%[\da-f]{2}/iu.test(value);
|
|
110
|
+
}
|
|
111
|
+
/** True for auth-like URL query parameter names that should be redacted. */
|
|
112
|
+
function isSensitiveUrlQueryParamName$1(name) {
|
|
113
|
+
const normalized = normalizeUrlQueryParamName(name);
|
|
114
|
+
return normalized.unresolvedEncoding || SENSITIVE_URL_QUERY_PARAM_NAMES.has(normalized.value) || SUFFIXED_OR_SCOPED_TOKEN_QUERY_PARAM_RE.test(normalized.value);
|
|
115
|
+
}
|
|
116
|
+
function redactDirectSensitiveUrl(value) {
|
|
117
|
+
try {
|
|
118
|
+
const parsed = new URL(value);
|
|
119
|
+
let mutated = false;
|
|
120
|
+
const redactedPath = redactSensitiveUrlPath(parsed.pathname);
|
|
121
|
+
if (redactedPath !== parsed.pathname) {
|
|
122
|
+
parsed.pathname = redactedPath;
|
|
123
|
+
mutated = true;
|
|
119
124
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
throw new Error(`ipaddr: cannot parse ${string} as octal`);
|
|
125
|
-
}
|
|
126
|
-
return parseInt(string, 10);
|
|
125
|
+
if (parsed.username || parsed.password) {
|
|
126
|
+
parsed.username = parsed.username ? "***" : "";
|
|
127
|
+
parsed.password = parsed.password ? "***" : "";
|
|
128
|
+
mutated = true;
|
|
127
129
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
for (const key of Array.from(parsed.searchParams.keys())) if (isSensitiveUrlQueryParamName$1(key)) {
|
|
131
|
+
parsed.searchParams.set(key, "***");
|
|
132
|
+
mutated = true;
|
|
131
133
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
]), 8]],
|
|
150
|
-
broadcast: [[new IPv4([
|
|
151
|
-
255,
|
|
152
|
-
255,
|
|
153
|
-
255,
|
|
154
|
-
255
|
|
155
|
-
]), 32]],
|
|
156
|
-
multicast: [[new IPv4([
|
|
157
|
-
224,
|
|
158
|
-
0,
|
|
159
|
-
0,
|
|
160
|
-
0
|
|
161
|
-
]), 4]],
|
|
162
|
-
linkLocal: [[new IPv4([
|
|
163
|
-
169,
|
|
164
|
-
254,
|
|
165
|
-
0,
|
|
166
|
-
0
|
|
167
|
-
]), 16]],
|
|
168
|
-
loopback: [[new IPv4([
|
|
169
|
-
127,
|
|
170
|
-
0,
|
|
171
|
-
0,
|
|
172
|
-
0
|
|
173
|
-
]), 8]],
|
|
174
|
-
carrierGradeNat: [[new IPv4([
|
|
175
|
-
100,
|
|
176
|
-
64,
|
|
177
|
-
0,
|
|
178
|
-
0
|
|
179
|
-
]), 10]],
|
|
180
|
-
"private": [
|
|
181
|
-
[new IPv4([
|
|
182
|
-
10,
|
|
183
|
-
0,
|
|
184
|
-
0,
|
|
185
|
-
0
|
|
186
|
-
]), 8],
|
|
187
|
-
[new IPv4([
|
|
188
|
-
172,
|
|
189
|
-
16,
|
|
190
|
-
0,
|
|
191
|
-
0
|
|
192
|
-
]), 12],
|
|
193
|
-
[new IPv4([
|
|
194
|
-
192,
|
|
195
|
-
168,
|
|
196
|
-
0,
|
|
197
|
-
0
|
|
198
|
-
]), 16]
|
|
199
|
-
],
|
|
200
|
-
reserved: [
|
|
201
|
-
[new IPv4([
|
|
202
|
-
192,
|
|
203
|
-
0,
|
|
204
|
-
0,
|
|
205
|
-
0
|
|
206
|
-
]), 24],
|
|
207
|
-
[new IPv4([
|
|
208
|
-
192,
|
|
209
|
-
0,
|
|
210
|
-
2,
|
|
211
|
-
0
|
|
212
|
-
]), 24],
|
|
213
|
-
[new IPv4([
|
|
214
|
-
192,
|
|
215
|
-
88,
|
|
216
|
-
99,
|
|
217
|
-
0
|
|
218
|
-
]), 24],
|
|
219
|
-
[new IPv4([
|
|
220
|
-
198,
|
|
221
|
-
18,
|
|
222
|
-
0,
|
|
223
|
-
0
|
|
224
|
-
]), 15],
|
|
225
|
-
[new IPv4([
|
|
226
|
-
198,
|
|
227
|
-
51,
|
|
228
|
-
100,
|
|
229
|
-
0
|
|
230
|
-
]), 24],
|
|
231
|
-
[new IPv4([
|
|
232
|
-
203,
|
|
233
|
-
0,
|
|
234
|
-
113,
|
|
235
|
-
0
|
|
236
|
-
]), 24],
|
|
237
|
-
[new IPv4([
|
|
238
|
-
240,
|
|
239
|
-
0,
|
|
240
|
-
0,
|
|
241
|
-
0
|
|
242
|
-
]), 4]
|
|
243
|
-
],
|
|
244
|
-
as112: [[new IPv4([
|
|
245
|
-
192,
|
|
246
|
-
175,
|
|
247
|
-
48,
|
|
248
|
-
0
|
|
249
|
-
]), 24], [new IPv4([
|
|
250
|
-
192,
|
|
251
|
-
31,
|
|
252
|
-
196,
|
|
253
|
-
0
|
|
254
|
-
]), 24]],
|
|
255
|
-
amt: [[new IPv4([
|
|
256
|
-
192,
|
|
257
|
-
52,
|
|
258
|
-
193,
|
|
259
|
-
0
|
|
260
|
-
]), 24]]
|
|
261
|
-
};
|
|
262
|
-
IPv4.prototype.kind = function() {
|
|
263
|
-
return "ipv4";
|
|
264
|
-
};
|
|
265
|
-
IPv4.prototype.match = function(other, cidrRange) {
|
|
266
|
-
let ref;
|
|
267
|
-
if (cidrRange === void 0) {
|
|
268
|
-
ref = other;
|
|
269
|
-
other = ref[0];
|
|
270
|
-
cidrRange = ref[1];
|
|
271
|
-
}
|
|
272
|
-
if (other.kind() !== "ipv4") throw new Error("ipaddr: cannot match ipv4 address with non-ipv4 one");
|
|
273
|
-
return matchCIDR(this.octets, other.octets, 8, cidrRange);
|
|
274
|
-
};
|
|
275
|
-
IPv4.prototype.prefixLengthFromSubnetMask = function() {
|
|
276
|
-
let cidr = 0;
|
|
277
|
-
let stop = false;
|
|
278
|
-
const zerotable = {
|
|
279
|
-
0: 8,
|
|
280
|
-
128: 7,
|
|
281
|
-
192: 6,
|
|
282
|
-
224: 5,
|
|
283
|
-
240: 4,
|
|
284
|
-
248: 3,
|
|
285
|
-
252: 2,
|
|
286
|
-
254: 1,
|
|
287
|
-
255: 0
|
|
288
|
-
};
|
|
289
|
-
let i, octet, zeros;
|
|
290
|
-
for (i = 3; i >= 0; i -= 1) {
|
|
291
|
-
octet = this.octets[i];
|
|
292
|
-
if (octet in zerotable) {
|
|
293
|
-
zeros = zerotable[octet];
|
|
294
|
-
if (stop && zeros !== 0) return null;
|
|
295
|
-
if (zeros !== 8) stop = true;
|
|
296
|
-
cidr += zeros;
|
|
297
|
-
} else return null;
|
|
298
|
-
}
|
|
299
|
-
return 32 - cidr;
|
|
300
|
-
};
|
|
301
|
-
IPv4.prototype.range = function() {
|
|
302
|
-
return ipaddr.subnetMatch(this, this.SpecialRanges);
|
|
303
|
-
};
|
|
304
|
-
IPv4.prototype.toByteArray = function() {
|
|
305
|
-
return this.octets.slice(0);
|
|
306
|
-
};
|
|
307
|
-
IPv4.prototype.toIPv4MappedAddress = function() {
|
|
308
|
-
return ipaddr.IPv6.parse(`::ffff:${this.toString()}`);
|
|
309
|
-
};
|
|
310
|
-
IPv4.prototype.toNormalizedString = function() {
|
|
311
|
-
return this.toString();
|
|
312
|
-
};
|
|
313
|
-
IPv4.prototype.toString = function() {
|
|
314
|
-
return this.octets.join(".");
|
|
315
|
-
};
|
|
316
|
-
return IPv4;
|
|
317
|
-
})();
|
|
318
|
-
ipaddr.IPv4.broadcastAddressFromCIDR = function(string) {
|
|
319
|
-
try {
|
|
320
|
-
const cidr = this.parseCIDR(string);
|
|
321
|
-
const ipInterfaceOctets = cidr[0].toByteArray();
|
|
322
|
-
const subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray();
|
|
323
|
-
const octets = [];
|
|
324
|
-
let i = 0;
|
|
325
|
-
while (i < 4) {
|
|
326
|
-
octets.push(parseInt(ipInterfaceOctets[i], 10) | parseInt(subnetMaskOctets[i], 10) ^ 255);
|
|
327
|
-
i++;
|
|
328
|
-
}
|
|
329
|
-
return new this(octets);
|
|
330
|
-
} catch (e) {
|
|
331
|
-
throw new Error("ipaddr: the address does not have IPv4 CIDR format");
|
|
332
|
-
}
|
|
333
|
-
};
|
|
334
|
-
ipaddr.IPv4.isIPv4 = function(string) {
|
|
335
|
-
return this.parser(string) !== null;
|
|
336
|
-
};
|
|
337
|
-
ipaddr.IPv4.isValid = function(string) {
|
|
338
|
-
try {
|
|
339
|
-
new this(this.parser(string));
|
|
340
|
-
return true;
|
|
341
|
-
} catch (e) {
|
|
342
|
-
return false;
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
ipaddr.IPv4.isValidCIDR = function(string) {
|
|
346
|
-
try {
|
|
347
|
-
this.parseCIDR(string);
|
|
348
|
-
return true;
|
|
349
|
-
} catch (e) {
|
|
350
|
-
return false;
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
ipaddr.IPv4.isValidFourPartDecimal = function(string) {
|
|
354
|
-
if (ipaddr.IPv4.isValid(string) && string.match(/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){3}$/)) return true;
|
|
355
|
-
else return false;
|
|
356
|
-
};
|
|
357
|
-
ipaddr.IPv4.isValidCIDRFourPartDecimal = function(string) {
|
|
358
|
-
const match = string.match(/^(.+)\/(\d+)$/);
|
|
359
|
-
if (!ipaddr.IPv4.isValidCIDR(string) || !match) return false;
|
|
360
|
-
return ipaddr.IPv4.isValidFourPartDecimal(match[1]);
|
|
361
|
-
};
|
|
362
|
-
ipaddr.IPv4.networkAddressFromCIDR = function(string) {
|
|
363
|
-
let cidr, i, ipInterfaceOctets, octets, subnetMaskOctets;
|
|
364
|
-
try {
|
|
365
|
-
cidr = this.parseCIDR(string);
|
|
366
|
-
ipInterfaceOctets = cidr[0].toByteArray();
|
|
367
|
-
subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray();
|
|
368
|
-
octets = [];
|
|
369
|
-
i = 0;
|
|
370
|
-
while (i < 4) {
|
|
371
|
-
octets.push(parseInt(ipInterfaceOctets[i], 10) & parseInt(subnetMaskOctets[i], 10));
|
|
372
|
-
i++;
|
|
373
|
-
}
|
|
374
|
-
return new this(octets);
|
|
375
|
-
} catch (e) {
|
|
376
|
-
throw new Error("ipaddr: the address does not have IPv4 CIDR format");
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
ipaddr.IPv4.parse = function(string) {
|
|
380
|
-
const parts = this.parser(string);
|
|
381
|
-
if (parts === null) throw new Error("ipaddr: string is not formatted like an IPv4 Address");
|
|
382
|
-
return new this(parts);
|
|
383
|
-
};
|
|
384
|
-
ipaddr.IPv4.parseCIDR = function(string) {
|
|
385
|
-
let match;
|
|
386
|
-
if (match = string.match(/^(.+)\/(\d+)$/)) {
|
|
387
|
-
const maskLength = parseInt(match[2]);
|
|
388
|
-
if (maskLength >= 0 && maskLength <= 32) {
|
|
389
|
-
const parsed = [this.parse(match[1]), maskLength];
|
|
390
|
-
Object.defineProperty(parsed, "toString", { value: function() {
|
|
391
|
-
return this.join("/");
|
|
392
|
-
} });
|
|
393
|
-
return parsed;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
throw new Error("ipaddr: string is not formatted like an IPv4 CIDR range");
|
|
397
|
-
};
|
|
398
|
-
ipaddr.IPv4.parser = function(string) {
|
|
399
|
-
let match, part, value;
|
|
400
|
-
if (match = string.match(ipv4Regexes.fourOctet)) return (function() {
|
|
401
|
-
const ref = match.slice(1, 6);
|
|
402
|
-
const results = [];
|
|
403
|
-
for (let i = 0; i < ref.length; i++) {
|
|
404
|
-
part = ref[i];
|
|
405
|
-
results.push(parseIntAuto(part));
|
|
406
|
-
}
|
|
407
|
-
return results;
|
|
408
|
-
})();
|
|
409
|
-
else if (match = string.match(ipv4Regexes.longValue)) {
|
|
410
|
-
value = parseIntAuto(match[1]);
|
|
411
|
-
if (value > 4294967295 || value < 0) throw new Error("ipaddr: address outside defined range");
|
|
412
|
-
return (function() {
|
|
413
|
-
const results = [];
|
|
414
|
-
let shift;
|
|
415
|
-
for (shift = 0; shift <= 24; shift += 8) results.push(value >> shift & 255);
|
|
416
|
-
return results;
|
|
417
|
-
})().reverse();
|
|
418
|
-
} else if (match = string.match(ipv4Regexes.twoOctet)) return (function() {
|
|
419
|
-
const ref = match.slice(1, 4);
|
|
420
|
-
const results = [];
|
|
421
|
-
value = parseIntAuto(ref[1]);
|
|
422
|
-
if (value > 16777215 || value < 0) throw new Error("ipaddr: address outside defined range");
|
|
423
|
-
results.push(parseIntAuto(ref[0]));
|
|
424
|
-
results.push(value >> 16 & 255);
|
|
425
|
-
results.push(value >> 8 & 255);
|
|
426
|
-
results.push(value & 255);
|
|
427
|
-
return results;
|
|
428
|
-
})();
|
|
429
|
-
else if (match = string.match(ipv4Regexes.threeOctet)) return (function() {
|
|
430
|
-
const ref = match.slice(1, 5);
|
|
431
|
-
const results = [];
|
|
432
|
-
value = parseIntAuto(ref[2]);
|
|
433
|
-
if (value > 65535 || value < 0) throw new Error("ipaddr: address outside defined range");
|
|
434
|
-
results.push(parseIntAuto(ref[0]));
|
|
435
|
-
results.push(parseIntAuto(ref[1]));
|
|
436
|
-
results.push(value >> 8 & 255);
|
|
437
|
-
results.push(value & 255);
|
|
438
|
-
return results;
|
|
439
|
-
})();
|
|
440
|
-
else return null;
|
|
441
|
-
};
|
|
442
|
-
ipaddr.IPv4.subnetMaskFromPrefixLength = function(prefix) {
|
|
443
|
-
prefix = parseInt(prefix);
|
|
444
|
-
if (prefix < 0 || prefix > 32) throw new Error("ipaddr: invalid IPv4 prefix length");
|
|
445
|
-
const octets = [
|
|
446
|
-
0,
|
|
447
|
-
0,
|
|
448
|
-
0,
|
|
449
|
-
0
|
|
450
|
-
];
|
|
451
|
-
let j = 0;
|
|
452
|
-
const filledOctetCount = Math.floor(prefix / 8);
|
|
453
|
-
while (j < filledOctetCount) {
|
|
454
|
-
octets[j] = 255;
|
|
455
|
-
j++;
|
|
134
|
+
return mutated ? parsed.toString() : value;
|
|
135
|
+
} catch {
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function redactQueryString(value, depth) {
|
|
140
|
+
const params = new URLSearchParams(value);
|
|
141
|
+
const entries = Array.from(params.entries());
|
|
142
|
+
const redactedEntries = [];
|
|
143
|
+
const seenSensitiveKeys = /* @__PURE__ */ new Set();
|
|
144
|
+
let mutated = false;
|
|
145
|
+
for (const [key, entryValue] of entries) {
|
|
146
|
+
if (isSensitiveUrlQueryParamName$1(key)) {
|
|
147
|
+
mutated = true;
|
|
148
|
+
if (!seenSensitiveKeys.has(key)) {
|
|
149
|
+
seenSensitiveKeys.add(key);
|
|
150
|
+
redactedEntries.push([key, "***"]);
|
|
456
151
|
}
|
|
457
|
-
|
|
458
|
-
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const redactedKey = redactNestedUrlValue(key, depth + 1);
|
|
155
|
+
const redactedValue = redactNestedUrlValue(entryValue, depth + 1);
|
|
156
|
+
if (redactedKey !== key || redactedValue !== entryValue) mutated = true;
|
|
157
|
+
redactedEntries.push([redactedKey, redactedValue]);
|
|
158
|
+
}
|
|
159
|
+
if (!mutated) return value;
|
|
160
|
+
const redactedParams = new URLSearchParams();
|
|
161
|
+
for (const [key, entryValue] of redactedEntries) redactedParams.append(key, entryValue);
|
|
162
|
+
return redactedParams.toString();
|
|
163
|
+
}
|
|
164
|
+
function redactUrlLikeFallback(value) {
|
|
165
|
+
return redactSensitiveUrlPath(redactEmbeddedUrlUserInfo(value).replace(/([?&])([^=&]+)=([^&]*)/g, (match, prefix, key) => isSensitiveUrlQueryParamName$1(key) ? `${prefix}${key}=***` : match));
|
|
166
|
+
}
|
|
167
|
+
function redactAuthorityUserInfo(candidate, authorityStart) {
|
|
168
|
+
const authority = candidate.slice(authorityStart);
|
|
169
|
+
const userInfoEnd = authority.lastIndexOf("@");
|
|
170
|
+
if (userInfoEnd < 0) return candidate;
|
|
171
|
+
return `${candidate.slice(0, authorityStart)}***:***@${authority.slice(userInfoEnd + 1)}`;
|
|
172
|
+
}
|
|
173
|
+
function redactEmbeddedUrlUserInfo(value) {
|
|
174
|
+
return value.replace(SPECIAL_SCHEME_AUTHORITY_RE, (candidate) => {
|
|
175
|
+
let authorityStart = candidate.indexOf(":") + 1;
|
|
176
|
+
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
177
|
+
return redactAuthorityUserInfo(candidate, authorityStart);
|
|
178
|
+
}).replace(SPECIAL_SCHEME_SPILLED_USERINFO_RE, (candidate) => {
|
|
179
|
+
let authorityStart = candidate.indexOf(":") + 1;
|
|
180
|
+
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
181
|
+
const userInfoEnd = candidate.lastIndexOf("@");
|
|
182
|
+
const firstReservedDelimiter = candidate.slice(authorityStart).search(/[\\/?#]/u);
|
|
183
|
+
if (userInfoEnd < 0 || firstReservedDelimiter < 0) return candidate;
|
|
184
|
+
const absoluteReservedDelimiter = authorityStart + firstReservedDelimiter;
|
|
185
|
+
if (absoluteReservedDelimiter >= userInfoEnd) return candidate;
|
|
186
|
+
const credentialSeparator = candidate.indexOf(":", authorityStart);
|
|
187
|
+
if (credentialSeparator < 0 || credentialSeparator > absoluteReservedDelimiter) return candidate;
|
|
188
|
+
const authorityPrefix = candidate.slice(authorityStart, absoluteReservedDelimiter);
|
|
189
|
+
const possiblePort = candidate.slice(credentialSeparator + 1, absoluteReservedDelimiter);
|
|
190
|
+
if (/^\d+$/u.test(possiblePort) || /^\[[^\]]+\](?::\d+)?$/u.test(authorityPrefix)) return candidate;
|
|
191
|
+
return `${candidate.slice(0, authorityStart)}***:***@${candidate.slice(userInfoEnd + 1)}`;
|
|
192
|
+
}).replace(PROTOCOL_RELATIVE_AUTHORITY_RE, (candidate) => {
|
|
193
|
+
let authorityStart = 0;
|
|
194
|
+
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
195
|
+
return redactAuthorityUserInfo(candidate, authorityStart);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function hasUnresolvedEmbeddedUrlUserInfo(value) {
|
|
199
|
+
for (const match of value.matchAll(/(?:\b(?:https?|wss?|ftp):[\\/]{0,2}|[\\/]{2,})/giu)) {
|
|
200
|
+
const remainder = value.slice((match.index ?? 0) + match[0].length);
|
|
201
|
+
const userInfoEnd = remainder.search(/(?<!\*\*\*:\*\*\*)@/u);
|
|
202
|
+
const authorityEnd = remainder.search(/[\\/?#]/u);
|
|
203
|
+
const pathBeforeAt = remainder.slice(authorityEnd + 1, userInfoEnd);
|
|
204
|
+
if (userInfoEnd >= 0 && (authorityEnd < 0 || userInfoEnd <= authorityEnd || remainder[authorityEnd] === "/" && (pathBeforeAt.includes(":") || /^[^/?#\s]+\.[^/?#\s]+(?:[/?#]|$)/u.test(remainder.slice(userInfoEnd + 1))))) return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
function redactRelativeUrlFragment(value, depth) {
|
|
209
|
+
const fragmentIndex = value.indexOf("#");
|
|
210
|
+
if (fragmentIndex < 0) return value;
|
|
211
|
+
const fragment = value.slice(fragmentIndex + 1);
|
|
212
|
+
const redactedFragment = redactFragment(fragment, depth + 1);
|
|
213
|
+
return redactedFragment === fragment ? value : `${value.slice(0, fragmentIndex + 1)}${redactedFragment}`;
|
|
214
|
+
}
|
|
215
|
+
function redactFragment(value, depth) {
|
|
216
|
+
if (!value) return value;
|
|
217
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH && looksLikeNestedUrlValue(value)) return "***";
|
|
218
|
+
const wholeUrl = redactSensitiveUrlAtDepth(value, depth);
|
|
219
|
+
if (wholeUrl.parsedWholeUrl) return redactUrlLikeFallback(wholeUrl.value);
|
|
220
|
+
const candidate = value;
|
|
221
|
+
const firstQueryDelimiter = candidate.search(/[?&]/u);
|
|
222
|
+
const firstEquals = candidate.indexOf("=");
|
|
223
|
+
if (firstEquals >= 0 && (firstQueryDelimiter < 0 || firstEquals < firstQueryDelimiter)) return redactQueryString(candidate, depth);
|
|
224
|
+
const hashRouterQueryIndex = candidate.indexOf("?");
|
|
225
|
+
if (hashRouterQueryIndex >= 0) {
|
|
226
|
+
const redactedQuery = redactQueryString(candidate.slice(hashRouterQueryIndex + 1), depth);
|
|
227
|
+
return `${redactEncodedUrlLikeString(redactUrlLikeFallback(candidate.slice(0, hashRouterQueryIndex + 1)), depth + 1)}${redactedQuery}`;
|
|
228
|
+
}
|
|
229
|
+
const fallback = redactUrlLikeFallback(candidate);
|
|
230
|
+
if (!looksLikeNestedUrlValue(fallback)) return fallback;
|
|
231
|
+
let decoded;
|
|
232
|
+
try {
|
|
233
|
+
decoded = decodeURIComponent(fallback);
|
|
234
|
+
} catch {
|
|
235
|
+
return "***";
|
|
236
|
+
}
|
|
237
|
+
if (decoded === fallback) return fallback;
|
|
238
|
+
const redactedDecoded = redactFragment(decoded, depth + 1);
|
|
239
|
+
return redactedDecoded === decoded ? fallback : encodeURIComponent(redactedDecoded);
|
|
240
|
+
}
|
|
241
|
+
function redactEncodedNestedUrlPath(value, depth) {
|
|
242
|
+
if (!looksLikeNestedUrlValue(value)) return value;
|
|
243
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH) return "***";
|
|
244
|
+
let decoded;
|
|
245
|
+
try {
|
|
246
|
+
decoded = decodeURIComponent(value);
|
|
247
|
+
} catch {
|
|
248
|
+
return "***";
|
|
249
|
+
}
|
|
250
|
+
if (decoded === value) return value;
|
|
251
|
+
const direct = redactSensitiveUrlLikeStringAtDepth(decoded, depth);
|
|
252
|
+
if (direct.value !== decoded || hasUnresolvedEmbeddedUrlUserInfo(decoded)) return direct.value !== decoded ? direct.value : "***";
|
|
253
|
+
if (direct.parsedWholeUrl) return value;
|
|
254
|
+
const nested = redactEncodedNestedUrlPath(decoded, depth + 1);
|
|
255
|
+
return nested === decoded ? value : nested;
|
|
256
|
+
}
|
|
257
|
+
function redactSensitiveUrlAtDepth(value, depth) {
|
|
258
|
+
try {
|
|
259
|
+
const directRedaction = redactDirectSensitiveUrl(value);
|
|
260
|
+
const parsed = new URL(directRedaction);
|
|
261
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH) return {
|
|
262
|
+
value: "***",
|
|
263
|
+
parsedWholeUrl: true
|
|
459
264
|
};
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
for (i = 0; i < this.parts.length; i++) {
|
|
469
|
-
part = this.parts[i];
|
|
470
|
-
if (!(0 <= part && part <= 65535)) throw new Error("ipaddr: ipv6 part should fit in 16 bits");
|
|
471
|
-
}
|
|
472
|
-
if (zoneId) this.zoneId = zoneId;
|
|
473
|
-
}
|
|
474
|
-
IPv6.prototype.SpecialRanges = {
|
|
475
|
-
unspecified: [new IPv6([
|
|
476
|
-
0,
|
|
477
|
-
0,
|
|
478
|
-
0,
|
|
479
|
-
0,
|
|
480
|
-
0,
|
|
481
|
-
0,
|
|
482
|
-
0,
|
|
483
|
-
0
|
|
484
|
-
]), 128],
|
|
485
|
-
linkLocal: [new IPv6([
|
|
486
|
-
65152,
|
|
487
|
-
0,
|
|
488
|
-
0,
|
|
489
|
-
0,
|
|
490
|
-
0,
|
|
491
|
-
0,
|
|
492
|
-
0,
|
|
493
|
-
0
|
|
494
|
-
]), 10],
|
|
495
|
-
multicast: [new IPv6([
|
|
496
|
-
65280,
|
|
497
|
-
0,
|
|
498
|
-
0,
|
|
499
|
-
0,
|
|
500
|
-
0,
|
|
501
|
-
0,
|
|
502
|
-
0,
|
|
503
|
-
0
|
|
504
|
-
]), 8],
|
|
505
|
-
loopback: [new IPv6([
|
|
506
|
-
0,
|
|
507
|
-
0,
|
|
508
|
-
0,
|
|
509
|
-
0,
|
|
510
|
-
0,
|
|
511
|
-
0,
|
|
512
|
-
0,
|
|
513
|
-
1
|
|
514
|
-
]), 128],
|
|
515
|
-
uniqueLocal: [new IPv6([
|
|
516
|
-
64512,
|
|
517
|
-
0,
|
|
518
|
-
0,
|
|
519
|
-
0,
|
|
520
|
-
0,
|
|
521
|
-
0,
|
|
522
|
-
0,
|
|
523
|
-
0
|
|
524
|
-
]), 7],
|
|
525
|
-
ipv4Mapped: [new IPv6([
|
|
526
|
-
0,
|
|
527
|
-
0,
|
|
528
|
-
0,
|
|
529
|
-
0,
|
|
530
|
-
0,
|
|
531
|
-
65535,
|
|
532
|
-
0,
|
|
533
|
-
0
|
|
534
|
-
]), 96],
|
|
535
|
-
deprecatedSiteLocal: [new IPv6([
|
|
536
|
-
65216,
|
|
537
|
-
0,
|
|
538
|
-
0,
|
|
539
|
-
0,
|
|
540
|
-
0,
|
|
541
|
-
0,
|
|
542
|
-
0,
|
|
543
|
-
0
|
|
544
|
-
]), 10],
|
|
545
|
-
discard: [new IPv6([
|
|
546
|
-
256,
|
|
547
|
-
0,
|
|
548
|
-
0,
|
|
549
|
-
0,
|
|
550
|
-
0,
|
|
551
|
-
0,
|
|
552
|
-
0,
|
|
553
|
-
0
|
|
554
|
-
]), 64],
|
|
555
|
-
rfc6145: [new IPv6([
|
|
556
|
-
0,
|
|
557
|
-
0,
|
|
558
|
-
0,
|
|
559
|
-
0,
|
|
560
|
-
65535,
|
|
561
|
-
0,
|
|
562
|
-
0,
|
|
563
|
-
0
|
|
564
|
-
]), 96],
|
|
565
|
-
rfc6052: [[new IPv6([
|
|
566
|
-
100,
|
|
567
|
-
65435,
|
|
568
|
-
0,
|
|
569
|
-
0,
|
|
570
|
-
0,
|
|
571
|
-
0,
|
|
572
|
-
0,
|
|
573
|
-
0
|
|
574
|
-
]), 96], [new IPv6([
|
|
575
|
-
100,
|
|
576
|
-
65435,
|
|
577
|
-
1,
|
|
578
|
-
0,
|
|
579
|
-
0,
|
|
580
|
-
0,
|
|
581
|
-
0,
|
|
582
|
-
0
|
|
583
|
-
]), 48]],
|
|
584
|
-
"6to4": [new IPv6([
|
|
585
|
-
8194,
|
|
586
|
-
0,
|
|
587
|
-
0,
|
|
588
|
-
0,
|
|
589
|
-
0,
|
|
590
|
-
0,
|
|
591
|
-
0,
|
|
592
|
-
0
|
|
593
|
-
]), 16],
|
|
594
|
-
teredo: [new IPv6([
|
|
595
|
-
8193,
|
|
596
|
-
0,
|
|
597
|
-
0,
|
|
598
|
-
0,
|
|
599
|
-
0,
|
|
600
|
-
0,
|
|
601
|
-
0,
|
|
602
|
-
0
|
|
603
|
-
]), 32],
|
|
604
|
-
benchmarking: [new IPv6([
|
|
605
|
-
8193,
|
|
606
|
-
2,
|
|
607
|
-
0,
|
|
608
|
-
0,
|
|
609
|
-
0,
|
|
610
|
-
0,
|
|
611
|
-
0,
|
|
612
|
-
0
|
|
613
|
-
]), 48],
|
|
614
|
-
amt: [new IPv6([
|
|
615
|
-
8193,
|
|
616
|
-
3,
|
|
617
|
-
0,
|
|
618
|
-
0,
|
|
619
|
-
0,
|
|
620
|
-
0,
|
|
621
|
-
0,
|
|
622
|
-
0
|
|
623
|
-
]), 32],
|
|
624
|
-
as112v6: [[new IPv6([
|
|
625
|
-
8193,
|
|
626
|
-
4,
|
|
627
|
-
274,
|
|
628
|
-
0,
|
|
629
|
-
0,
|
|
630
|
-
0,
|
|
631
|
-
0,
|
|
632
|
-
0
|
|
633
|
-
]), 48], [new IPv6([
|
|
634
|
-
9760,
|
|
635
|
-
79,
|
|
636
|
-
32768,
|
|
637
|
-
0,
|
|
638
|
-
0,
|
|
639
|
-
0,
|
|
640
|
-
0,
|
|
641
|
-
0
|
|
642
|
-
]), 48]],
|
|
643
|
-
deprecatedOrchid: [new IPv6([
|
|
644
|
-
8193,
|
|
645
|
-
16,
|
|
646
|
-
0,
|
|
647
|
-
0,
|
|
648
|
-
0,
|
|
649
|
-
0,
|
|
650
|
-
0,
|
|
651
|
-
0
|
|
652
|
-
]), 28],
|
|
653
|
-
orchid2: [new IPv6([
|
|
654
|
-
8193,
|
|
655
|
-
32,
|
|
656
|
-
0,
|
|
657
|
-
0,
|
|
658
|
-
0,
|
|
659
|
-
0,
|
|
660
|
-
0,
|
|
661
|
-
0
|
|
662
|
-
]), 28],
|
|
663
|
-
droneRemoteIdProtocolEntityTags: [new IPv6([
|
|
664
|
-
8193,
|
|
665
|
-
48,
|
|
666
|
-
0,
|
|
667
|
-
0,
|
|
668
|
-
0,
|
|
669
|
-
0,
|
|
670
|
-
0,
|
|
671
|
-
0
|
|
672
|
-
]), 28],
|
|
673
|
-
segmentRouting: [new IPv6([
|
|
674
|
-
24320,
|
|
675
|
-
0,
|
|
676
|
-
0,
|
|
677
|
-
0,
|
|
678
|
-
0,
|
|
679
|
-
0,
|
|
680
|
-
0,
|
|
681
|
-
0
|
|
682
|
-
]), 16],
|
|
683
|
-
reserved: [
|
|
684
|
-
[new IPv6([
|
|
685
|
-
8193,
|
|
686
|
-
0,
|
|
687
|
-
0,
|
|
688
|
-
0,
|
|
689
|
-
0,
|
|
690
|
-
0,
|
|
691
|
-
0,
|
|
692
|
-
0
|
|
693
|
-
]), 23],
|
|
694
|
-
[new IPv6([
|
|
695
|
-
8193,
|
|
696
|
-
3512,
|
|
697
|
-
0,
|
|
698
|
-
0,
|
|
699
|
-
0,
|
|
700
|
-
0,
|
|
701
|
-
0,
|
|
702
|
-
0
|
|
703
|
-
]), 32],
|
|
704
|
-
[new IPv6([
|
|
705
|
-
16383,
|
|
706
|
-
0,
|
|
707
|
-
0,
|
|
708
|
-
0,
|
|
709
|
-
0,
|
|
710
|
-
0,
|
|
711
|
-
0,
|
|
712
|
-
0
|
|
713
|
-
]), 20]
|
|
714
|
-
]
|
|
715
|
-
};
|
|
716
|
-
IPv6.prototype.isIPv4MappedAddress = function() {
|
|
717
|
-
return this.range() === "ipv4Mapped";
|
|
718
|
-
};
|
|
719
|
-
IPv6.prototype.kind = function() {
|
|
720
|
-
return "ipv6";
|
|
721
|
-
};
|
|
722
|
-
IPv6.prototype.match = function(other, cidrRange) {
|
|
723
|
-
let ref;
|
|
724
|
-
if (cidrRange === void 0) {
|
|
725
|
-
ref = other;
|
|
726
|
-
other = ref[0];
|
|
727
|
-
cidrRange = ref[1];
|
|
728
|
-
}
|
|
729
|
-
if (other.kind() !== "ipv6") throw new Error("ipaddr: cannot match ipv6 address with non-ipv6 one");
|
|
730
|
-
return matchCIDR(this.parts, other.parts, 16, cidrRange);
|
|
731
|
-
};
|
|
732
|
-
IPv6.prototype.prefixLengthFromSubnetMask = function() {
|
|
733
|
-
let cidr = 0;
|
|
734
|
-
let stop = false;
|
|
735
|
-
const zerotable = {
|
|
736
|
-
0: 16,
|
|
737
|
-
32768: 15,
|
|
738
|
-
49152: 14,
|
|
739
|
-
57344: 13,
|
|
740
|
-
61440: 12,
|
|
741
|
-
63488: 11,
|
|
742
|
-
64512: 10,
|
|
743
|
-
65024: 9,
|
|
744
|
-
65280: 8,
|
|
745
|
-
65408: 7,
|
|
746
|
-
65472: 6,
|
|
747
|
-
65504: 5,
|
|
748
|
-
65520: 4,
|
|
749
|
-
65528: 3,
|
|
750
|
-
65532: 2,
|
|
751
|
-
65534: 1,
|
|
752
|
-
65535: 0
|
|
753
|
-
};
|
|
754
|
-
let part, zeros;
|
|
755
|
-
for (let i = 7; i >= 0; i -= 1) {
|
|
756
|
-
part = this.parts[i];
|
|
757
|
-
if (part in zerotable) {
|
|
758
|
-
zeros = zerotable[part];
|
|
759
|
-
if (stop && zeros !== 0) return null;
|
|
760
|
-
if (zeros !== 16) stop = true;
|
|
761
|
-
cidr += zeros;
|
|
762
|
-
} else return null;
|
|
763
|
-
}
|
|
764
|
-
return 128 - cidr;
|
|
265
|
+
let mutated = directRedaction !== value;
|
|
266
|
+
const redactedNestedPath = redactEmbeddedUrlUserInfo(redactEncodedNestedUrlPath(parsed.pathname, depth + 1));
|
|
267
|
+
if (redactedNestedPath !== parsed.pathname) {
|
|
268
|
+
const originalPath = parsed.pathname;
|
|
269
|
+
parsed.pathname = redactedNestedPath;
|
|
270
|
+
if (parsed.pathname === originalPath) return {
|
|
271
|
+
value: directRedaction,
|
|
272
|
+
parsedWholeUrl: false
|
|
765
273
|
};
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
const results = [];
|
|
783
|
-
for (let i = 0; i < this.parts.length; i++) results.push(padPart(this.parts[i].toString(16), 4));
|
|
784
|
-
return results;
|
|
785
|
-
}).call(this).join(":");
|
|
786
|
-
let suffix = "";
|
|
787
|
-
if (this.zoneId) suffix = `%${this.zoneId}`;
|
|
788
|
-
return addr + suffix;
|
|
789
|
-
};
|
|
790
|
-
IPv6.prototype.toIPv4Address = function() {
|
|
791
|
-
if (!this.isIPv4MappedAddress()) throw new Error("ipaddr: trying to convert a generic ipv6 address to ipv4");
|
|
792
|
-
const ref = this.parts.slice(-2);
|
|
793
|
-
const high = ref[0];
|
|
794
|
-
const low = ref[1];
|
|
795
|
-
return new ipaddr.IPv4([
|
|
796
|
-
high >> 8,
|
|
797
|
-
high & 255,
|
|
798
|
-
low >> 8,
|
|
799
|
-
low & 255
|
|
800
|
-
]);
|
|
801
|
-
};
|
|
802
|
-
IPv6.prototype.toNormalizedString = function() {
|
|
803
|
-
const addr = (function() {
|
|
804
|
-
const results = [];
|
|
805
|
-
for (let i = 0; i < this.parts.length; i++) results.push(this.parts[i].toString(16));
|
|
806
|
-
return results;
|
|
807
|
-
}).call(this).join(":");
|
|
808
|
-
let suffix = "";
|
|
809
|
-
if (this.zoneId) suffix = `%${this.zoneId}`;
|
|
810
|
-
return addr + suffix;
|
|
811
|
-
};
|
|
812
|
-
IPv6.prototype.toRFC5952String = function() {
|
|
813
|
-
const regex = /((^|:)(0(:|$)){2,})/g;
|
|
814
|
-
const string = this.toNormalizedString();
|
|
815
|
-
let bestMatchIndex = 0;
|
|
816
|
-
let bestMatchLength = -1;
|
|
817
|
-
let match;
|
|
818
|
-
while (match = regex.exec(string)) if (match[0].length > bestMatchLength) {
|
|
819
|
-
bestMatchIndex = match.index;
|
|
820
|
-
bestMatchLength = match[0].length;
|
|
821
|
-
}
|
|
822
|
-
if (bestMatchLength < 0) return string;
|
|
823
|
-
return `${string.substring(0, bestMatchIndex)}::${string.substring(bestMatchIndex + bestMatchLength)}`;
|
|
824
|
-
};
|
|
825
|
-
IPv6.prototype.toString = function() {
|
|
826
|
-
return this.toRFC5952String();
|
|
827
|
-
};
|
|
828
|
-
return IPv6;
|
|
829
|
-
})();
|
|
830
|
-
ipaddr.IPv6.broadcastAddressFromCIDR = function(string) {
|
|
831
|
-
try {
|
|
832
|
-
const cidr = this.parseCIDR(string);
|
|
833
|
-
const ipInterfaceOctets = cidr[0].toByteArray();
|
|
834
|
-
const subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray();
|
|
835
|
-
const octets = [];
|
|
836
|
-
let i = 0;
|
|
837
|
-
while (i < 16) {
|
|
838
|
-
octets.push(parseInt(ipInterfaceOctets[i], 10) | parseInt(subnetMaskOctets[i], 10) ^ 255);
|
|
839
|
-
i++;
|
|
840
|
-
}
|
|
841
|
-
return new this(octets);
|
|
842
|
-
} catch (e) {
|
|
843
|
-
throw new Error(`ipaddr: the address does not have IPv6 CIDR format (${e})`);
|
|
844
|
-
}
|
|
845
|
-
};
|
|
846
|
-
ipaddr.IPv6.isIPv6 = function(string) {
|
|
847
|
-
return this.parser(string) !== null;
|
|
848
|
-
};
|
|
849
|
-
ipaddr.IPv6.isValid = function(string) {
|
|
850
|
-
if (typeof string === "string" && string.indexOf(":") === -1) return false;
|
|
851
|
-
try {
|
|
852
|
-
const addr = this.parser(string);
|
|
853
|
-
new this(addr.parts, addr.zoneId);
|
|
854
|
-
return true;
|
|
855
|
-
} catch (e) {
|
|
856
|
-
return false;
|
|
857
|
-
}
|
|
858
|
-
};
|
|
859
|
-
ipaddr.IPv6.isValidCIDR = function(string) {
|
|
860
|
-
if (typeof string === "string" && string.indexOf(":") === -1) return false;
|
|
861
|
-
try {
|
|
862
|
-
this.parseCIDR(string);
|
|
863
|
-
return true;
|
|
864
|
-
} catch (e) {
|
|
865
|
-
return false;
|
|
866
|
-
}
|
|
867
|
-
};
|
|
868
|
-
ipaddr.IPv6.networkAddressFromCIDR = function(string) {
|
|
869
|
-
let cidr, i, ipInterfaceOctets, octets, subnetMaskOctets;
|
|
870
|
-
try {
|
|
871
|
-
cidr = this.parseCIDR(string);
|
|
872
|
-
ipInterfaceOctets = cidr[0].toByteArray();
|
|
873
|
-
subnetMaskOctets = this.subnetMaskFromPrefixLength(cidr[1]).toByteArray();
|
|
874
|
-
octets = [];
|
|
875
|
-
i = 0;
|
|
876
|
-
while (i < 16) {
|
|
877
|
-
octets.push(parseInt(ipInterfaceOctets[i], 10) & parseInt(subnetMaskOctets[i], 10));
|
|
878
|
-
i++;
|
|
879
|
-
}
|
|
880
|
-
return new this(octets);
|
|
881
|
-
} catch (e) {
|
|
882
|
-
throw new Error(`ipaddr: the address does not have IPv6 CIDR format (${e})`);
|
|
883
|
-
}
|
|
884
|
-
};
|
|
885
|
-
ipaddr.IPv6.parse = function(string) {
|
|
886
|
-
const addr = this.parser(string);
|
|
887
|
-
if (addr.parts === null) throw new Error("ipaddr: string is not formatted like an IPv6 Address");
|
|
888
|
-
return new this(addr.parts, addr.zoneId);
|
|
889
|
-
};
|
|
890
|
-
ipaddr.IPv6.parseCIDR = function(string) {
|
|
891
|
-
let maskLength, match, parsed;
|
|
892
|
-
if (match = string.match(/^(.+)\/(\d+)$/)) {
|
|
893
|
-
maskLength = parseInt(match[2]);
|
|
894
|
-
if (maskLength >= 0 && maskLength <= 128) {
|
|
895
|
-
parsed = [this.parse(match[1]), maskLength];
|
|
896
|
-
Object.defineProperty(parsed, "toString", { value: function() {
|
|
897
|
-
return this.join("/");
|
|
898
|
-
} });
|
|
899
|
-
return parsed;
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
throw new Error("ipaddr: string is not formatted like an IPv6 CIDR range");
|
|
903
|
-
};
|
|
904
|
-
ipaddr.IPv6.parser = function(string) {
|
|
905
|
-
let addr, i, match, octet, octets, zoneId;
|
|
906
|
-
if (match = string.match(ipv6Regexes.deprecatedTransitional)) return this.parser(`::ffff:${match[1]}`);
|
|
907
|
-
if (ipv6Regexes.native.test(string)) return expandIPv6(string, 8);
|
|
908
|
-
if (match = string.match(ipv6Regexes.transitional)) {
|
|
909
|
-
zoneId = match[6] || "";
|
|
910
|
-
addr = match[1];
|
|
911
|
-
if (!match[1].endsWith("::")) addr = addr.slice(0, -1);
|
|
912
|
-
addr = expandIPv6(addr + zoneId, 6);
|
|
913
|
-
if (addr.parts) {
|
|
914
|
-
octets = [
|
|
915
|
-
parseInt(match[2]),
|
|
916
|
-
parseInt(match[3]),
|
|
917
|
-
parseInt(match[4]),
|
|
918
|
-
parseInt(match[5])
|
|
919
|
-
];
|
|
920
|
-
for (i = 0; i < octets.length; i++) {
|
|
921
|
-
octet = octets[i];
|
|
922
|
-
if (!(0 <= octet && octet <= 255)) return null;
|
|
923
|
-
}
|
|
924
|
-
addr.parts.push(octets[0] << 8 | octets[1]);
|
|
925
|
-
addr.parts.push(octets[2] << 8 | octets[3]);
|
|
926
|
-
return {
|
|
927
|
-
parts: addr.parts,
|
|
928
|
-
zoneId: addr.zoneId
|
|
929
|
-
};
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
return null;
|
|
933
|
-
};
|
|
934
|
-
ipaddr.IPv6.subnetMaskFromPrefixLength = function(prefix) {
|
|
935
|
-
prefix = parseInt(prefix);
|
|
936
|
-
if (prefix < 0 || prefix > 128) throw new Error("ipaddr: invalid IPv6 prefix length");
|
|
937
|
-
const octets = [
|
|
938
|
-
0,
|
|
939
|
-
0,
|
|
940
|
-
0,
|
|
941
|
-
0,
|
|
942
|
-
0,
|
|
943
|
-
0,
|
|
944
|
-
0,
|
|
945
|
-
0,
|
|
946
|
-
0,
|
|
947
|
-
0,
|
|
948
|
-
0,
|
|
949
|
-
0,
|
|
950
|
-
0,
|
|
951
|
-
0,
|
|
952
|
-
0,
|
|
953
|
-
0
|
|
954
|
-
];
|
|
955
|
-
let j = 0;
|
|
956
|
-
const filledOctetCount = Math.floor(prefix / 8);
|
|
957
|
-
while (j < filledOctetCount) {
|
|
958
|
-
octets[j] = 255;
|
|
959
|
-
j++;
|
|
960
|
-
}
|
|
961
|
-
if (filledOctetCount < 16) octets[filledOctetCount] = Math.pow(2, prefix % 8) - 1 << 8 - prefix % 8;
|
|
962
|
-
return new this(octets);
|
|
963
|
-
};
|
|
964
|
-
ipaddr.fromByteArray = function(bytes) {
|
|
965
|
-
const length = bytes.length;
|
|
966
|
-
if (length === 4) return new ipaddr.IPv4(bytes);
|
|
967
|
-
else if (length === 16) return new ipaddr.IPv6(bytes);
|
|
968
|
-
else throw new Error("ipaddr: the binary input is neither an IPv6 nor IPv4 address");
|
|
969
|
-
};
|
|
970
|
-
ipaddr.isValid = function(string) {
|
|
971
|
-
return ipaddr.IPv6.isValid(string) || ipaddr.IPv4.isValid(string);
|
|
972
|
-
};
|
|
973
|
-
ipaddr.isValidCIDR = function(string) {
|
|
974
|
-
return ipaddr.IPv6.isValidCIDR(string) || ipaddr.IPv4.isValidCIDR(string);
|
|
975
|
-
};
|
|
976
|
-
ipaddr.parse = function(string) {
|
|
977
|
-
if (ipaddr.IPv6.isValid(string)) return ipaddr.IPv6.parse(string);
|
|
978
|
-
else if (ipaddr.IPv4.isValid(string)) return ipaddr.IPv4.parse(string);
|
|
979
|
-
else throw new Error("ipaddr: the address has neither IPv6 nor IPv4 format");
|
|
980
|
-
};
|
|
981
|
-
ipaddr.parseCIDR = function(string) {
|
|
982
|
-
try {
|
|
983
|
-
return ipaddr.IPv6.parseCIDR(string);
|
|
984
|
-
} catch (e) {
|
|
985
|
-
try {
|
|
986
|
-
return ipaddr.IPv4.parseCIDR(string);
|
|
987
|
-
} catch (e2) {
|
|
988
|
-
throw new Error("ipaddr: the address has neither IPv6 nor IPv4 CIDR format");
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
};
|
|
992
|
-
ipaddr.process = function(string) {
|
|
993
|
-
const addr = this.parse(string);
|
|
994
|
-
if (addr.kind() === "ipv6" && addr.isIPv4MappedAddress()) return addr.toIPv4Address();
|
|
995
|
-
else return addr;
|
|
274
|
+
mutated = true;
|
|
275
|
+
}
|
|
276
|
+
const redactedQuery = redactQueryString(parsed.search.slice(1), depth);
|
|
277
|
+
if (redactedQuery !== parsed.search.slice(1)) {
|
|
278
|
+
parsed.search = redactedQuery;
|
|
279
|
+
mutated = true;
|
|
280
|
+
}
|
|
281
|
+
const fragment = parsed.hash.slice(1);
|
|
282
|
+
const redactedHash = redactFragment(fragment, depth + 1);
|
|
283
|
+
if (redactedHash !== fragment) {
|
|
284
|
+
parsed.hash = redactedHash;
|
|
285
|
+
mutated = true;
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
value: mutated ? parsed.toString() : value,
|
|
289
|
+
parsedWholeUrl: true
|
|
996
290
|
};
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
rangeSubnets = rangeList[rangeName];
|
|
1002
|
-
if (rangeSubnets[0] && !(rangeSubnets[0] instanceof Array)) rangeSubnets = [rangeSubnets];
|
|
1003
|
-
for (i = 0; i < rangeSubnets.length; i++) {
|
|
1004
|
-
subnet = rangeSubnets[i];
|
|
1005
|
-
if (address.kind() === subnet[0].kind() && address.match.apply(address, subnet)) return rangeName;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
return defaultName;
|
|
291
|
+
} catch {
|
|
292
|
+
return {
|
|
293
|
+
value,
|
|
294
|
+
parsedWholeUrl: false
|
|
1009
295
|
};
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function redactSensitiveUrlLikeStringAtDepth(value, depth) {
|
|
299
|
+
const redactedUrl = redactSensitiveUrlAtDepth(value, depth);
|
|
300
|
+
if (redactedUrl.parsedWholeUrl) return redactedUrl;
|
|
301
|
+
return {
|
|
302
|
+
value: redactEncodedUrlLikeString(redactRelativeUrlFragment(redactUrlLikeFallback(redactedUrl.value), depth), depth + 1),
|
|
303
|
+
parsedWholeUrl: false
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function redactEncodedUrlLikeString(value, depth) {
|
|
307
|
+
if (!looksLikeNestedUrlValue(value)) return value;
|
|
308
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH) return "***";
|
|
309
|
+
let decoded;
|
|
310
|
+
try {
|
|
311
|
+
decoded = decodeURIComponent(value);
|
|
312
|
+
} catch {
|
|
313
|
+
return "***";
|
|
314
|
+
}
|
|
315
|
+
if (decoded === value) return value;
|
|
316
|
+
const redactedDecoded = redactSensitiveUrlLikeStringAtDepth(decoded, depth + 1);
|
|
317
|
+
if (redactedDecoded.value !== decoded || redactedDecoded.parsedWholeUrl) return redactedDecoded.value === decoded ? value : redactedDecoded.value;
|
|
318
|
+
return hasUnresolvedEmbeddedUrlUserInfo(decoded) ? "***" : value;
|
|
319
|
+
}
|
|
320
|
+
function redactNestedUrlValue(value, depth) {
|
|
321
|
+
if (!looksLikeNestedUrlValue(value)) return value;
|
|
322
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH) return "***";
|
|
323
|
+
const direct = redactSensitiveUrlLikeStringAtDepth(value, depth);
|
|
324
|
+
if (direct.value !== value) return direct.value;
|
|
325
|
+
if (hasUnresolvedEmbeddedUrlUserInfo(value)) return "***";
|
|
326
|
+
if (direct.parsedWholeUrl) return value;
|
|
327
|
+
let decoded;
|
|
328
|
+
try {
|
|
329
|
+
decoded = decodeURIComponent(value);
|
|
330
|
+
} catch {
|
|
331
|
+
return "***";
|
|
332
|
+
}
|
|
333
|
+
if (decoded === value || !looksLikeNestedUrlValue(decoded)) return value;
|
|
334
|
+
const redactedDecoded = redactNestedUrlValue(decoded, depth + 1);
|
|
335
|
+
return redactedDecoded === decoded ? value : encodeURIComponent(redactedDecoded);
|
|
336
|
+
}
|
|
337
|
+
/** Redacts sensitive URL-looking substrings even when the full value is not a valid URL. */
|
|
338
|
+
function redactSensitiveUrlLikeString(value) {
|
|
339
|
+
return redactSensitiveUrlLikeStringAtDepth(value, 0).value;
|
|
340
|
+
}
|
|
341
|
+
ipaddr.IPv4.parse("198.18.0.0");
|
|
1015
342
|
function stripIpv6Brackets(value) {
|
|
1016
343
|
if (value.startsWith("[") && value.endsWith("]")) return value.slice(1, -1);
|
|
1017
344
|
return value;
|
|
@@ -1034,7 +361,7 @@ function normalizeIpParseInput(raw) {
|
|
|
1034
361
|
function parseCanonicalIpAddress(raw) {
|
|
1035
362
|
const normalized = normalizeIpParseInput(raw);
|
|
1036
363
|
if (!normalized) return;
|
|
1037
|
-
return
|
|
364
|
+
return ipaddr.IPv4.isValidFourPartDecimal(normalized) || ipaddr.IPv6.isValid(normalized) ? ipaddr.parse(normalized) : void 0;
|
|
1038
365
|
}
|
|
1039
366
|
/** Normalizes canonical IP literals and maps IPv4-mapped IPv6 addresses to IPv4 text. */
|
|
1040
367
|
function normalizeIpAddress(raw) {
|
|
@@ -1056,8 +383,12 @@ function normalizeGatewayErrorText(value) {
|
|
|
1056
383
|
function isSensitiveUrlQueryParamName(key) {
|
|
1057
384
|
return /(?:token|password|secret|key|auth|credential)/iu.test(key);
|
|
1058
385
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
386
|
+
const SHA256_HEX_FINGERPRINT = /^[a-fA-F0-9]{64}$/u;
|
|
387
|
+
const SHA256_COLON_FINGERPRINT = /^(?:[a-fA-F0-9]{2}:){31}[a-fA-F0-9]{2}$/u;
|
|
388
|
+
function normalizeTlsFingerprint(fingerprint) {
|
|
389
|
+
const value = (fingerprint ?? "").trim().replace(/^sha256:/iu, "");
|
|
390
|
+
if (SHA256_HEX_FINGERPRINT.test(value)) return value.toLowerCase();
|
|
391
|
+
return SHA256_COLON_FINGERPRINT.test(value) ? value.replaceAll(":", "").toLowerCase() : "";
|
|
1061
392
|
}
|
|
1062
393
|
function parseHostForAddressChecks(host) {
|
|
1063
394
|
if (!host) return null;
|
|
@@ -1164,15 +495,17 @@ function resolveGatewayWebSocketTransport(params) {
|
|
|
1164
495
|
} catch {}
|
|
1165
496
|
throw new GatewayWebSocketTransportConfigurationError(`SECURITY ERROR: Cannot connect to "${displayHost}" over plaintext ws://. Both credentials and chat data would be exposed to network interception. Use wss:// for remote URLs. Safe defaults: keep gateway.bind=loopback and connect via SSH tunnel (ssh -N -L 18789:127.0.0.1:18789 user@gateway-host), or use Tailscale Serve/Funnel. ` + (allowPrivateWs ? "" : "Break-glass (trusted private networks only): set OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1. ") + "Run `openclaw doctor --fix` for guidance.");
|
|
1166
497
|
}
|
|
1167
|
-
const normalize = params.normalizeTlsFingerprint ??
|
|
498
|
+
const normalize = params.normalizeTlsFingerprint ?? normalizeTlsFingerprint;
|
|
499
|
+
const expectedFingerprint = params.tlsFingerprint ? normalizeTlsFingerprint(params.tlsFingerprint) : void 0;
|
|
500
|
+
if (params.tlsFingerprint && !expectedFingerprint) throw new GatewayWebSocketTransportConfigurationError("gateway tls fingerprint must be a SHA-256 fingerprint");
|
|
1168
501
|
const options = { ...params.options };
|
|
1169
|
-
if (usesTls &&
|
|
502
|
+
if (usesTls && expectedFingerprint) {
|
|
1170
503
|
options.rejectUnauthorized = false;
|
|
1171
504
|
options.checkServerIdentity = (_hostValue, cert) => {
|
|
1172
505
|
const fingerprintValue = typeof cert === "object" && cert && "fingerprint256" in cert ? cert.fingerprint256 ?? "" : "";
|
|
1173
|
-
const
|
|
1174
|
-
const
|
|
1175
|
-
|
|
506
|
+
const canonicalFingerprint = normalizeTlsFingerprint(typeof fingerprintValue === "string" ? fingerprintValue : "");
|
|
507
|
+
const fingerprint = canonicalFingerprint ? normalize(canonicalFingerprint) : "";
|
|
508
|
+
const expected = normalize(expectedFingerprint);
|
|
1176
509
|
if (!fingerprint) return /* @__PURE__ */ new Error("Missing server TLS fingerprint");
|
|
1177
510
|
if (fingerprint !== expected) return /* @__PURE__ */ new Error("Server TLS fingerprint mismatch");
|
|
1178
511
|
};
|
|
@@ -1181,12 +514,12 @@ function resolveGatewayWebSocketTransport(params) {
|
|
|
1181
514
|
options,
|
|
1182
515
|
validateSocket: (socket) => {
|
|
1183
516
|
if (!params.tlsFingerprint) return null;
|
|
1184
|
-
const expected = normalize(
|
|
517
|
+
const expected = expectedFingerprint ? normalize(expectedFingerprint) : "";
|
|
1185
518
|
if (!expected) return /* @__PURE__ */ new Error("gateway tls fingerprint missing");
|
|
1186
519
|
const rawSocket = socket["_socket"];
|
|
1187
520
|
if (!rawSocket || typeof rawSocket.getPeerCertificate !== "function") return /* @__PURE__ */ new Error("gateway tls fingerprint unavailable");
|
|
1188
|
-
const
|
|
1189
|
-
const fingerprint = normalize(
|
|
521
|
+
const canonicalFingerprint = normalizeTlsFingerprint(rawSocket.getPeerCertificate()?.fingerprint256 ?? "");
|
|
522
|
+
const fingerprint = canonicalFingerprint ? normalize(canonicalFingerprint) : "";
|
|
1190
523
|
if (!fingerprint) return /* @__PURE__ */ new Error("gateway tls fingerprint unavailable");
|
|
1191
524
|
return fingerprint === expected ? null : /* @__PURE__ */ new Error("gateway tls fingerprint mismatch");
|
|
1192
525
|
}
|
|
@@ -1210,7 +543,7 @@ const DEFAULT_HOST_DEPS = {
|
|
|
1210
543
|
logDebug: () => {},
|
|
1211
544
|
logError: () => {},
|
|
1212
545
|
redactForLog: (message) => message,
|
|
1213
|
-
normalizeTlsFingerprint
|
|
546
|
+
normalizeTlsFingerprint
|
|
1214
547
|
};
|
|
1215
548
|
function resolveHostDeps(overrides) {
|
|
1216
549
|
return Object.fromEntries(Object.entries(DEFAULT_HOST_DEPS).map(([key, fallback]) => [key, overrides?.[key] ?? fallback]));
|
|
@@ -1416,6 +749,9 @@ var GatewayClient = class {
|
|
|
1416
749
|
}
|
|
1417
750
|
createSocket(handlers) {
|
|
1418
751
|
const url = this.opts.url ?? DEFAULT_GATEWAY_CLIENT_URL;
|
|
752
|
+
const configuredEdgeAuthHeaders = this.opts.edgeAuthHeaders;
|
|
753
|
+
const edgeAuthHeaders = configuredEdgeAuthHeaders && Object.keys(configuredEdgeAuthHeaders).length > 0 ? configuredEdgeAuthHeaders : void 0;
|
|
754
|
+
if (edgeAuthHeaders && new URL(url).protocol !== "wss:") throw new GatewayWebSocketTransportConfigurationError("edge auth headers require a wss:// Gateway URL");
|
|
1419
755
|
const handshakeTimeoutMs = resolvePreauthHandshakeTimeoutMs({
|
|
1420
756
|
env: this.opts.env,
|
|
1421
757
|
configuredTimeoutMs: this.opts.preauthHandshakeTimeoutMs
|
|
@@ -1428,7 +764,11 @@ var GatewayClient = class {
|
|
|
1428
764
|
options: {
|
|
1429
765
|
maxPayload: 25 * 1024 * 1024,
|
|
1430
766
|
handshakeTimeout: handshakeTimeoutMs,
|
|
1431
|
-
...this.opts.origin ? { origin: this.opts.origin } : {}
|
|
767
|
+
...this.opts.origin ? { origin: this.opts.origin } : {},
|
|
768
|
+
...edgeAuthHeaders ? {
|
|
769
|
+
followRedirects: false,
|
|
770
|
+
headers: edgeAuthHeaders
|
|
771
|
+
} : {}
|
|
1432
772
|
}
|
|
1433
773
|
});
|
|
1434
774
|
this.deps.beforeConnect();
|
|
@@ -1470,13 +810,16 @@ var GatewayClient = class {
|
|
|
1470
810
|
ws.on("unexpected-response", (request, response) => {
|
|
1471
811
|
readUpgradeErrorBody(response).then((body) => {
|
|
1472
812
|
const statusCode = response.statusCode;
|
|
813
|
+
const rawLocation = response.headers.location;
|
|
814
|
+
const location = rawLocation ? redactSensitiveUrlLikeString(Array.isArray(rawLocation) ? rawLocation[0] ?? "" : rawLocation) : void 0;
|
|
1473
815
|
upgradeError = new GatewayClientRequestError({
|
|
1474
816
|
code: "UNAVAILABLE",
|
|
1475
817
|
message: `gateway rejected websocket upgrade (HTTP ${statusCode ?? "unknown"})${body ? `: ${body}` : ""}`,
|
|
1476
818
|
retryable: true,
|
|
1477
819
|
details: {
|
|
1478
820
|
reason: "websocket-upgrade-rejected",
|
|
1479
|
-
...statusCode === void 0 ? {} : { httpStatus: statusCode }
|
|
821
|
+
...statusCode === void 0 ? {} : { httpStatus: statusCode },
|
|
822
|
+
...location ? { location } : {}
|
|
1480
823
|
}
|
|
1481
824
|
});
|
|
1482
825
|
handlers.error(upgradeError);
|
|
@@ -1734,6 +1077,7 @@ var GatewayClient = class {
|
|
|
1734
1077
|
closeReason: "connect retry"
|
|
1735
1078
|
};
|
|
1736
1079
|
}
|
|
1080
|
+
this.nodeProtocolTransitionPending = false;
|
|
1737
1081
|
const role = this.opts.role ?? "operator";
|
|
1738
1082
|
const detailCode = error instanceof GatewayClientRequestError ? readConnectErrorDetailCode(error.details) : null;
|
|
1739
1083
|
const shouldRetryWithDeviceToken = shouldRetryGatewayWithDeviceToken({
|
|
@@ -1813,7 +1157,7 @@ var GatewayClient = class {
|
|
|
1813
1157
|
const details = context.connectFailure?.error instanceof GatewayClientRequestError ? context.connectFailure.error.details : void 0;
|
|
1814
1158
|
if (context.code === 1013 && context.connectFailure?.reconnectDelayMs !== void 0) return {
|
|
1815
1159
|
retry: true,
|
|
1816
|
-
notify:
|
|
1160
|
+
notify: this.opts.notifyOnStartupRetry === true,
|
|
1817
1161
|
reconnectDelayMs: context.connectFailure.reconnectDelayMs
|
|
1818
1162
|
};
|
|
1819
1163
|
if (info.transientPreHelloCleanClose && this.suppressedTransientPreHelloCleanCloses < MAX_SUPPRESSED_TRANSIENT_PRE_HELLO_CLEAN_CLOSES) {
|
|
@@ -1834,6 +1178,7 @@ var GatewayClient = class {
|
|
|
1834
1178
|
details,
|
|
1835
1179
|
deviceTokenRetryPending: this.pendingDeviceTokenRetry,
|
|
1836
1180
|
tokenMismatchIsTerminal: true,
|
|
1181
|
+
protocolMismatchIsTerminal: !this.nodeProtocolTransitionPending,
|
|
1837
1182
|
clientVersionMismatchIsTerminal: true
|
|
1838
1183
|
})) {
|
|
1839
1184
|
this.notifyReconnectPaused({
|
|
@@ -1969,4 +1314,15 @@ function createGatewayRequestAbortError(method) {
|
|
|
1969
1314
|
return err;
|
|
1970
1315
|
}
|
|
1971
1316
|
//#endregion
|
|
1972
|
-
|
|
1317
|
+
//#region packages/gateway-client/src/cloudflare-access.ts
|
|
1318
|
+
const CF_ACCESS_CLIENT_ID_HEADER = "CF-Access-Client-Id";
|
|
1319
|
+
const CF_ACCESS_CLIENT_SECRET_HEADER = "CF-Access-Client-Secret";
|
|
1320
|
+
/** Build only the two headers Cloudflare Access defines for service-token auth. */
|
|
1321
|
+
function buildCloudflareAccessHeaders(credentials) {
|
|
1322
|
+
return {
|
|
1323
|
+
[CF_ACCESS_CLIENT_ID_HEADER]: credentials.clientId,
|
|
1324
|
+
[CF_ACCESS_CLIENT_SECRET_HEADER]: credentials.clientSecret
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
//#endregion
|
|
1328
|
+
export { CF_ACCESS_CLIENT_ID_HEADER, CF_ACCESS_CLIENT_SECRET_HEADER, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, GatewayBrowserDeviceAuthLifecycle, GatewayClient, GatewayClientRequestError, GatewayClientRequestTimeoutError, GatewayScopeUpgrade, GatewaySessionMessageSubscriptionCoordinator, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, buildCloudflareAccessHeaders, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isLocallyOptimisticSessionMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readSessionMessageIdentity, readSessionMessageSequence, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
|