@checkly/playwright-core 1.51.16 → 1.51.17-beta.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/lib/checkly/secretsFilter.js +10 -5
- package/lib/common/socksProxy.js +569 -0
- package/lib/common/timeoutSettings.js +73 -0
- package/lib/common/types.js +5 -0
- package/lib/image_tools/colorUtils.js +98 -0
- package/lib/image_tools/compare.js +108 -0
- package/lib/image_tools/imageChannel.js +70 -0
- package/lib/image_tools/stats.js +102 -0
- package/lib/protocol/transport.js +82 -0
- package/lib/third_party/diff_match_patch.js +2222 -0
- package/lib/utils/ascii.js +31 -0
- package/lib/utils/comparators.js +171 -0
- package/lib/utils/crypto.js +174 -0
- package/lib/utils/debug.js +46 -0
- package/lib/utils/debugLogger.js +91 -0
- package/lib/utils/env.js +49 -0
- package/lib/utils/eventsHelper.js +38 -0
- package/lib/utils/happy-eyeballs.js +210 -0
- package/lib/utils/headers.js +52 -0
- package/lib/utils/hostPlatform.js +133 -0
- package/lib/utils/httpServer.js +237 -0
- package/lib/utils/linuxUtils.js +78 -0
- package/lib/utils/manualPromise.js +109 -0
- package/lib/utils/multimap.js +75 -0
- package/lib/utils/network.js +160 -0
- package/lib/utils/processLauncher.js +248 -0
- package/lib/utils/profiler.js +53 -0
- package/lib/utils/rtti.js +44 -0
- package/lib/utils/semaphore.js +51 -0
- package/lib/utils/spawnAsync.js +45 -0
- package/lib/utils/task.js +58 -0
- package/lib/utils/time.js +37 -0
- package/lib/utils/traceUtils.js +44 -0
- package/lib/utils/userAgent.js +105 -0
- package/lib/utils/wsServer.js +127 -0
- package/lib/utils/zipFile.js +75 -0
- package/lib/vite/recorder/assets/codeMirrorModule-DrMbgOIo.js +16684 -0
- package/lib/vite/recorder/assets/codeMirrorModule-DuST8d_k.css +344 -0
- package/lib/vite/recorder/assets/index-5NM3V7eb.css +2524 -0
- package/lib/vite/recorder/assets/index-CT-scFHn.js +16848 -0
- package/lib/vite/recorder/index.html +2 -2
- package/lib/vite/traceViewer/assets/codeMirrorModule-CB-2okZ8.js +16684 -0
- package/lib/vite/traceViewer/assets/defaultSettingsView-CBiB4avC.js +217 -0
- package/lib/vite/traceViewer/assets/inspectorTab-CwgfffWb.js +25143 -0
- package/lib/vite/traceViewer/assets/workbench-CWZselvp.js +2470 -0
- package/lib/vite/traceViewer/assets/xtermModule-Es_gt_u7.js +5994 -0
- package/lib/vite/traceViewer/codeMirrorModule.DuST8d_k.css +344 -0
- package/lib/vite/traceViewer/defaultSettingsView.Dp3b_92q.css +41 -0
- package/lib/vite/traceViewer/embedded.BeldSa2G.css +68 -0
- package/lib/vite/traceViewer/embedded.gzudoghF.js +106 -0
- package/lib/vite/traceViewer/embedded.html +6 -6
- package/lib/vite/traceViewer/index.DilotR1h.js +314 -0
- package/lib/vite/traceViewer/index.QewjJ85u.css +131 -0
- package/lib/vite/traceViewer/index.html +8 -8
- package/lib/vite/traceViewer/inspectorTab.DnGm18kV.css +3178 -0
- package/lib/vite/traceViewer/recorder.DLgqV9db.css +15 -0
- package/lib/vite/traceViewer/recorder.DVrkq3Um.js +551 -0
- package/lib/vite/traceViewer/recorder.html +4 -4
- package/lib/vite/traceViewer/uiMode.C9_OcpPU.js +1756 -0
- package/lib/vite/traceViewer/uiMode.c5ORgcrX.css +1424 -0
- package/lib/vite/traceViewer/uiMode.html +8 -8
- package/lib/vite/traceViewer/workbench.xUZSA8PY.css +787 -0
- package/lib/vite/traceViewer/xtermModule.EsaqrrTX.css +209 -0
- package/package.json +1 -1
- package/lib/vite/recorder/assets/codeMirrorModule-B9YMkrwa.js +0 -24
- package/lib/vite/recorder/assets/codeMirrorModule-C3UTv-Ge.css +0 -1
- package/lib/vite/recorder/assets/index-ELPgmkwA.js +0 -184
- package/lib/vite/recorder/assets/index-eHBmevrY.css +0 -1
- package/lib/vite/traceViewer/assets/codeMirrorModule-gU1OOCQO.js +0 -24
- package/lib/vite/traceViewer/assets/defaultSettingsView-B5n_FjMx.js +0 -1
- package/lib/vite/traceViewer/assets/inspectorTab-6Tru8Mn_.js +0 -235
- package/lib/vite/traceViewer/assets/workbench-B_Nj4NA2.js +0 -25
- package/lib/vite/traceViewer/assets/xtermModule-BoAIEibi.js +0 -9
- package/lib/vite/traceViewer/codeMirrorModule.C3UTv-Ge.css +0 -1
- package/lib/vite/traceViewer/defaultSettingsView.CO3FR0CX.css +0 -1
- package/lib/vite/traceViewer/embedded.DpNPH6mk.js +0 -2
- package/lib/vite/traceViewer/embedded.mLhjB5IF.css +0 -1
- package/lib/vite/traceViewer/index.CFOW-Ezb.css +0 -1
- package/lib/vite/traceViewer/index.CuE3SYGw.js +0 -2
- package/lib/vite/traceViewer/inspectorTab.CXDulcFG.css +0 -1
- package/lib/vite/traceViewer/recorder.BD-uZJs7.js +0 -2
- package/lib/vite/traceViewer/recorder.tn0RQdqM.css +0 -0
- package/lib/vite/traceViewer/uiMode.BatfzHMG.css +0 -1
- package/lib/vite/traceViewer/uiMode.DHrNgddz.js +0 -5
- package/lib/vite/traceViewer/workbench.B9vIAzH9.css +0 -1
- package/lib/vite/traceViewer/xtermModule.Beg8tuEN.css +0 -32
|
@@ -10,10 +10,15 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const IdentityFunction = s => s;
|
|
13
|
+
const secretPlaceholder = '*********';
|
|
13
14
|
const secretsFilter = () => {
|
|
14
15
|
const disabled = process.env['CHECKLY_INTERNAL_ENABLE_PATCHED_TRACING'] !== 'true';
|
|
15
16
|
if (disabled) return IdentityFunction;
|
|
16
17
|
|
|
18
|
+
// GitLeaks
|
|
19
|
+
const gitLeaksKeys = process.env['CHECKLY_GITLEAKS_RULES'] || '[]';
|
|
20
|
+
const gitLeaksKeyList = JSON.parse(gitLeaksKeys).map(rule => new RegExp(rule, 'gi'));
|
|
21
|
+
|
|
17
22
|
// Cache for regex to avoid recompiling on every call
|
|
18
23
|
let cachedRegex = null;
|
|
19
24
|
let cachedKeys = '';
|
|
@@ -36,11 +41,11 @@ const secretsFilter = () => {
|
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
// First filter out console markers entirely
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return filtered;
|
|
44
|
+
const filtered = s.replace(consoleMarkerRegex, '');
|
|
45
|
+
const gitLeaksFiltered = gitLeaksKeyList.reduce((memo, gitLeaksRule) => {
|
|
46
|
+
return memo.replaceAll(gitLeaksRule, secretPlaceholder);
|
|
47
|
+
}, filtered);
|
|
48
|
+
return cachedRegex ? gitLeaksFiltered.replaceAll(cachedRegex, secretPlaceholder) : filtered;
|
|
44
49
|
};
|
|
45
50
|
};
|
|
46
51
|
exports.secretsFilter = secretsFilter;
|
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.SocksProxyHandler = exports.SocksProxy = void 0;
|
|
7
|
+
exports.parsePattern = parsePattern;
|
|
8
|
+
var _events = _interopRequireDefault(require("events"));
|
|
9
|
+
var _net = _interopRequireDefault(require("net"));
|
|
10
|
+
var _debugLogger = require("../utils/debugLogger");
|
|
11
|
+
var _happyEyeballs = require("../utils/happy-eyeballs");
|
|
12
|
+
var _utils = require("../utils");
|
|
13
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
|
+
/**
|
|
15
|
+
* Copyright (c) Microsoft Corporation.
|
|
16
|
+
*
|
|
17
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
18
|
+
* you may not use this file except in compliance with the License.
|
|
19
|
+
* You may obtain a copy of the License at
|
|
20
|
+
*
|
|
21
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
22
|
+
*
|
|
23
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
24
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
25
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
26
|
+
* See the License for the specific language governing permissions and
|
|
27
|
+
* limitations under the License.
|
|
28
|
+
*/
|
|
29
|
+
// https://tools.ietf.org/html/rfc1928
|
|
30
|
+
var SocksAuth = /*#__PURE__*/function (SocksAuth) {
|
|
31
|
+
SocksAuth[SocksAuth["NO_AUTHENTICATION_REQUIRED"] = 0] = "NO_AUTHENTICATION_REQUIRED";
|
|
32
|
+
SocksAuth[SocksAuth["GSSAPI"] = 1] = "GSSAPI";
|
|
33
|
+
SocksAuth[SocksAuth["USERNAME_PASSWORD"] = 2] = "USERNAME_PASSWORD";
|
|
34
|
+
SocksAuth[SocksAuth["NO_ACCEPTABLE_METHODS"] = 255] = "NO_ACCEPTABLE_METHODS";
|
|
35
|
+
return SocksAuth;
|
|
36
|
+
}(SocksAuth || {});
|
|
37
|
+
var SocksAddressType = /*#__PURE__*/function (SocksAddressType) {
|
|
38
|
+
SocksAddressType[SocksAddressType["IPv4"] = 1] = "IPv4";
|
|
39
|
+
SocksAddressType[SocksAddressType["FqName"] = 3] = "FqName";
|
|
40
|
+
SocksAddressType[SocksAddressType["IPv6"] = 4] = "IPv6";
|
|
41
|
+
return SocksAddressType;
|
|
42
|
+
}(SocksAddressType || {});
|
|
43
|
+
var SocksCommand = /*#__PURE__*/function (SocksCommand) {
|
|
44
|
+
SocksCommand[SocksCommand["CONNECT"] = 1] = "CONNECT";
|
|
45
|
+
SocksCommand[SocksCommand["BIND"] = 2] = "BIND";
|
|
46
|
+
SocksCommand[SocksCommand["UDP_ASSOCIATE"] = 3] = "UDP_ASSOCIATE";
|
|
47
|
+
return SocksCommand;
|
|
48
|
+
}(SocksCommand || {});
|
|
49
|
+
var SocksReply = /*#__PURE__*/function (SocksReply) {
|
|
50
|
+
SocksReply[SocksReply["Succeeded"] = 0] = "Succeeded";
|
|
51
|
+
SocksReply[SocksReply["GeneralServerFailure"] = 1] = "GeneralServerFailure";
|
|
52
|
+
SocksReply[SocksReply["NotAllowedByRuleSet"] = 2] = "NotAllowedByRuleSet";
|
|
53
|
+
SocksReply[SocksReply["NetworkUnreachable"] = 3] = "NetworkUnreachable";
|
|
54
|
+
SocksReply[SocksReply["HostUnreachable"] = 4] = "HostUnreachable";
|
|
55
|
+
SocksReply[SocksReply["ConnectionRefused"] = 5] = "ConnectionRefused";
|
|
56
|
+
SocksReply[SocksReply["TtlExpired"] = 6] = "TtlExpired";
|
|
57
|
+
SocksReply[SocksReply["CommandNotSupported"] = 7] = "CommandNotSupported";
|
|
58
|
+
SocksReply[SocksReply["AddressTypeNotSupported"] = 8] = "AddressTypeNotSupported";
|
|
59
|
+
return SocksReply;
|
|
60
|
+
}(SocksReply || {});
|
|
61
|
+
class SocksConnection {
|
|
62
|
+
constructor(uid, socket, client) {
|
|
63
|
+
this._buffer = Buffer.from([]);
|
|
64
|
+
this._offset = 0;
|
|
65
|
+
this._fence = 0;
|
|
66
|
+
this._fenceCallback = void 0;
|
|
67
|
+
this._socket = void 0;
|
|
68
|
+
this._boundOnData = void 0;
|
|
69
|
+
this._uid = void 0;
|
|
70
|
+
this._client = void 0;
|
|
71
|
+
this._uid = uid;
|
|
72
|
+
this._socket = socket;
|
|
73
|
+
this._client = client;
|
|
74
|
+
this._boundOnData = this._onData.bind(this);
|
|
75
|
+
socket.on('data', this._boundOnData);
|
|
76
|
+
socket.on('close', () => this._onClose());
|
|
77
|
+
socket.on('end', () => this._onClose());
|
|
78
|
+
socket.on('error', () => this._onClose());
|
|
79
|
+
this._run().catch(() => this._socket.end());
|
|
80
|
+
}
|
|
81
|
+
async _run() {
|
|
82
|
+
(0, _utils.assert)(await this._authenticate());
|
|
83
|
+
const {
|
|
84
|
+
command,
|
|
85
|
+
host,
|
|
86
|
+
port
|
|
87
|
+
} = await this._parseRequest();
|
|
88
|
+
if (command !== SocksCommand.CONNECT) {
|
|
89
|
+
this._writeBytes(Buffer.from([0x05, SocksReply.CommandNotSupported, 0x00,
|
|
90
|
+
// RSV
|
|
91
|
+
0x01,
|
|
92
|
+
// IPv4
|
|
93
|
+
0x00, 0x00, 0x00, 0x00,
|
|
94
|
+
// Address
|
|
95
|
+
0x00, 0x00 // Port
|
|
96
|
+
]));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this._socket.off('data', this._boundOnData);
|
|
100
|
+
this._client.onSocketRequested({
|
|
101
|
+
uid: this._uid,
|
|
102
|
+
host,
|
|
103
|
+
port
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async _authenticate() {
|
|
107
|
+
// Request:
|
|
108
|
+
// +----+----------+----------+
|
|
109
|
+
// |VER | NMETHODS | METHODS |
|
|
110
|
+
// +----+----------+----------+
|
|
111
|
+
// | 1 | 1 | 1 to 255 |
|
|
112
|
+
// +----+----------+----------+
|
|
113
|
+
|
|
114
|
+
// Response:
|
|
115
|
+
// +----+--------+
|
|
116
|
+
// |VER | METHOD |
|
|
117
|
+
// +----+--------+
|
|
118
|
+
// | 1 | 1 |
|
|
119
|
+
// +----+--------+
|
|
120
|
+
|
|
121
|
+
const version = await this._readByte();
|
|
122
|
+
(0, _utils.assert)(version === 0x05, 'The VER field must be set to x05 for this version of the protocol, was ' + version);
|
|
123
|
+
const nMethods = await this._readByte();
|
|
124
|
+
(0, _utils.assert)(nMethods, 'No authentication methods specified');
|
|
125
|
+
const methods = await this._readBytes(nMethods);
|
|
126
|
+
for (const method of methods) {
|
|
127
|
+
if (method === 0) {
|
|
128
|
+
this._writeBytes(Buffer.from([version, method]));
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this._writeBytes(Buffer.from([version, SocksAuth.NO_ACCEPTABLE_METHODS]));
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
async _parseRequest() {
|
|
136
|
+
// Request.
|
|
137
|
+
// +----+-----+-------+------+----------+----------+
|
|
138
|
+
// |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
|
139
|
+
// +----+-----+-------+------+----------+----------+
|
|
140
|
+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
|
|
141
|
+
// +----+-----+-------+------+----------+----------+
|
|
142
|
+
|
|
143
|
+
// Response.
|
|
144
|
+
// +----+-----+-------+------+----------+----------+
|
|
145
|
+
// |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
|
|
146
|
+
// +----+-----+-------+------+----------+----------+
|
|
147
|
+
// | 1 | 1 | X'00' | 1 | Variable | 2 |
|
|
148
|
+
// +----+-----+-------+------+----------+----------+
|
|
149
|
+
|
|
150
|
+
const version = await this._readByte();
|
|
151
|
+
(0, _utils.assert)(version === 0x05, 'The VER field must be set to x05 for this version of the protocol, was ' + version);
|
|
152
|
+
const command = await this._readByte();
|
|
153
|
+
await this._readByte(); // skip reserved.
|
|
154
|
+
const addressType = await this._readByte();
|
|
155
|
+
let host = '';
|
|
156
|
+
switch (addressType) {
|
|
157
|
+
case SocksAddressType.IPv4:
|
|
158
|
+
host = (await this._readBytes(4)).join('.');
|
|
159
|
+
break;
|
|
160
|
+
case SocksAddressType.FqName:
|
|
161
|
+
const length = await this._readByte();
|
|
162
|
+
host = (await this._readBytes(length)).toString();
|
|
163
|
+
break;
|
|
164
|
+
case SocksAddressType.IPv6:
|
|
165
|
+
const bytes = await this._readBytes(16);
|
|
166
|
+
const tokens = [];
|
|
167
|
+
for (let i = 0; i < 8; ++i) tokens.push(bytes.readUInt16BE(i * 2).toString(16));
|
|
168
|
+
host = tokens.join(':');
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
const port = (await this._readBytes(2)).readUInt16BE(0);
|
|
172
|
+
this._buffer = Buffer.from([]);
|
|
173
|
+
this._offset = 0;
|
|
174
|
+
this._fence = 0;
|
|
175
|
+
return {
|
|
176
|
+
command,
|
|
177
|
+
host,
|
|
178
|
+
port
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
async _readByte() {
|
|
182
|
+
const buffer = await this._readBytes(1);
|
|
183
|
+
return buffer[0];
|
|
184
|
+
}
|
|
185
|
+
async _readBytes(length) {
|
|
186
|
+
this._fence = this._offset + length;
|
|
187
|
+
if (!this._buffer || this._buffer.length < this._fence) await new Promise(f => this._fenceCallback = f);
|
|
188
|
+
this._offset += length;
|
|
189
|
+
return this._buffer.slice(this._offset - length, this._offset);
|
|
190
|
+
}
|
|
191
|
+
_writeBytes(buffer) {
|
|
192
|
+
if (this._socket.writable) this._socket.write(buffer);
|
|
193
|
+
}
|
|
194
|
+
_onClose() {
|
|
195
|
+
this._client.onSocketClosed({
|
|
196
|
+
uid: this._uid
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
_onData(buffer) {
|
|
200
|
+
this._buffer = Buffer.concat([this._buffer, buffer]);
|
|
201
|
+
if (this._fenceCallback && this._buffer.length >= this._fence) {
|
|
202
|
+
const callback = this._fenceCallback;
|
|
203
|
+
this._fenceCallback = undefined;
|
|
204
|
+
callback();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
socketConnected(host, port) {
|
|
208
|
+
this._writeBytes(Buffer.from([0x05, SocksReply.Succeeded, 0x00,
|
|
209
|
+
// RSV
|
|
210
|
+
...ipToSocksAddress(host),
|
|
211
|
+
// ATYP, Address
|
|
212
|
+
port >> 8, port & 0xFF // Port
|
|
213
|
+
]));
|
|
214
|
+
this._socket.on('data', data => this._client.onSocketData({
|
|
215
|
+
uid: this._uid,
|
|
216
|
+
data
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
socketFailed(errorCode) {
|
|
220
|
+
const buffer = Buffer.from([0x05, 0, 0x00,
|
|
221
|
+
// RSV
|
|
222
|
+
...ipToSocksAddress('0.0.0.0'),
|
|
223
|
+
// ATYP, Address
|
|
224
|
+
0, 0 // Port
|
|
225
|
+
]);
|
|
226
|
+
switch (errorCode) {
|
|
227
|
+
case 'ENOENT':
|
|
228
|
+
case 'ENOTFOUND':
|
|
229
|
+
case 'ETIMEDOUT':
|
|
230
|
+
case 'EHOSTUNREACH':
|
|
231
|
+
buffer[1] = SocksReply.HostUnreachable;
|
|
232
|
+
break;
|
|
233
|
+
case 'ENETUNREACH':
|
|
234
|
+
buffer[1] = SocksReply.NetworkUnreachable;
|
|
235
|
+
break;
|
|
236
|
+
case 'ECONNREFUSED':
|
|
237
|
+
buffer[1] = SocksReply.ConnectionRefused;
|
|
238
|
+
break;
|
|
239
|
+
case 'ERULESET':
|
|
240
|
+
buffer[1] = SocksReply.NotAllowedByRuleSet;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
this._writeBytes(buffer);
|
|
244
|
+
this._socket.end();
|
|
245
|
+
}
|
|
246
|
+
sendData(data) {
|
|
247
|
+
this._socket.write(data);
|
|
248
|
+
}
|
|
249
|
+
end() {
|
|
250
|
+
this._socket.end();
|
|
251
|
+
}
|
|
252
|
+
error(error) {
|
|
253
|
+
this._socket.destroy(new Error(error));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function hexToNumber(hex) {
|
|
257
|
+
// Note: parseInt has a few issues including ignoring trailing characters and allowing leading 0x.
|
|
258
|
+
return [...hex].reduce((value, digit) => {
|
|
259
|
+
const code = digit.charCodeAt(0);
|
|
260
|
+
if (code >= 48 && code <= 57)
|
|
261
|
+
// 0..9
|
|
262
|
+
return value + code;
|
|
263
|
+
if (code >= 97 && code <= 102)
|
|
264
|
+
// a..f
|
|
265
|
+
return value + (code - 97) + 10;
|
|
266
|
+
if (code >= 65 && code <= 70)
|
|
267
|
+
// A..F
|
|
268
|
+
return value + (code - 65) + 10;
|
|
269
|
+
throw new Error('Invalid IPv6 token ' + hex);
|
|
270
|
+
}, 0);
|
|
271
|
+
}
|
|
272
|
+
function ipToSocksAddress(address) {
|
|
273
|
+
if (_net.default.isIPv4(address)) {
|
|
274
|
+
return [0x01,
|
|
275
|
+
// IPv4
|
|
276
|
+
...address.split('.', 4).map(t => +t & 0xFF) // Address
|
|
277
|
+
];
|
|
278
|
+
}
|
|
279
|
+
if (_net.default.isIPv6(address)) {
|
|
280
|
+
const result = [0x04]; // IPv6
|
|
281
|
+
const tokens = address.split(':', 8);
|
|
282
|
+
while (tokens.length < 8) tokens.unshift('');
|
|
283
|
+
for (const token of tokens) {
|
|
284
|
+
const value = hexToNumber(token);
|
|
285
|
+
result.push(value >> 8 & 0xFF, value & 0xFF); // Big-endian
|
|
286
|
+
}
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
throw new Error('Only IPv4 and IPv6 addresses are supported');
|
|
290
|
+
}
|
|
291
|
+
function starMatchToRegex(pattern) {
|
|
292
|
+
const source = pattern.split('*').map(s => {
|
|
293
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
|
|
294
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
295
|
+
}).join('.*');
|
|
296
|
+
return new RegExp('^' + source + '$');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// This follows "Proxy bypass rules" syntax without implicit and negative rules.
|
|
300
|
+
// https://source.chromium.org/chromium/chromium/src/+/main:net/docs/proxy.md;l=331
|
|
301
|
+
function parsePattern(pattern) {
|
|
302
|
+
if (!pattern) return () => false;
|
|
303
|
+
const matchers = pattern.split(',').map(token => {
|
|
304
|
+
const match = token.match(/^(.*?)(?::(\d+))?$/);
|
|
305
|
+
if (!match) throw new Error(`Unsupported token "${token}" in pattern "${pattern}"`);
|
|
306
|
+
const tokenPort = match[2] ? +match[2] : undefined;
|
|
307
|
+
const portMatches = port => tokenPort === undefined || tokenPort === port;
|
|
308
|
+
let tokenHost = match[1];
|
|
309
|
+
if (tokenHost === '<loopback>') {
|
|
310
|
+
return (host, port) => {
|
|
311
|
+
if (!portMatches(port)) return false;
|
|
312
|
+
return host === 'localhost' || host.endsWith('.localhost') || host === '127.0.0.1' || host === '[::1]';
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
if (tokenHost === '*') return (host, port) => portMatches(port);
|
|
316
|
+
if (_net.default.isIPv4(tokenHost) || _net.default.isIPv6(tokenHost)) return (host, port) => host === tokenHost && portMatches(port);
|
|
317
|
+
if (tokenHost[0] === '.') tokenHost = '*' + tokenHost;
|
|
318
|
+
const tokenRegex = starMatchToRegex(tokenHost);
|
|
319
|
+
return (host, port) => {
|
|
320
|
+
if (!portMatches(port)) return false;
|
|
321
|
+
if (_net.default.isIPv4(host) || _net.default.isIPv6(host)) return false;
|
|
322
|
+
return !!host.match(tokenRegex);
|
|
323
|
+
};
|
|
324
|
+
});
|
|
325
|
+
return (host, port) => matchers.some(matcher => matcher(host, port));
|
|
326
|
+
}
|
|
327
|
+
class SocksProxy extends _events.default {
|
|
328
|
+
constructor() {
|
|
329
|
+
super();
|
|
330
|
+
this._server = void 0;
|
|
331
|
+
this._connections = new Map();
|
|
332
|
+
this._sockets = new Set();
|
|
333
|
+
this._closed = false;
|
|
334
|
+
this._port = void 0;
|
|
335
|
+
this._patternMatcher = () => false;
|
|
336
|
+
this._directSockets = new Map();
|
|
337
|
+
this._server = new _net.default.Server(socket => {
|
|
338
|
+
const uid = (0, _utils.createGuid)();
|
|
339
|
+
const connection = new SocksConnection(uid, socket, this);
|
|
340
|
+
this._connections.set(uid, connection);
|
|
341
|
+
});
|
|
342
|
+
this._server.on('connection', socket => {
|
|
343
|
+
if (this._closed) {
|
|
344
|
+
socket.destroy();
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
this._sockets.add(socket);
|
|
348
|
+
socket.once('close', () => this._sockets.delete(socket));
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
setPattern(pattern) {
|
|
352
|
+
try {
|
|
353
|
+
this._patternMatcher = parsePattern(pattern);
|
|
354
|
+
} catch (e) {
|
|
355
|
+
this._patternMatcher = () => false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
async _handleDirect(request) {
|
|
359
|
+
try {
|
|
360
|
+
var _this$_connections$ge4;
|
|
361
|
+
const socket = await (0, _happyEyeballs.createSocket)(request.host, request.port);
|
|
362
|
+
socket.on('data', data => {
|
|
363
|
+
var _this$_connections$ge;
|
|
364
|
+
return (_this$_connections$ge = this._connections.get(request.uid)) === null || _this$_connections$ge === void 0 ? void 0 : _this$_connections$ge.sendData(data);
|
|
365
|
+
});
|
|
366
|
+
socket.on('error', error => {
|
|
367
|
+
var _this$_connections$ge2;
|
|
368
|
+
(_this$_connections$ge2 = this._connections.get(request.uid)) === null || _this$_connections$ge2 === void 0 || _this$_connections$ge2.error(error.message);
|
|
369
|
+
this._directSockets.delete(request.uid);
|
|
370
|
+
});
|
|
371
|
+
socket.on('end', () => {
|
|
372
|
+
var _this$_connections$ge3;
|
|
373
|
+
(_this$_connections$ge3 = this._connections.get(request.uid)) === null || _this$_connections$ge3 === void 0 || _this$_connections$ge3.end();
|
|
374
|
+
this._directSockets.delete(request.uid);
|
|
375
|
+
});
|
|
376
|
+
const localAddress = socket.localAddress;
|
|
377
|
+
const localPort = socket.localPort;
|
|
378
|
+
this._directSockets.set(request.uid, socket);
|
|
379
|
+
(_this$_connections$ge4 = this._connections.get(request.uid)) === null || _this$_connections$ge4 === void 0 || _this$_connections$ge4.socketConnected(localAddress, localPort);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
var _this$_connections$ge5;
|
|
382
|
+
(_this$_connections$ge5 = this._connections.get(request.uid)) === null || _this$_connections$ge5 === void 0 || _this$_connections$ge5.socketFailed(error.code);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
port() {
|
|
386
|
+
return this._port;
|
|
387
|
+
}
|
|
388
|
+
async listen(port, hostname) {
|
|
389
|
+
return new Promise(f => {
|
|
390
|
+
this._server.listen(port, hostname, () => {
|
|
391
|
+
const port = this._server.address().port;
|
|
392
|
+
this._port = port;
|
|
393
|
+
f(port);
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
async close() {
|
|
398
|
+
if (this._closed) return;
|
|
399
|
+
this._closed = true;
|
|
400
|
+
for (const socket of this._sockets) socket.destroy();
|
|
401
|
+
this._sockets.clear();
|
|
402
|
+
await new Promise(f => this._server.close(f));
|
|
403
|
+
}
|
|
404
|
+
onSocketRequested(payload) {
|
|
405
|
+
if (!this._patternMatcher(payload.host, payload.port)) {
|
|
406
|
+
this._handleDirect(payload);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
this.emit(SocksProxy.Events.SocksRequested, payload);
|
|
410
|
+
}
|
|
411
|
+
onSocketData(payload) {
|
|
412
|
+
const direct = this._directSockets.get(payload.uid);
|
|
413
|
+
if (direct) {
|
|
414
|
+
direct.write(payload.data);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
this.emit(SocksProxy.Events.SocksData, payload);
|
|
418
|
+
}
|
|
419
|
+
onSocketClosed(payload) {
|
|
420
|
+
const direct = this._directSockets.get(payload.uid);
|
|
421
|
+
if (direct) {
|
|
422
|
+
direct.destroy();
|
|
423
|
+
this._directSockets.delete(payload.uid);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
this.emit(SocksProxy.Events.SocksClosed, payload);
|
|
427
|
+
}
|
|
428
|
+
socketConnected({
|
|
429
|
+
uid,
|
|
430
|
+
host,
|
|
431
|
+
port
|
|
432
|
+
}) {
|
|
433
|
+
var _this$_connections$ge6;
|
|
434
|
+
(_this$_connections$ge6 = this._connections.get(uid)) === null || _this$_connections$ge6 === void 0 || _this$_connections$ge6.socketConnected(host, port);
|
|
435
|
+
}
|
|
436
|
+
socketFailed({
|
|
437
|
+
uid,
|
|
438
|
+
errorCode
|
|
439
|
+
}) {
|
|
440
|
+
var _this$_connections$ge7;
|
|
441
|
+
(_this$_connections$ge7 = this._connections.get(uid)) === null || _this$_connections$ge7 === void 0 || _this$_connections$ge7.socketFailed(errorCode);
|
|
442
|
+
}
|
|
443
|
+
sendSocketData({
|
|
444
|
+
uid,
|
|
445
|
+
data
|
|
446
|
+
}) {
|
|
447
|
+
var _this$_connections$ge8;
|
|
448
|
+
(_this$_connections$ge8 = this._connections.get(uid)) === null || _this$_connections$ge8 === void 0 || _this$_connections$ge8.sendData(data);
|
|
449
|
+
}
|
|
450
|
+
sendSocketEnd({
|
|
451
|
+
uid
|
|
452
|
+
}) {
|
|
453
|
+
var _this$_connections$ge9;
|
|
454
|
+
(_this$_connections$ge9 = this._connections.get(uid)) === null || _this$_connections$ge9 === void 0 || _this$_connections$ge9.end();
|
|
455
|
+
}
|
|
456
|
+
sendSocketError({
|
|
457
|
+
uid,
|
|
458
|
+
error
|
|
459
|
+
}) {
|
|
460
|
+
var _this$_connections$ge10;
|
|
461
|
+
(_this$_connections$ge10 = this._connections.get(uid)) === null || _this$_connections$ge10 === void 0 || _this$_connections$ge10.error(error);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
exports.SocksProxy = SocksProxy;
|
|
465
|
+
SocksProxy.Events = {
|
|
466
|
+
SocksRequested: 'socksRequested',
|
|
467
|
+
SocksData: 'socksData',
|
|
468
|
+
SocksClosed: 'socksClosed'
|
|
469
|
+
};
|
|
470
|
+
class SocksProxyHandler extends _events.default {
|
|
471
|
+
constructor(pattern, redirectPortForTest) {
|
|
472
|
+
super();
|
|
473
|
+
this._sockets = new Map();
|
|
474
|
+
this._patternMatcher = () => false;
|
|
475
|
+
this._redirectPortForTest = void 0;
|
|
476
|
+
this._patternMatcher = parsePattern(pattern);
|
|
477
|
+
this._redirectPortForTest = redirectPortForTest;
|
|
478
|
+
}
|
|
479
|
+
cleanup() {
|
|
480
|
+
for (const uid of this._sockets.keys()) this.socketClosed({
|
|
481
|
+
uid
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
async socketRequested({
|
|
485
|
+
uid,
|
|
486
|
+
host,
|
|
487
|
+
port
|
|
488
|
+
}) {
|
|
489
|
+
_debugLogger.debugLogger.log('socks', `[${uid}] => request ${host}:${port}`);
|
|
490
|
+
if (!this._patternMatcher(host, port)) {
|
|
491
|
+
const payload = {
|
|
492
|
+
uid,
|
|
493
|
+
errorCode: 'ERULESET'
|
|
494
|
+
};
|
|
495
|
+
_debugLogger.debugLogger.log('socks', `[${uid}] <= pattern error ${payload.errorCode}`);
|
|
496
|
+
this.emit(SocksProxyHandler.Events.SocksFailed, payload);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (host === 'local.playwright') host = 'localhost';
|
|
500
|
+
try {
|
|
501
|
+
if (this._redirectPortForTest) port = this._redirectPortForTest;
|
|
502
|
+
const socket = await (0, _happyEyeballs.createSocket)(host, port);
|
|
503
|
+
socket.on('data', data => {
|
|
504
|
+
const payload = {
|
|
505
|
+
uid,
|
|
506
|
+
data
|
|
507
|
+
};
|
|
508
|
+
this.emit(SocksProxyHandler.Events.SocksData, payload);
|
|
509
|
+
});
|
|
510
|
+
socket.on('error', error => {
|
|
511
|
+
const payload = {
|
|
512
|
+
uid,
|
|
513
|
+
error: error.message
|
|
514
|
+
};
|
|
515
|
+
_debugLogger.debugLogger.log('socks', `[${uid}] <= network socket error ${payload.error}`);
|
|
516
|
+
this.emit(SocksProxyHandler.Events.SocksError, payload);
|
|
517
|
+
this._sockets.delete(uid);
|
|
518
|
+
});
|
|
519
|
+
socket.on('end', () => {
|
|
520
|
+
const payload = {
|
|
521
|
+
uid
|
|
522
|
+
};
|
|
523
|
+
_debugLogger.debugLogger.log('socks', `[${uid}] <= network socket closed`);
|
|
524
|
+
this.emit(SocksProxyHandler.Events.SocksEnd, payload);
|
|
525
|
+
this._sockets.delete(uid);
|
|
526
|
+
});
|
|
527
|
+
const localAddress = socket.localAddress;
|
|
528
|
+
const localPort = socket.localPort;
|
|
529
|
+
this._sockets.set(uid, socket);
|
|
530
|
+
const payload = {
|
|
531
|
+
uid,
|
|
532
|
+
host: localAddress,
|
|
533
|
+
port: localPort
|
|
534
|
+
};
|
|
535
|
+
_debugLogger.debugLogger.log('socks', `[${uid}] <= connected to network ${payload.host}:${payload.port}`);
|
|
536
|
+
this.emit(SocksProxyHandler.Events.SocksConnected, payload);
|
|
537
|
+
} catch (error) {
|
|
538
|
+
const payload = {
|
|
539
|
+
uid,
|
|
540
|
+
errorCode: error.code
|
|
541
|
+
};
|
|
542
|
+
_debugLogger.debugLogger.log('socks', `[${uid}] <= connect error ${payload.errorCode}`);
|
|
543
|
+
this.emit(SocksProxyHandler.Events.SocksFailed, payload);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
sendSocketData({
|
|
547
|
+
uid,
|
|
548
|
+
data
|
|
549
|
+
}) {
|
|
550
|
+
var _this$_sockets$get;
|
|
551
|
+
(_this$_sockets$get = this._sockets.get(uid)) === null || _this$_sockets$get === void 0 || _this$_sockets$get.write(data);
|
|
552
|
+
}
|
|
553
|
+
socketClosed({
|
|
554
|
+
uid
|
|
555
|
+
}) {
|
|
556
|
+
var _this$_sockets$get2;
|
|
557
|
+
_debugLogger.debugLogger.log('socks', `[${uid}] <= browser socket closed`);
|
|
558
|
+
(_this$_sockets$get2 = this._sockets.get(uid)) === null || _this$_sockets$get2 === void 0 || _this$_sockets$get2.destroy();
|
|
559
|
+
this._sockets.delete(uid);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
exports.SocksProxyHandler = SocksProxyHandler;
|
|
563
|
+
SocksProxyHandler.Events = {
|
|
564
|
+
SocksConnected: 'socksConnected',
|
|
565
|
+
SocksData: 'socksData',
|
|
566
|
+
SocksError: 'socksError',
|
|
567
|
+
SocksFailed: 'socksFailed',
|
|
568
|
+
SocksEnd: 'socksEnd'
|
|
569
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.TimeoutSettings = exports.DEFAULT_TIMEOUT = exports.DEFAULT_LAUNCH_TIMEOUT = void 0;
|
|
7
|
+
var _utils = require("../utils");
|
|
8
|
+
/**
|
|
9
|
+
* Copyright 2019 Google Inc. All rights reserved.
|
|
10
|
+
* Modifications copyright (c) Microsoft Corporation.
|
|
11
|
+
*
|
|
12
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
+
* you may not use this file except in compliance with the License.
|
|
14
|
+
* You may obtain a copy of the License at
|
|
15
|
+
*
|
|
16
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
*
|
|
18
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
* See the License for the specific language governing permissions and
|
|
22
|
+
* limitations under the License.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const DEFAULT_TIMEOUT = exports.DEFAULT_TIMEOUT = 30000;
|
|
26
|
+
const DEFAULT_LAUNCH_TIMEOUT = exports.DEFAULT_LAUNCH_TIMEOUT = 3 * 60 * 1000; // 3 minutes
|
|
27
|
+
|
|
28
|
+
class TimeoutSettings {
|
|
29
|
+
constructor(parent) {
|
|
30
|
+
this._parent = void 0;
|
|
31
|
+
this._defaultTimeout = void 0;
|
|
32
|
+
this._defaultNavigationTimeout = void 0;
|
|
33
|
+
this._parent = parent;
|
|
34
|
+
}
|
|
35
|
+
setDefaultTimeout(timeout) {
|
|
36
|
+
this._defaultTimeout = timeout;
|
|
37
|
+
}
|
|
38
|
+
setDefaultNavigationTimeout(timeout) {
|
|
39
|
+
this._defaultNavigationTimeout = timeout;
|
|
40
|
+
}
|
|
41
|
+
defaultNavigationTimeout() {
|
|
42
|
+
return this._defaultNavigationTimeout;
|
|
43
|
+
}
|
|
44
|
+
defaultTimeout() {
|
|
45
|
+
return this._defaultTimeout;
|
|
46
|
+
}
|
|
47
|
+
navigationTimeout(options) {
|
|
48
|
+
if (typeof options.timeout === 'number') return options.timeout;
|
|
49
|
+
if (this._defaultNavigationTimeout !== undefined) return this._defaultNavigationTimeout;
|
|
50
|
+
if ((0, _utils.debugMode)()) return 0;
|
|
51
|
+
if (this._defaultTimeout !== undefined) return this._defaultTimeout;
|
|
52
|
+
if (this._parent) return this._parent.navigationTimeout(options);
|
|
53
|
+
return DEFAULT_TIMEOUT;
|
|
54
|
+
}
|
|
55
|
+
timeout(options) {
|
|
56
|
+
if (typeof options.timeout === 'number') return options.timeout;
|
|
57
|
+
if ((0, _utils.debugMode)()) return 0;
|
|
58
|
+
if (this._defaultTimeout !== undefined) return this._defaultTimeout;
|
|
59
|
+
if (this._parent) return this._parent.timeout(options);
|
|
60
|
+
return DEFAULT_TIMEOUT;
|
|
61
|
+
}
|
|
62
|
+
static timeout(options) {
|
|
63
|
+
if (typeof options.timeout === 'number') return options.timeout;
|
|
64
|
+
if ((0, _utils.debugMode)()) return 0;
|
|
65
|
+
return DEFAULT_TIMEOUT;
|
|
66
|
+
}
|
|
67
|
+
static launchTimeout(options) {
|
|
68
|
+
if (typeof options.timeout === 'number') return options.timeout;
|
|
69
|
+
if ((0, _utils.debugMode)()) return 0;
|
|
70
|
+
return DEFAULT_LAUNCH_TIMEOUT;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.TimeoutSettings = TimeoutSettings;
|