@openclaw/gateway-client 2026.8.1-beta.2 → 2026.8.1
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-device-auth-Dz6H7eXy.d.mts → browser-device-auth-DoPo-sPB.d.mts} +0 -1
- package/dist/browser.d.mts +6 -7
- package/dist/browser.mjs +1 -1
- package/dist/index.d.mts +14 -4
- package/dist/index.mjs +387 -1013
- package/dist/{protocol-client-BbN-I582.d.mts → protocol-client-BfrZgB1l.d.mts} +2 -2
- package/dist/{protocol-request-D4mVhLxE.d.mts → protocol-request-CcYZeK09.d.mts} +1 -1
- package/dist/{readiness--KX7i8Mq.d.mts → readiness-bH1mOPOT.d.mts} +10 -3
- package/dist/readiness.d.mts +1 -1
- package/dist/scope-upgrade.d.mts +7 -9
- package/dist/{session-subscriptions-uKmTyc3P.mjs → session-subscriptions-BxuNBgqH.mjs} +160 -99
- package/dist/{session-subscriptions-BTNpXybo.d.mts → session-subscriptions-CZOt8niS.d.mts} +12 -10
- package/dist/timeouts.d.mts +15 -16
- package/dist/websocket-data.d.mts +2 -4
- package/package.json +7 -4
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as buildGatewayConnectAuth, D as buildDeviceAuthPayload, E as shouldRetryGatewayWithDeviceToken, O as buildDeviceAuthPayloadV3, S as GatewayBrowserDeviceAuthLifecycle, T as selectGatewayConnectAuth, _ as GatewayProtocolClient, a as createSessionProjection, b as gatewayCredentialScope, c as projectLiveSessionMessage, d as reduceSessionProjectionRunEvent, f as normalizeSessionProjectionRunId, g as shouldPauseGatewayReconnect, h as isRecord, i as resetGatewaySessionMessageSubscriptionCoordinator, k as normalizeDeviceMetadataForAuth, 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 GatewayProtocolRequestError, w as resolveGatewayConnectScopes, x as gatewayOriginScope, y as GatewayProtocolRequestTimeoutError } from "./session-subscriptions-BxuNBgqH.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,8 @@ 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
|
-
|
|
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";
|
|
13
|
+
import { TLSSocket } from "node:tls";
|
|
35
14
|
//#region packages/normalization-core/src/string-coerce.ts
|
|
36
15
|
/** Trims string input and returns null for non-strings or empty strings. */
|
|
37
16
|
function normalizeNullableString(value) {
|
|
@@ -52,966 +31,315 @@ function normalizeLowercaseStringOrEmpty(value) {
|
|
|
52
31
|
return normalizeOptionalLowercaseString(value) ?? "";
|
|
53
32
|
}
|
|
54
33
|
//#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
|
-
|
|
34
|
+
//#region packages/net-policy/src/redact-sensitive-url.ts
|
|
35
|
+
const SENSITIVE_URL_QUERY_PARAM_NAMES = /* @__PURE__ */ new Set([
|
|
36
|
+
"token",
|
|
37
|
+
"key",
|
|
38
|
+
"api_key",
|
|
39
|
+
"apikey",
|
|
40
|
+
"secret",
|
|
41
|
+
"access_token",
|
|
42
|
+
"auth_token",
|
|
43
|
+
"password",
|
|
44
|
+
"pass",
|
|
45
|
+
"passwd",
|
|
46
|
+
"auth",
|
|
47
|
+
"jwt",
|
|
48
|
+
"session",
|
|
49
|
+
"id_token",
|
|
50
|
+
"code",
|
|
51
|
+
"client_secret",
|
|
52
|
+
"app_secret",
|
|
53
|
+
"hook_token",
|
|
54
|
+
"refresh_token",
|
|
55
|
+
"signature",
|
|
56
|
+
"x_amz_signature",
|
|
57
|
+
"x_amz_security_token",
|
|
58
|
+
"private_key",
|
|
59
|
+
"credential",
|
|
60
|
+
"authorization",
|
|
61
|
+
"sig",
|
|
62
|
+
"x_api_key",
|
|
63
|
+
"x_access_token",
|
|
64
|
+
"x_auth_token"
|
|
65
|
+
]);
|
|
66
|
+
const URL_QUERY_NAME_SEPARATOR_RE = /[\p{C}\p{Z}\u115F\u1160\u3164\uFFA0+]/gu;
|
|
67
|
+
const SUFFIXED_OR_SCOPED_TOKEN_QUERY_PARAM_RE = /(?:^|_)token(?:_[a-f0-9]{16,})?$/u;
|
|
68
|
+
const TELEGRAM_BOT_TOKEN_PATH_RE = /\/bot\d{6,}(?::|%3[aA])[A-Za-z0-9_-]{20,}(?=\/|$)/giu;
|
|
69
|
+
const MAX_NESTED_URL_REDACTION_DEPTH = 8;
|
|
70
|
+
const URL_SCHEME_RE = /(?:^|[^a-z\d+.-])[a-z][a-z\d+.-]{0,31}:/iu;
|
|
71
|
+
const SPECIAL_SCHEME_AUTHORITY_RE = /\b(?:https?|wss?|ftp):[\\/]{0,2}[^\\/?#\s]*/giu;
|
|
72
|
+
const SPECIAL_SCHEME_SPILLED_USERINFO_RE = /\b(?:https?|wss?|ftp):[\\/]{0,2}[^\s]*@[^\\/?#\s]*/giu;
|
|
73
|
+
const PROTOCOL_RELATIVE_AUTHORITY_RE = /[\\/]{2,}[^\\/?#\s]*/gu;
|
|
74
|
+
function redactSensitiveUrlPath(value) {
|
|
75
|
+
return value.replace(TELEGRAM_BOT_TOKEN_PATH_RE, "/bot***");
|
|
76
|
+
}
|
|
77
|
+
function normalizeUrlQueryParamName(name) {
|
|
78
|
+
let current = name.replace(URL_QUERY_NAME_SEPARATOR_RE, "");
|
|
79
|
+
for (let depth = 0; depth <= MAX_NESTED_URL_REDACTION_DEPTH; depth += 1) {
|
|
80
|
+
let decoded;
|
|
81
|
+
try {
|
|
82
|
+
decoded = decodeURIComponent(current).replace(URL_QUERY_NAME_SEPARATOR_RE, "");
|
|
83
|
+
} catch {
|
|
102
84
|
return {
|
|
103
|
-
|
|
104
|
-
|
|
85
|
+
value: normalizeLowercaseStringOrEmpty(current).replaceAll("-", "_"),
|
|
86
|
+
unresolvedEncoding: current.includes("%")
|
|
105
87
|
};
|
|
106
88
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
89
|
+
if (decoded === current) return {
|
|
90
|
+
value: normalizeLowercaseStringOrEmpty(current).replaceAll("-", "_"),
|
|
91
|
+
unresolvedEncoding: false
|
|
92
|
+
};
|
|
93
|
+
current = decoded;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
value: normalizeLowercaseStringOrEmpty(current).replaceAll("-", "_"),
|
|
97
|
+
unresolvedEncoding: current.includes("%")
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function looksLikeNestedUrlValue(value) {
|
|
101
|
+
if (URL_SCHEME_RE.test(value)) return true;
|
|
102
|
+
const forwardAuthorityIndex = value.indexOf("//");
|
|
103
|
+
const backwardAuthorityIndex = value.indexOf("\\\\");
|
|
104
|
+
const authorityIndex = forwardAuthorityIndex < 0 ? backwardAuthorityIndex : backwardAuthorityIndex < 0 ? forwardAuthorityIndex : Math.min(forwardAuthorityIndex, backwardAuthorityIndex);
|
|
105
|
+
if (authorityIndex >= 0 && value.includes("@", authorityIndex + 2)) return true;
|
|
106
|
+
const queryIndex = value.search(/[?&]/u);
|
|
107
|
+
if (queryIndex >= 0 && value.includes("=", queryIndex + 1)) return true;
|
|
108
|
+
const fragmentIndex = value.indexOf("#");
|
|
109
|
+
if (fragmentIndex >= 0 && value.includes("=", fragmentIndex + 1)) return true;
|
|
110
|
+
return /%[\da-f]{2}/iu.test(value);
|
|
111
|
+
}
|
|
112
|
+
/** True for auth-like URL query parameter names that should be redacted. */
|
|
113
|
+
function isSensitiveUrlQueryParamName$1(name) {
|
|
114
|
+
const normalized = normalizeUrlQueryParamName(name);
|
|
115
|
+
return normalized.unresolvedEncoding || SENSITIVE_URL_QUERY_PARAM_NAMES.has(normalized.value) || SUFFIXED_OR_SCOPED_TOKEN_QUERY_PARAM_RE.test(normalized.value);
|
|
116
|
+
}
|
|
117
|
+
function redactDirectSensitiveUrl(value) {
|
|
118
|
+
try {
|
|
119
|
+
const parsed = new URL(value);
|
|
120
|
+
let mutated = false;
|
|
121
|
+
const redactedPath = redactSensitiveUrlPath(parsed.pathname);
|
|
122
|
+
if (redactedPath !== parsed.pathname) {
|
|
123
|
+
parsed.pathname = redactedPath;
|
|
124
|
+
mutated = true;
|
|
119
125
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
throw new Error(`ipaddr: cannot parse ${string} as octal`);
|
|
125
|
-
}
|
|
126
|
-
return parseInt(string, 10);
|
|
126
|
+
if (parsed.username || parsed.password) {
|
|
127
|
+
parsed.username = parsed.username ? "***" : "";
|
|
128
|
+
parsed.password = parsed.password ? "***" : "";
|
|
129
|
+
mutated = true;
|
|
127
130
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
for (const key of Array.from(parsed.searchParams.keys())) if (isSensitiveUrlQueryParamName$1(key)) {
|
|
132
|
+
parsed.searchParams.set(key, "***");
|
|
133
|
+
mutated = true;
|
|
131
134
|
}
|
|
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++;
|
|
135
|
+
return mutated ? parsed.toString() : value;
|
|
136
|
+
} catch {
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function redactQueryString(value, depth) {
|
|
141
|
+
const params = new URLSearchParams(value);
|
|
142
|
+
const entries = Array.from(params.entries());
|
|
143
|
+
const redactedEntries = [];
|
|
144
|
+
const seenSensitiveKeys = /* @__PURE__ */ new Set();
|
|
145
|
+
let mutated = false;
|
|
146
|
+
for (const [key, entryValue] of entries) {
|
|
147
|
+
if (isSensitiveUrlQueryParamName$1(key)) {
|
|
148
|
+
mutated = true;
|
|
149
|
+
if (!seenSensitiveKeys.has(key)) {
|
|
150
|
+
seenSensitiveKeys.add(key);
|
|
151
|
+
redactedEntries.push([key, "***"]);
|
|
456
152
|
}
|
|
457
|
-
|
|
458
|
-
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const redactedKey = redactNestedUrlValue(key, depth + 1);
|
|
156
|
+
const redactedValue = redactNestedUrlValue(entryValue, depth + 1);
|
|
157
|
+
if (redactedKey !== key || redactedValue !== entryValue) mutated = true;
|
|
158
|
+
redactedEntries.push([redactedKey, redactedValue]);
|
|
159
|
+
}
|
|
160
|
+
if (!mutated) return value;
|
|
161
|
+
const redactedParams = new URLSearchParams();
|
|
162
|
+
for (const [key, entryValue] of redactedEntries) redactedParams.append(key, entryValue);
|
|
163
|
+
return redactedParams.toString();
|
|
164
|
+
}
|
|
165
|
+
function redactUrlLikeFallback(value) {
|
|
166
|
+
return redactSensitiveUrlPath(redactEmbeddedUrlUserInfo(value).replace(/([?&])([^=&]+)=([^&]*)/g, (match, prefix, key) => isSensitiveUrlQueryParamName$1(key) ? `${prefix}${key}=***` : match));
|
|
167
|
+
}
|
|
168
|
+
function redactAuthorityUserInfo(candidate, authorityStart) {
|
|
169
|
+
const authority = candidate.slice(authorityStart);
|
|
170
|
+
const userInfoEnd = authority.lastIndexOf("@");
|
|
171
|
+
if (userInfoEnd < 0) return candidate;
|
|
172
|
+
return `${candidate.slice(0, authorityStart)}***:***@${authority.slice(userInfoEnd + 1)}`;
|
|
173
|
+
}
|
|
174
|
+
function redactEmbeddedUrlUserInfo(value) {
|
|
175
|
+
return value.replace(SPECIAL_SCHEME_AUTHORITY_RE, (candidate) => {
|
|
176
|
+
let authorityStart = candidate.indexOf(":") + 1;
|
|
177
|
+
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
178
|
+
return redactAuthorityUserInfo(candidate, authorityStart);
|
|
179
|
+
}).replace(SPECIAL_SCHEME_SPILLED_USERINFO_RE, (candidate) => {
|
|
180
|
+
let authorityStart = candidate.indexOf(":") + 1;
|
|
181
|
+
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
182
|
+
const userInfoEnd = candidate.lastIndexOf("@");
|
|
183
|
+
const firstReservedDelimiter = candidate.slice(authorityStart).search(/[\\/?#]/u);
|
|
184
|
+
if (userInfoEnd < 0 || firstReservedDelimiter < 0) return candidate;
|
|
185
|
+
const absoluteReservedDelimiter = authorityStart + firstReservedDelimiter;
|
|
186
|
+
if (absoluteReservedDelimiter >= userInfoEnd) return candidate;
|
|
187
|
+
const credentialSeparator = candidate.indexOf(":", authorityStart);
|
|
188
|
+
if (credentialSeparator < 0 || credentialSeparator > absoluteReservedDelimiter) return candidate;
|
|
189
|
+
const authorityPrefix = candidate.slice(authorityStart, absoluteReservedDelimiter);
|
|
190
|
+
const possiblePort = candidate.slice(credentialSeparator + 1, absoluteReservedDelimiter);
|
|
191
|
+
if (/^\d+$/u.test(possiblePort) || /^\[[^\]]+\](?::\d+)?$/u.test(authorityPrefix)) return candidate;
|
|
192
|
+
return `${candidate.slice(0, authorityStart)}***:***@${candidate.slice(userInfoEnd + 1)}`;
|
|
193
|
+
}).replace(PROTOCOL_RELATIVE_AUTHORITY_RE, (candidate) => {
|
|
194
|
+
let authorityStart = 0;
|
|
195
|
+
while (authorityStart < candidate.length && (candidate[authorityStart] === "/" || candidate[authorityStart] === "\\")) authorityStart += 1;
|
|
196
|
+
return redactAuthorityUserInfo(candidate, authorityStart);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function hasUnresolvedEmbeddedUrlUserInfo(value) {
|
|
200
|
+
for (const match of value.matchAll(/(?:\b(?:https?|wss?|ftp):[\\/]{0,2}|[\\/]{2,})/giu)) {
|
|
201
|
+
const remainder = value.slice((match.index ?? 0) + match[0].length);
|
|
202
|
+
const userInfoEnd = remainder.search(/(?<!\*\*\*:\*\*\*)@/u);
|
|
203
|
+
const authorityEnd = remainder.search(/[\\/?#]/u);
|
|
204
|
+
const pathBeforeAt = remainder.slice(authorityEnd + 1, userInfoEnd);
|
|
205
|
+
if (userInfoEnd >= 0 && (authorityEnd < 0 || userInfoEnd <= authorityEnd || remainder[authorityEnd] === "/" && (pathBeforeAt.includes(":") || /^[^/?#\s]+\.[^/?#\s]+(?:[/?#]|$)/u.test(remainder.slice(userInfoEnd + 1))))) return true;
|
|
206
|
+
}
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
function redactRelativeUrlFragment(value, depth) {
|
|
210
|
+
const fragmentIndex = value.indexOf("#");
|
|
211
|
+
if (fragmentIndex < 0) return value;
|
|
212
|
+
const fragment = value.slice(fragmentIndex + 1);
|
|
213
|
+
const redactedFragment = redactFragment(fragment, depth + 1);
|
|
214
|
+
return redactedFragment === fragment ? value : `${value.slice(0, fragmentIndex + 1)}${redactedFragment}`;
|
|
215
|
+
}
|
|
216
|
+
function redactFragment(value, depth) {
|
|
217
|
+
if (!value) return value;
|
|
218
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH && looksLikeNestedUrlValue(value)) return "***";
|
|
219
|
+
const wholeUrl = redactSensitiveUrlAtDepth(value, depth);
|
|
220
|
+
if (wholeUrl.parsedWholeUrl) return redactUrlLikeFallback(wholeUrl.value);
|
|
221
|
+
const candidate = value;
|
|
222
|
+
const firstQueryDelimiter = candidate.search(/[?&]/u);
|
|
223
|
+
const firstEquals = candidate.indexOf("=");
|
|
224
|
+
if (firstEquals >= 0 && (firstQueryDelimiter < 0 || firstEquals < firstQueryDelimiter)) return redactQueryString(candidate, depth);
|
|
225
|
+
const hashRouterQueryIndex = candidate.indexOf("?");
|
|
226
|
+
if (hashRouterQueryIndex >= 0) {
|
|
227
|
+
const redactedQuery = redactQueryString(candidate.slice(hashRouterQueryIndex + 1), depth);
|
|
228
|
+
return `${redactEncodedUrlLikeString(redactUrlLikeFallback(candidate.slice(0, hashRouterQueryIndex + 1)), depth + 1)}${redactedQuery}`;
|
|
229
|
+
}
|
|
230
|
+
const fallback = redactUrlLikeFallback(candidate);
|
|
231
|
+
if (!looksLikeNestedUrlValue(fallback)) return fallback;
|
|
232
|
+
let decoded;
|
|
233
|
+
try {
|
|
234
|
+
decoded = decodeURIComponent(fallback);
|
|
235
|
+
} catch {
|
|
236
|
+
return "***";
|
|
237
|
+
}
|
|
238
|
+
if (decoded === fallback) return fallback;
|
|
239
|
+
const redactedDecoded = redactFragment(decoded, depth + 1);
|
|
240
|
+
return redactedDecoded === decoded ? fallback : encodeURIComponent(redactedDecoded);
|
|
241
|
+
}
|
|
242
|
+
function redactEncodedNestedUrlPath(value, depth) {
|
|
243
|
+
if (!looksLikeNestedUrlValue(value)) return value;
|
|
244
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH) return "***";
|
|
245
|
+
let decoded;
|
|
246
|
+
try {
|
|
247
|
+
decoded = decodeURIComponent(value);
|
|
248
|
+
} catch {
|
|
249
|
+
return "***";
|
|
250
|
+
}
|
|
251
|
+
if (decoded === value) return value;
|
|
252
|
+
const direct = redactSensitiveUrlLikeStringAtDepth(decoded, depth);
|
|
253
|
+
if (direct.value !== decoded || hasUnresolvedEmbeddedUrlUserInfo(decoded)) return direct.value !== decoded ? direct.value : "***";
|
|
254
|
+
if (direct.parsedWholeUrl) return value;
|
|
255
|
+
const nested = redactEncodedNestedUrlPath(decoded, depth + 1);
|
|
256
|
+
return nested === decoded ? value : nested;
|
|
257
|
+
}
|
|
258
|
+
function redactSensitiveUrlAtDepth(value, depth) {
|
|
259
|
+
try {
|
|
260
|
+
const directRedaction = redactDirectSensitiveUrl(value);
|
|
261
|
+
const parsed = new URL(directRedaction);
|
|
262
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH) return {
|
|
263
|
+
value: "***",
|
|
264
|
+
parsedWholeUrl: true
|
|
459
265
|
};
|
|
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";
|
|
266
|
+
let mutated = directRedaction !== value;
|
|
267
|
+
const redactedNestedPath = redactEmbeddedUrlUserInfo(redactEncodedNestedUrlPath(parsed.pathname, depth + 1));
|
|
268
|
+
if (redactedNestedPath !== parsed.pathname) {
|
|
269
|
+
const originalPath = parsed.pathname;
|
|
270
|
+
parsed.pathname = redactedNestedPath;
|
|
271
|
+
if (parsed.pathname === originalPath) return {
|
|
272
|
+
value: directRedaction,
|
|
273
|
+
parsedWholeUrl: false
|
|
718
274
|
};
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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;
|
|
765
|
-
};
|
|
766
|
-
IPv6.prototype.range = function() {
|
|
767
|
-
return ipaddr.subnetMatch(this, this.SpecialRanges);
|
|
768
|
-
};
|
|
769
|
-
IPv6.prototype.toByteArray = function() {
|
|
770
|
-
let part;
|
|
771
|
-
const bytes = [];
|
|
772
|
-
const ref = this.parts;
|
|
773
|
-
for (let i = 0; i < ref.length; i++) {
|
|
774
|
-
part = ref[i];
|
|
775
|
-
bytes.push(part >> 8);
|
|
776
|
-
bytes.push(part & 255);
|
|
777
|
-
}
|
|
778
|
-
return bytes;
|
|
779
|
-
};
|
|
780
|
-
IPv6.prototype.toFixedLengthString = function() {
|
|
781
|
-
const addr = (function() {
|
|
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;
|
|
275
|
+
mutated = true;
|
|
276
|
+
}
|
|
277
|
+
const redactedQuery = redactQueryString(parsed.search.slice(1), depth);
|
|
278
|
+
if (redactedQuery !== parsed.search.slice(1)) {
|
|
279
|
+
parsed.search = redactedQuery;
|
|
280
|
+
mutated = true;
|
|
281
|
+
}
|
|
282
|
+
const fragment = parsed.hash.slice(1);
|
|
283
|
+
const redactedHash = redactFragment(fragment, depth + 1);
|
|
284
|
+
if (redactedHash !== fragment) {
|
|
285
|
+
parsed.hash = redactedHash;
|
|
286
|
+
mutated = true;
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
value: mutated ? parsed.toString() : value,
|
|
290
|
+
parsedWholeUrl: true
|
|
996
291
|
};
|
|
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;
|
|
292
|
+
} catch {
|
|
293
|
+
return {
|
|
294
|
+
value,
|
|
295
|
+
parsedWholeUrl: false
|
|
1009
296
|
};
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function redactSensitiveUrlLikeStringAtDepth(value, depth) {
|
|
300
|
+
const redactedUrl = redactSensitiveUrlAtDepth(value, depth);
|
|
301
|
+
if (redactedUrl.parsedWholeUrl) return redactedUrl;
|
|
302
|
+
return {
|
|
303
|
+
value: redactEncodedUrlLikeString(redactRelativeUrlFragment(redactUrlLikeFallback(redactedUrl.value), depth), depth + 1),
|
|
304
|
+
parsedWholeUrl: false
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function redactEncodedUrlLikeString(value, depth) {
|
|
308
|
+
if (!looksLikeNestedUrlValue(value)) return value;
|
|
309
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH) return "***";
|
|
310
|
+
let decoded;
|
|
311
|
+
try {
|
|
312
|
+
decoded = decodeURIComponent(value);
|
|
313
|
+
} catch {
|
|
314
|
+
return "***";
|
|
315
|
+
}
|
|
316
|
+
if (decoded === value) return value;
|
|
317
|
+
const redactedDecoded = redactSensitiveUrlLikeStringAtDepth(decoded, depth + 1);
|
|
318
|
+
if (redactedDecoded.value !== decoded || redactedDecoded.parsedWholeUrl) return redactedDecoded.value === decoded ? value : redactedDecoded.value;
|
|
319
|
+
return hasUnresolvedEmbeddedUrlUserInfo(decoded) ? "***" : value;
|
|
320
|
+
}
|
|
321
|
+
function redactNestedUrlValue(value, depth) {
|
|
322
|
+
if (!looksLikeNestedUrlValue(value)) return value;
|
|
323
|
+
if (depth > MAX_NESTED_URL_REDACTION_DEPTH) return "***";
|
|
324
|
+
const direct = redactSensitiveUrlLikeStringAtDepth(value, depth);
|
|
325
|
+
if (direct.value !== value) return direct.value;
|
|
326
|
+
if (hasUnresolvedEmbeddedUrlUserInfo(value)) return "***";
|
|
327
|
+
if (direct.parsedWholeUrl) return value;
|
|
328
|
+
let decoded;
|
|
329
|
+
try {
|
|
330
|
+
decoded = decodeURIComponent(value);
|
|
331
|
+
} catch {
|
|
332
|
+
return "***";
|
|
333
|
+
}
|
|
334
|
+
if (decoded === value || !looksLikeNestedUrlValue(decoded)) return value;
|
|
335
|
+
const redactedDecoded = redactNestedUrlValue(decoded, depth + 1);
|
|
336
|
+
return redactedDecoded === decoded ? value : encodeURIComponent(redactedDecoded);
|
|
337
|
+
}
|
|
338
|
+
/** Redacts sensitive URL-looking substrings even when the full value is not a valid URL. */
|
|
339
|
+
function redactSensitiveUrlLikeString(value) {
|
|
340
|
+
return redactSensitiveUrlLikeStringAtDepth(value, 0).value;
|
|
341
|
+
}
|
|
342
|
+
ipaddr.IPv4.parse("198.18.0.0");
|
|
1015
343
|
function stripIpv6Brackets(value) {
|
|
1016
344
|
if (value.startsWith("[") && value.endsWith("]")) return value.slice(1, -1);
|
|
1017
345
|
return value;
|
|
@@ -1034,7 +362,7 @@ function normalizeIpParseInput(raw) {
|
|
|
1034
362
|
function parseCanonicalIpAddress(raw) {
|
|
1035
363
|
const normalized = normalizeIpParseInput(raw);
|
|
1036
364
|
if (!normalized) return;
|
|
1037
|
-
return
|
|
365
|
+
return ipaddr.IPv4.isValidFourPartDecimal(normalized) || ipaddr.IPv6.isValid(normalized) ? ipaddr.parse(normalized) : void 0;
|
|
1038
366
|
}
|
|
1039
367
|
/** Normalizes canonical IP literals and maps IPv4-mapped IPv6 addresses to IPv4 text. */
|
|
1040
368
|
function normalizeIpAddress(raw) {
|
|
@@ -1056,8 +384,12 @@ function normalizeGatewayErrorText(value) {
|
|
|
1056
384
|
function isSensitiveUrlQueryParamName(key) {
|
|
1057
385
|
return /(?:token|password|secret|key|auth|credential)/iu.test(key);
|
|
1058
386
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
387
|
+
const SHA256_HEX_FINGERPRINT = /^[a-fA-F0-9]{64}$/u;
|
|
388
|
+
const SHA256_COLON_FINGERPRINT = /^(?:[a-fA-F0-9]{2}:){31}[a-fA-F0-9]{2}$/u;
|
|
389
|
+
function normalizeTlsFingerprint(fingerprint) {
|
|
390
|
+
const value = (fingerprint ?? "").trim().replace(/^sha256:/iu, "");
|
|
391
|
+
if (SHA256_HEX_FINGERPRINT.test(value)) return value.toLowerCase();
|
|
392
|
+
return SHA256_COLON_FINGERPRINT.test(value) ? value.replaceAll(":", "").toLowerCase() : "";
|
|
1061
393
|
}
|
|
1062
394
|
function parseHostForAddressChecks(host) {
|
|
1063
395
|
if (!host) return null;
|
|
@@ -1153,6 +485,7 @@ function isSecureWebSocketUrl(rawUrl, options) {
|
|
|
1153
485
|
}
|
|
1154
486
|
}
|
|
1155
487
|
var GatewayWebSocketTransportConfigurationError = class extends Error {};
|
|
488
|
+
var GatewayWebSocketTlsPinError = class extends Error {};
|
|
1156
489
|
function resolveGatewayWebSocketTransport(params) {
|
|
1157
490
|
const usesTls = isWssUrl(params.url);
|
|
1158
491
|
if (params.tlsFingerprint && !usesTls) throw new GatewayWebSocketTransportConfigurationError("gateway tls fingerprint requires wss:// gateway url");
|
|
@@ -1164,32 +497,41 @@ function resolveGatewayWebSocketTransport(params) {
|
|
|
1164
497
|
} catch {}
|
|
1165
498
|
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
499
|
}
|
|
1167
|
-
const normalize = params.normalizeTlsFingerprint ??
|
|
500
|
+
const normalize = params.normalizeTlsFingerprint ?? normalizeTlsFingerprint;
|
|
501
|
+
const expectedFingerprint = params.tlsFingerprint ? normalizeTlsFingerprint(params.tlsFingerprint) : void 0;
|
|
502
|
+
if (params.tlsFingerprint && !expectedFingerprint) throw new GatewayWebSocketTransportConfigurationError("gateway tls fingerprint must be a SHA-256 fingerprint");
|
|
1168
503
|
const options = { ...params.options };
|
|
1169
|
-
if (usesTls &&
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
const
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
504
|
+
if (usesTls && expectedFingerprint) applyGatewayWebSocketTlsPin(options, expectedFingerprint, normalize);
|
|
505
|
+
return { options };
|
|
506
|
+
}
|
|
507
|
+
function applyGatewayWebSocketTlsPin(options, expectedFingerprint, normalize = normalizeTlsFingerprint) {
|
|
508
|
+
options.rejectUnauthorized = false;
|
|
509
|
+
const headers = { ...options.headers };
|
|
510
|
+
const deferredHeaders = Object.entries(headers).filter(([key]) => key.toLowerCase() === "expect");
|
|
511
|
+
for (const [key] of deferredHeaders) delete headers[key];
|
|
512
|
+
options.headers = headers;
|
|
513
|
+
options.finishRequest = (request) => {
|
|
514
|
+
request.once("socket", (socket) => {
|
|
515
|
+
if (!(socket instanceof TLSSocket)) {
|
|
516
|
+
request.destroy(new GatewayWebSocketTlsPinError("gateway tls fingerprint unavailable"));
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
const validatePin = () => {
|
|
520
|
+
if (request.destroyed) return;
|
|
521
|
+
const canonicalFingerprint = normalizeTlsFingerprint(socket.getPeerCertificate()?.fingerprint256);
|
|
522
|
+
const fingerprint = canonicalFingerprint ? normalize(canonicalFingerprint) : "";
|
|
523
|
+
if (!fingerprint || fingerprint !== normalize(expectedFingerprint)) {
|
|
524
|
+
request.destroy(new GatewayWebSocketTlsPinError(fingerprint ? "gateway tls fingerprint mismatch" : "gateway tls fingerprint unavailable"));
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
for (const [key, value] of deferredHeaders) if (value !== void 0) request.setHeader(key, value);
|
|
528
|
+
request.end();
|
|
529
|
+
};
|
|
530
|
+
if (socket.secureConnecting) {
|
|
531
|
+
socket.once("secureConnect", validatePin);
|
|
532
|
+
request.once("close", () => socket.off("secureConnect", validatePin));
|
|
533
|
+
} else validatePin();
|
|
534
|
+
});
|
|
1193
535
|
};
|
|
1194
536
|
}
|
|
1195
537
|
//#endregion
|
|
@@ -1210,7 +552,7 @@ const DEFAULT_HOST_DEPS = {
|
|
|
1210
552
|
logDebug: () => {},
|
|
1211
553
|
logError: () => {},
|
|
1212
554
|
redactForLog: (message) => message,
|
|
1213
|
-
normalizeTlsFingerprint
|
|
555
|
+
normalizeTlsFingerprint
|
|
1214
556
|
};
|
|
1215
557
|
function resolveHostDeps(overrides) {
|
|
1216
558
|
return Object.fromEntries(Object.entries(DEFAULT_HOST_DEPS).map(([key, fallback]) => [key, overrides?.[key] ?? fallback]));
|
|
@@ -1370,6 +712,11 @@ var GatewayClient = class {
|
|
|
1370
712
|
},
|
|
1371
713
|
notifyStoppedClose: true,
|
|
1372
714
|
onConnectError: (error) => this.notifyConnectError(error),
|
|
715
|
+
onReconnectStopped: (error) => this.notifyReconnectPaused({
|
|
716
|
+
code: 1008,
|
|
717
|
+
reason: error.message,
|
|
718
|
+
detailCode: null
|
|
719
|
+
}),
|
|
1373
720
|
onParseError: (error) => this.logDebug(`gateway client parse error: ${formatGatewayClientErrorForLog(error)}`),
|
|
1374
721
|
onEvent: (event) => this.opts.onEvent?.(event),
|
|
1375
722
|
onGap: (info) => this.opts.onGap?.(info),
|
|
@@ -1416,6 +763,9 @@ var GatewayClient = class {
|
|
|
1416
763
|
}
|
|
1417
764
|
createSocket(handlers) {
|
|
1418
765
|
const url = this.opts.url ?? DEFAULT_GATEWAY_CLIENT_URL;
|
|
766
|
+
const configuredEdgeAuthHeaders = this.opts.edgeAuthHeaders;
|
|
767
|
+
const edgeAuthHeaders = configuredEdgeAuthHeaders && Object.keys(configuredEdgeAuthHeaders).length > 0 ? configuredEdgeAuthHeaders : void 0;
|
|
768
|
+
if (edgeAuthHeaders && new URL(url).protocol !== "wss:") throw new GatewayWebSocketTransportConfigurationError("edge auth headers require a wss:// Gateway URL");
|
|
1419
769
|
const handshakeTimeoutMs = resolvePreauthHandshakeTimeoutMs({
|
|
1420
770
|
env: this.opts.env,
|
|
1421
771
|
configuredTimeoutMs: this.opts.preauthHandshakeTimeoutMs
|
|
@@ -1428,7 +778,11 @@ var GatewayClient = class {
|
|
|
1428
778
|
options: {
|
|
1429
779
|
maxPayload: 25 * 1024 * 1024,
|
|
1430
780
|
handshakeTimeout: handshakeTimeoutMs,
|
|
1431
|
-
...this.opts.origin ? { origin: this.opts.origin } : {}
|
|
781
|
+
...this.opts.origin ? { origin: this.opts.origin } : {},
|
|
782
|
+
...edgeAuthHeaders ? {
|
|
783
|
+
followRedirects: false,
|
|
784
|
+
headers: edgeAuthHeaders
|
|
785
|
+
} : {}
|
|
1432
786
|
}
|
|
1433
787
|
});
|
|
1434
788
|
this.deps.beforeConnect();
|
|
@@ -1451,14 +805,8 @@ var GatewayClient = class {
|
|
|
1451
805
|
this.transportValidated = false;
|
|
1452
806
|
let upgradeError;
|
|
1453
807
|
ws.on("open", () => {
|
|
1454
|
-
handlers.open();
|
|
1455
|
-
const tlsError = transport.validateSocket(ws);
|
|
1456
|
-
if (tlsError) {
|
|
1457
|
-
handlers.error(tlsError);
|
|
1458
|
-
ws.close(1008, tlsError.message);
|
|
1459
|
-
return;
|
|
1460
|
-
}
|
|
1461
808
|
this.transportValidated = true;
|
|
809
|
+
handlers.open();
|
|
1462
810
|
});
|
|
1463
811
|
ws.on("message", (data) => handlers.message(rawDataToString(data)));
|
|
1464
812
|
ws.on("close", (code, reason) => {
|
|
@@ -1470,13 +818,26 @@ var GatewayClient = class {
|
|
|
1470
818
|
ws.on("unexpected-response", (request, response) => {
|
|
1471
819
|
readUpgradeErrorBody(response).then((body) => {
|
|
1472
820
|
const statusCode = response.statusCode;
|
|
821
|
+
let gatewayError;
|
|
822
|
+
try {
|
|
823
|
+
const parsed = JSON.parse(body);
|
|
824
|
+
const parsedError = isRecord(parsed) ? parsed.error : void 0;
|
|
825
|
+
gatewayError = isRecord(parsedError) ? parsedError : void 0;
|
|
826
|
+
} catch {}
|
|
827
|
+
const rawLocation = response.headers.location;
|
|
828
|
+
const location = rawLocation ? redactSensitiveUrlLikeString(Array.isArray(rawLocation) ? rawLocation[0] ?? "" : rawLocation) : void 0;
|
|
1473
829
|
upgradeError = new GatewayClientRequestError({
|
|
1474
830
|
code: "UNAVAILABLE",
|
|
1475
831
|
message: `gateway rejected websocket upgrade (HTTP ${statusCode ?? "unknown"})${body ? `: ${body}` : ""}`,
|
|
1476
832
|
retryable: true,
|
|
1477
833
|
details: {
|
|
1478
834
|
reason: "websocket-upgrade-rejected",
|
|
1479
|
-
...statusCode === void 0 ? {} : { httpStatus: statusCode }
|
|
835
|
+
...statusCode === void 0 ? {} : { httpStatus: statusCode },
|
|
836
|
+
...location ? { location } : {},
|
|
837
|
+
...typeof gatewayError?.type === "string" ? {
|
|
838
|
+
gatewayErrorType: gatewayError.type,
|
|
839
|
+
...typeof gatewayError.message === "string" ? { gatewayErrorMessage: gatewayError.message } : {}
|
|
840
|
+
} : {}
|
|
1480
841
|
}
|
|
1481
842
|
});
|
|
1482
843
|
handlers.error(upgradeError);
|
|
@@ -1734,6 +1095,7 @@ var GatewayClient = class {
|
|
|
1734
1095
|
closeReason: "connect retry"
|
|
1735
1096
|
};
|
|
1736
1097
|
}
|
|
1098
|
+
this.nodeProtocolTransitionPending = false;
|
|
1737
1099
|
const role = this.opts.role ?? "operator";
|
|
1738
1100
|
const detailCode = error instanceof GatewayClientRequestError ? readConnectErrorDetailCode(error.details) : null;
|
|
1739
1101
|
const shouldRetryWithDeviceToken = shouldRetryGatewayWithDeviceToken({
|
|
@@ -1813,7 +1175,7 @@ var GatewayClient = class {
|
|
|
1813
1175
|
const details = context.connectFailure?.error instanceof GatewayClientRequestError ? context.connectFailure.error.details : void 0;
|
|
1814
1176
|
if (context.code === 1013 && context.connectFailure?.reconnectDelayMs !== void 0) return {
|
|
1815
1177
|
retry: true,
|
|
1816
|
-
notify:
|
|
1178
|
+
notify: this.opts.notifyOnStartupRetry === true,
|
|
1817
1179
|
reconnectDelayMs: context.connectFailure.reconnectDelayMs
|
|
1818
1180
|
};
|
|
1819
1181
|
if (info.transientPreHelloCleanClose && this.suppressedTransientPreHelloCleanCloses < MAX_SUPPRESSED_TRANSIENT_PRE_HELLO_CLEAN_CLOSES) {
|
|
@@ -1834,6 +1196,7 @@ var GatewayClient = class {
|
|
|
1834
1196
|
details,
|
|
1835
1197
|
deviceTokenRetryPending: this.pendingDeviceTokenRetry,
|
|
1836
1198
|
tokenMismatchIsTerminal: true,
|
|
1199
|
+
protocolMismatchIsTerminal: !this.nodeProtocolTransitionPending,
|
|
1837
1200
|
clientVersionMismatchIsTerminal: true
|
|
1838
1201
|
})) {
|
|
1839
1202
|
this.notifyReconnectPaused({
|
|
@@ -1969,4 +1332,15 @@ function createGatewayRequestAbortError(method) {
|
|
|
1969
1332
|
return err;
|
|
1970
1333
|
}
|
|
1971
1334
|
//#endregion
|
|
1972
|
-
|
|
1335
|
+
//#region packages/gateway-client/src/cloudflare-access.ts
|
|
1336
|
+
const CF_ACCESS_CLIENT_ID_HEADER = "CF-Access-Client-Id";
|
|
1337
|
+
const CF_ACCESS_CLIENT_SECRET_HEADER = "CF-Access-Client-Secret";
|
|
1338
|
+
/** Build only the two headers Cloudflare Access defines for service-token auth. */
|
|
1339
|
+
function buildCloudflareAccessHeaders(credentials) {
|
|
1340
|
+
return {
|
|
1341
|
+
[CF_ACCESS_CLIENT_ID_HEADER]: credentials.clientId,
|
|
1342
|
+
[CF_ACCESS_CLIENT_SECRET_HEADER]: credentials.clientSecret
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
//#endregion
|
|
1346
|
+
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 };
|