@checkly/playwright-core 1.48.22 → 1.48.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/lib/checkly/secretsFilter.js +29 -6
  2. package/lib/client/clientStackTrace.js +65 -0
  3. package/lib/client/fileUtils.js +31 -0
  4. package/lib/client/platform.js +71 -0
  5. package/lib/client/timeoutSettings.js +65 -0
  6. package/lib/client/webSocket.js +106 -0
  7. package/lib/generated/clockSource.js +2 -1
  8. package/lib/generated/consoleApiSource.js +2 -1
  9. package/lib/generated/injectedScriptSource.js +2 -1
  10. package/lib/generated/pollingRecorderSource.js +2 -1
  11. package/lib/generated/utilityScriptSource.js +2 -1
  12. package/lib/generated/webSocketMockSource.js +2 -1
  13. package/lib/server/callLog.js +79 -0
  14. package/lib/server/harBackend.js +157 -0
  15. package/lib/server/localUtils.js +203 -0
  16. package/lib/server/recorder/chat.js +177 -0
  17. package/lib/server/storageScript.js +160 -0
  18. package/lib/server/timeoutSettings.js +74 -0
  19. package/lib/server/utils/ascii.js +31 -0
  20. package/lib/server/utils/comparators.js +159 -0
  21. package/lib/server/utils/crypto.js +171 -0
  22. package/lib/server/utils/debug.js +38 -0
  23. package/lib/server/utils/debugLogger.js +93 -0
  24. package/lib/server/utils/env.js +53 -0
  25. package/lib/server/utils/eventsHelper.js +38 -0
  26. package/lib/server/utils/expectUtils.js +33 -0
  27. package/lib/server/utils/fileUtils.js +204 -0
  28. package/lib/server/utils/happyEyeballs.js +209 -0
  29. package/lib/server/utils/hostPlatform.js +145 -0
  30. package/lib/server/utils/httpServer.js +233 -0
  31. package/lib/server/utils/image_tools/colorUtils.js +98 -0
  32. package/lib/server/utils/image_tools/compare.js +108 -0
  33. package/lib/server/utils/image_tools/imageChannel.js +70 -0
  34. package/lib/server/utils/image_tools/stats.js +102 -0
  35. package/lib/server/utils/linuxUtils.js +58 -0
  36. package/lib/server/utils/network.js +160 -0
  37. package/lib/server/utils/nodePlatform.js +140 -0
  38. package/lib/server/utils/pipeTransport.js +82 -0
  39. package/lib/server/utils/processLauncher.js +248 -0
  40. package/lib/server/utils/profiler.js +52 -0
  41. package/lib/server/utils/socksProxy.js +570 -0
  42. package/lib/server/utils/spawnAsync.js +45 -0
  43. package/lib/server/utils/task.js +58 -0
  44. package/lib/server/utils/userAgent.js +91 -0
  45. package/lib/server/utils/wsServer.js +128 -0
  46. package/lib/server/utils/zipFile.js +75 -0
  47. package/lib/server/utils/zones.js +54 -0
  48. package/lib/utils/isomorphic/ariaSnapshot.js +392 -0
  49. package/lib/utils/isomorphic/assert.js +25 -0
  50. package/lib/utils/isomorphic/colors.js +65 -0
  51. package/lib/utils/isomorphic/headers.js +52 -0
  52. package/lib/utils/isomorphic/manualPromise.js +107 -0
  53. package/lib/utils/isomorphic/multimap.js +73 -0
  54. package/lib/utils/isomorphic/rtti.js +41 -0
  55. package/lib/utils/isomorphic/semaphore.js +51 -0
  56. package/lib/utils/isomorphic/stackTrace.js +169 -0
  57. package/lib/utils/isomorphic/time.js +25 -0
  58. package/lib/utils/isomorphic/timeoutRunner.js +66 -0
  59. package/lib/utils/isomorphic/types.js +5 -0
  60. package/lib/utils.js +447 -0
  61. package/lib/vite/traceViewer/assets/{codeMirrorModule-pBPtArIT.js → codeMirrorModule-Bh1rfd2w.js} +14 -14
  62. package/lib/vite/traceViewer/assets/codeMirrorModule-DZoSgqUd.js +24 -0
  63. package/lib/vite/traceViewer/assets/codeMirrorModule-xvopPhZ4.js +24 -0
  64. package/lib/vite/traceViewer/assets/{inspectorTab-BuJ3wAX_.js → inspectorTab-7GHnKvSD.js} +2 -2
  65. package/lib/vite/traceViewer/assets/{inspectorTab-Soeeuvzv.js → inspectorTab-BHcfR9dD.js} +3 -3
  66. package/lib/vite/traceViewer/assets/inspectorTab-wfvwpMHs.js +64 -0
  67. package/lib/vite/traceViewer/assets/{workbench-DdmJ9AJV.js → workbench-C6nMfKVy.js} +1 -1
  68. package/lib/vite/traceViewer/assets/{workbench-lypYlf00.js → workbench-DZqNXdoV.js} +1 -1
  69. package/lib/vite/traceViewer/assets/workbench-LKskf2Iy.js +9 -0
  70. package/lib/vite/traceViewer/{embedded.BkvOrz5Z.js → embedded.BXYl5zRv.js} +1 -1
  71. package/lib/vite/traceViewer/{embedded.DInvAijy.js → embedded.CShPz96b.js} +1 -1
  72. package/lib/vite/traceViewer/embedded.Dxe2heQk.js +2 -0
  73. package/lib/vite/traceViewer/embedded.html +3 -3
  74. package/lib/vite/traceViewer/{index.Dha3cgqs.js → index.BZ9CE8t3.js} +1 -1
  75. package/lib/vite/traceViewer/{index._Iolt-uE.js → index.CB297BuW.js} +1 -1
  76. package/lib/vite/traceViewer/index.DZkJsFod.js +2 -0
  77. package/lib/vite/traceViewer/index.html +3 -3
  78. package/lib/vite/traceViewer/{recorder.DNMfnSiu.js → recorder.BVExlUUk.js} +1 -1
  79. package/lib/vite/traceViewer/{recorder.DTSaNaly.js → recorder.C4zxcvd2.js} +1 -1
  80. package/lib/vite/traceViewer/recorder.C88JDknq.js +2 -0
  81. package/lib/vite/traceViewer/recorder.html +2 -2
  82. package/lib/vite/traceViewer/{uiMode.BM7yhjzl.js → uiMode.2tr9k625.js} +1 -1
  83. package/lib/vite/traceViewer/{uiMode.Cr1tvTWS.js → uiMode.DXa41vt9.js} +1 -1
  84. package/lib/vite/traceViewer/uiMode.DjTS7tqC.js +5 -0
  85. package/lib/vite/traceViewer/uiMode.html +3 -3
  86. package/package.json +1 -1
  87. package/lib/vite/traceViewer/assets/codeMirrorModule-tzBrK1V4.js +0 -24
@@ -0,0 +1,570 @@
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 _assert = require("../../utils/isomorphic/assert");
11
+ var _crypto = require("./crypto");
12
+ var _debugLogger = require("./debugLogger");
13
+ var _happyEyeballs = require("./happyEyeballs");
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ /**
16
+ * Copyright (c) Microsoft Corporation.
17
+ *
18
+ * Licensed under the Apache License, Version 2.0 (the "License");
19
+ * you may not use this file except in compliance with the License.
20
+ * You may obtain a copy of the License at
21
+ *
22
+ * http://www.apache.org/licenses/LICENSE-2.0
23
+ *
24
+ * Unless required by applicable law or agreed to in writing, software
25
+ * distributed under the License is distributed on an "AS IS" BASIS,
26
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27
+ * See the License for the specific language governing permissions and
28
+ * limitations under the License.
29
+ */
30
+ // https://tools.ietf.org/html/rfc1928
31
+ var SocksAuth = /*#__PURE__*/function (SocksAuth) {
32
+ SocksAuth[SocksAuth["NO_AUTHENTICATION_REQUIRED"] = 0] = "NO_AUTHENTICATION_REQUIRED";
33
+ SocksAuth[SocksAuth["GSSAPI"] = 1] = "GSSAPI";
34
+ SocksAuth[SocksAuth["USERNAME_PASSWORD"] = 2] = "USERNAME_PASSWORD";
35
+ SocksAuth[SocksAuth["NO_ACCEPTABLE_METHODS"] = 255] = "NO_ACCEPTABLE_METHODS";
36
+ return SocksAuth;
37
+ }(SocksAuth || {});
38
+ var SocksAddressType = /*#__PURE__*/function (SocksAddressType) {
39
+ SocksAddressType[SocksAddressType["IPv4"] = 1] = "IPv4";
40
+ SocksAddressType[SocksAddressType["FqName"] = 3] = "FqName";
41
+ SocksAddressType[SocksAddressType["IPv6"] = 4] = "IPv6";
42
+ return SocksAddressType;
43
+ }(SocksAddressType || {});
44
+ var SocksCommand = /*#__PURE__*/function (SocksCommand) {
45
+ SocksCommand[SocksCommand["CONNECT"] = 1] = "CONNECT";
46
+ SocksCommand[SocksCommand["BIND"] = 2] = "BIND";
47
+ SocksCommand[SocksCommand["UDP_ASSOCIATE"] = 3] = "UDP_ASSOCIATE";
48
+ return SocksCommand;
49
+ }(SocksCommand || {});
50
+ var SocksReply = /*#__PURE__*/function (SocksReply) {
51
+ SocksReply[SocksReply["Succeeded"] = 0] = "Succeeded";
52
+ SocksReply[SocksReply["GeneralServerFailure"] = 1] = "GeneralServerFailure";
53
+ SocksReply[SocksReply["NotAllowedByRuleSet"] = 2] = "NotAllowedByRuleSet";
54
+ SocksReply[SocksReply["NetworkUnreachable"] = 3] = "NetworkUnreachable";
55
+ SocksReply[SocksReply["HostUnreachable"] = 4] = "HostUnreachable";
56
+ SocksReply[SocksReply["ConnectionRefused"] = 5] = "ConnectionRefused";
57
+ SocksReply[SocksReply["TtlExpired"] = 6] = "TtlExpired";
58
+ SocksReply[SocksReply["CommandNotSupported"] = 7] = "CommandNotSupported";
59
+ SocksReply[SocksReply["AddressTypeNotSupported"] = 8] = "AddressTypeNotSupported";
60
+ return SocksReply;
61
+ }(SocksReply || {});
62
+ class SocksConnection {
63
+ constructor(uid, socket, client) {
64
+ this._buffer = Buffer.from([]);
65
+ this._offset = 0;
66
+ this._fence = 0;
67
+ this._fenceCallback = void 0;
68
+ this._socket = void 0;
69
+ this._boundOnData = void 0;
70
+ this._uid = void 0;
71
+ this._client = void 0;
72
+ this._uid = uid;
73
+ this._socket = socket;
74
+ this._client = client;
75
+ this._boundOnData = this._onData.bind(this);
76
+ socket.on('data', this._boundOnData);
77
+ socket.on('close', () => this._onClose());
78
+ socket.on('end', () => this._onClose());
79
+ socket.on('error', () => this._onClose());
80
+ this._run().catch(() => this._socket.end());
81
+ }
82
+ async _run() {
83
+ (0, _assert.assert)(await this._authenticate());
84
+ const {
85
+ command,
86
+ host,
87
+ port
88
+ } = await this._parseRequest();
89
+ if (command !== SocksCommand.CONNECT) {
90
+ this._writeBytes(Buffer.from([0x05, SocksReply.CommandNotSupported, 0x00,
91
+ // RSV
92
+ 0x01,
93
+ // IPv4
94
+ 0x00, 0x00, 0x00, 0x00,
95
+ // Address
96
+ 0x00, 0x00 // Port
97
+ ]));
98
+ return;
99
+ }
100
+ this._socket.off('data', this._boundOnData);
101
+ this._client.onSocketRequested({
102
+ uid: this._uid,
103
+ host,
104
+ port
105
+ });
106
+ }
107
+ async _authenticate() {
108
+ // Request:
109
+ // +----+----------+----------+
110
+ // |VER | NMETHODS | METHODS |
111
+ // +----+----------+----------+
112
+ // | 1 | 1 | 1 to 255 |
113
+ // +----+----------+----------+
114
+
115
+ // Response:
116
+ // +----+--------+
117
+ // |VER | METHOD |
118
+ // +----+--------+
119
+ // | 1 | 1 |
120
+ // +----+--------+
121
+
122
+ const version = await this._readByte();
123
+ (0, _assert.assert)(version === 0x05, 'The VER field must be set to x05 for this version of the protocol, was ' + version);
124
+ const nMethods = await this._readByte();
125
+ (0, _assert.assert)(nMethods, 'No authentication methods specified');
126
+ const methods = await this._readBytes(nMethods);
127
+ for (const method of methods) {
128
+ if (method === 0) {
129
+ this._writeBytes(Buffer.from([version, method]));
130
+ return true;
131
+ }
132
+ }
133
+ this._writeBytes(Buffer.from([version, SocksAuth.NO_ACCEPTABLE_METHODS]));
134
+ return false;
135
+ }
136
+ async _parseRequest() {
137
+ // Request.
138
+ // +----+-----+-------+------+----------+----------+
139
+ // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
140
+ // +----+-----+-------+------+----------+----------+
141
+ // | 1 | 1 | X'00' | 1 | Variable | 2 |
142
+ // +----+-----+-------+------+----------+----------+
143
+
144
+ // Response.
145
+ // +----+-----+-------+------+----------+----------+
146
+ // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
147
+ // +----+-----+-------+------+----------+----------+
148
+ // | 1 | 1 | X'00' | 1 | Variable | 2 |
149
+ // +----+-----+-------+------+----------+----------+
150
+
151
+ const version = await this._readByte();
152
+ (0, _assert.assert)(version === 0x05, 'The VER field must be set to x05 for this version of the protocol, was ' + version);
153
+ const command = await this._readByte();
154
+ await this._readByte(); // skip reserved.
155
+ const addressType = await this._readByte();
156
+ let host = '';
157
+ switch (addressType) {
158
+ case SocksAddressType.IPv4:
159
+ host = (await this._readBytes(4)).join('.');
160
+ break;
161
+ case SocksAddressType.FqName:
162
+ const length = await this._readByte();
163
+ host = (await this._readBytes(length)).toString();
164
+ break;
165
+ case SocksAddressType.IPv6:
166
+ const bytes = await this._readBytes(16);
167
+ const tokens = [];
168
+ for (let i = 0; i < 8; ++i) tokens.push(bytes.readUInt16BE(i * 2).toString(16));
169
+ host = tokens.join(':');
170
+ break;
171
+ }
172
+ const port = (await this._readBytes(2)).readUInt16BE(0);
173
+ this._buffer = Buffer.from([]);
174
+ this._offset = 0;
175
+ this._fence = 0;
176
+ return {
177
+ command,
178
+ host,
179
+ port
180
+ };
181
+ }
182
+ async _readByte() {
183
+ const buffer = await this._readBytes(1);
184
+ return buffer[0];
185
+ }
186
+ async _readBytes(length) {
187
+ this._fence = this._offset + length;
188
+ if (!this._buffer || this._buffer.length < this._fence) await new Promise(f => this._fenceCallback = f);
189
+ this._offset += length;
190
+ return this._buffer.slice(this._offset - length, this._offset);
191
+ }
192
+ _writeBytes(buffer) {
193
+ if (this._socket.writable) this._socket.write(buffer);
194
+ }
195
+ _onClose() {
196
+ this._client.onSocketClosed({
197
+ uid: this._uid
198
+ });
199
+ }
200
+ _onData(buffer) {
201
+ this._buffer = Buffer.concat([this._buffer, buffer]);
202
+ if (this._fenceCallback && this._buffer.length >= this._fence) {
203
+ const callback = this._fenceCallback;
204
+ this._fenceCallback = undefined;
205
+ callback();
206
+ }
207
+ }
208
+ socketConnected(host, port) {
209
+ this._writeBytes(Buffer.from([0x05, SocksReply.Succeeded, 0x00,
210
+ // RSV
211
+ ...ipToSocksAddress(host),
212
+ // ATYP, Address
213
+ port >> 8, port & 0xFF // Port
214
+ ]));
215
+ this._socket.on('data', data => this._client.onSocketData({
216
+ uid: this._uid,
217
+ data
218
+ }));
219
+ }
220
+ socketFailed(errorCode) {
221
+ const buffer = Buffer.from([0x05, 0, 0x00,
222
+ // RSV
223
+ ...ipToSocksAddress('0.0.0.0'),
224
+ // ATYP, Address
225
+ 0, 0 // Port
226
+ ]);
227
+ switch (errorCode) {
228
+ case 'ENOENT':
229
+ case 'ENOTFOUND':
230
+ case 'ETIMEDOUT':
231
+ case 'EHOSTUNREACH':
232
+ buffer[1] = SocksReply.HostUnreachable;
233
+ break;
234
+ case 'ENETUNREACH':
235
+ buffer[1] = SocksReply.NetworkUnreachable;
236
+ break;
237
+ case 'ECONNREFUSED':
238
+ buffer[1] = SocksReply.ConnectionRefused;
239
+ break;
240
+ case 'ERULESET':
241
+ buffer[1] = SocksReply.NotAllowedByRuleSet;
242
+ break;
243
+ }
244
+ this._writeBytes(buffer);
245
+ this._socket.end();
246
+ }
247
+ sendData(data) {
248
+ this._socket.write(data);
249
+ }
250
+ end() {
251
+ this._socket.end();
252
+ }
253
+ error(error) {
254
+ this._socket.destroy(new Error(error));
255
+ }
256
+ }
257
+ function hexToNumber(hex) {
258
+ // Note: parseInt has a few issues including ignoring trailing characters and allowing leading 0x.
259
+ return [...hex].reduce((value, digit) => {
260
+ const code = digit.charCodeAt(0);
261
+ if (code >= 48 && code <= 57)
262
+ // 0..9
263
+ return value + code;
264
+ if (code >= 97 && code <= 102)
265
+ // a..f
266
+ return value + (code - 97) + 10;
267
+ if (code >= 65 && code <= 70)
268
+ // A..F
269
+ return value + (code - 65) + 10;
270
+ throw new Error('Invalid IPv6 token ' + hex);
271
+ }, 0);
272
+ }
273
+ function ipToSocksAddress(address) {
274
+ if (_net.default.isIPv4(address)) {
275
+ return [0x01,
276
+ // IPv4
277
+ ...address.split('.', 4).map(t => +t & 0xFF) // Address
278
+ ];
279
+ }
280
+ if (_net.default.isIPv6(address)) {
281
+ const result = [0x04]; // IPv6
282
+ const tokens = address.split(':', 8);
283
+ while (tokens.length < 8) tokens.unshift('');
284
+ for (const token of tokens) {
285
+ const value = hexToNumber(token);
286
+ result.push(value >> 8 & 0xFF, value & 0xFF); // Big-endian
287
+ }
288
+ return result;
289
+ }
290
+ throw new Error('Only IPv4 and IPv6 addresses are supported');
291
+ }
292
+ function starMatchToRegex(pattern) {
293
+ const source = pattern.split('*').map(s => {
294
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
295
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
296
+ }).join('.*');
297
+ return new RegExp('^' + source + '$');
298
+ }
299
+
300
+ // This follows "Proxy bypass rules" syntax without implicit and negative rules.
301
+ // https://source.chromium.org/chromium/chromium/src/+/main:net/docs/proxy.md;l=331
302
+ function parsePattern(pattern) {
303
+ if (!pattern) return () => false;
304
+ const matchers = pattern.split(',').map(token => {
305
+ const match = token.match(/^(.*?)(?::(\d+))?$/);
306
+ if (!match) throw new Error(`Unsupported token "${token}" in pattern "${pattern}"`);
307
+ const tokenPort = match[2] ? +match[2] : undefined;
308
+ const portMatches = port => tokenPort === undefined || tokenPort === port;
309
+ let tokenHost = match[1];
310
+ if (tokenHost === '<loopback>') {
311
+ return (host, port) => {
312
+ if (!portMatches(port)) return false;
313
+ return host === 'localhost' || host.endsWith('.localhost') || host === '127.0.0.1' || host === '[::1]';
314
+ };
315
+ }
316
+ if (tokenHost === '*') return (host, port) => portMatches(port);
317
+ if (_net.default.isIPv4(tokenHost) || _net.default.isIPv6(tokenHost)) return (host, port) => host === tokenHost && portMatches(port);
318
+ if (tokenHost[0] === '.') tokenHost = '*' + tokenHost;
319
+ const tokenRegex = starMatchToRegex(tokenHost);
320
+ return (host, port) => {
321
+ if (!portMatches(port)) return false;
322
+ if (_net.default.isIPv4(host) || _net.default.isIPv6(host)) return false;
323
+ return !!host.match(tokenRegex);
324
+ };
325
+ });
326
+ return (host, port) => matchers.some(matcher => matcher(host, port));
327
+ }
328
+ class SocksProxy extends _events.default {
329
+ constructor() {
330
+ super();
331
+ this._server = void 0;
332
+ this._connections = new Map();
333
+ this._sockets = new Set();
334
+ this._closed = false;
335
+ this._port = void 0;
336
+ this._patternMatcher = () => false;
337
+ this._directSockets = new Map();
338
+ this._server = new _net.default.Server(socket => {
339
+ const uid = (0, _crypto.createGuid)();
340
+ const connection = new SocksConnection(uid, socket, this);
341
+ this._connections.set(uid, connection);
342
+ });
343
+ this._server.on('connection', socket => {
344
+ if (this._closed) {
345
+ socket.destroy();
346
+ return;
347
+ }
348
+ this._sockets.add(socket);
349
+ socket.once('close', () => this._sockets.delete(socket));
350
+ });
351
+ }
352
+ setPattern(pattern) {
353
+ try {
354
+ this._patternMatcher = parsePattern(pattern);
355
+ } catch (e) {
356
+ this._patternMatcher = () => false;
357
+ }
358
+ }
359
+ async _handleDirect(request) {
360
+ try {
361
+ var _this$_connections$ge4;
362
+ const socket = await (0, _happyEyeballs.createSocket)(request.host, request.port);
363
+ socket.on('data', data => {
364
+ var _this$_connections$ge;
365
+ return (_this$_connections$ge = this._connections.get(request.uid)) === null || _this$_connections$ge === void 0 ? void 0 : _this$_connections$ge.sendData(data);
366
+ });
367
+ socket.on('error', error => {
368
+ var _this$_connections$ge2;
369
+ (_this$_connections$ge2 = this._connections.get(request.uid)) === null || _this$_connections$ge2 === void 0 || _this$_connections$ge2.error(error.message);
370
+ this._directSockets.delete(request.uid);
371
+ });
372
+ socket.on('end', () => {
373
+ var _this$_connections$ge3;
374
+ (_this$_connections$ge3 = this._connections.get(request.uid)) === null || _this$_connections$ge3 === void 0 || _this$_connections$ge3.end();
375
+ this._directSockets.delete(request.uid);
376
+ });
377
+ const localAddress = socket.localAddress;
378
+ const localPort = socket.localPort;
379
+ this._directSockets.set(request.uid, socket);
380
+ (_this$_connections$ge4 = this._connections.get(request.uid)) === null || _this$_connections$ge4 === void 0 || _this$_connections$ge4.socketConnected(localAddress, localPort);
381
+ } catch (error) {
382
+ var _this$_connections$ge5;
383
+ (_this$_connections$ge5 = this._connections.get(request.uid)) === null || _this$_connections$ge5 === void 0 || _this$_connections$ge5.socketFailed(error.code);
384
+ }
385
+ }
386
+ port() {
387
+ return this._port;
388
+ }
389
+ async listen(port, hostname) {
390
+ return new Promise(f => {
391
+ this._server.listen(port, hostname, () => {
392
+ const port = this._server.address().port;
393
+ this._port = port;
394
+ f(port);
395
+ });
396
+ });
397
+ }
398
+ async close() {
399
+ if (this._closed) return;
400
+ this._closed = true;
401
+ for (const socket of this._sockets) socket.destroy();
402
+ this._sockets.clear();
403
+ await new Promise(f => this._server.close(f));
404
+ }
405
+ onSocketRequested(payload) {
406
+ if (!this._patternMatcher(payload.host, payload.port)) {
407
+ this._handleDirect(payload);
408
+ return;
409
+ }
410
+ this.emit(SocksProxy.Events.SocksRequested, payload);
411
+ }
412
+ onSocketData(payload) {
413
+ const direct = this._directSockets.get(payload.uid);
414
+ if (direct) {
415
+ direct.write(payload.data);
416
+ return;
417
+ }
418
+ this.emit(SocksProxy.Events.SocksData, payload);
419
+ }
420
+ onSocketClosed(payload) {
421
+ const direct = this._directSockets.get(payload.uid);
422
+ if (direct) {
423
+ direct.destroy();
424
+ this._directSockets.delete(payload.uid);
425
+ return;
426
+ }
427
+ this.emit(SocksProxy.Events.SocksClosed, payload);
428
+ }
429
+ socketConnected({
430
+ uid,
431
+ host,
432
+ port
433
+ }) {
434
+ var _this$_connections$ge6;
435
+ (_this$_connections$ge6 = this._connections.get(uid)) === null || _this$_connections$ge6 === void 0 || _this$_connections$ge6.socketConnected(host, port);
436
+ }
437
+ socketFailed({
438
+ uid,
439
+ errorCode
440
+ }) {
441
+ var _this$_connections$ge7;
442
+ (_this$_connections$ge7 = this._connections.get(uid)) === null || _this$_connections$ge7 === void 0 || _this$_connections$ge7.socketFailed(errorCode);
443
+ }
444
+ sendSocketData({
445
+ uid,
446
+ data
447
+ }) {
448
+ var _this$_connections$ge8;
449
+ (_this$_connections$ge8 = this._connections.get(uid)) === null || _this$_connections$ge8 === void 0 || _this$_connections$ge8.sendData(data);
450
+ }
451
+ sendSocketEnd({
452
+ uid
453
+ }) {
454
+ var _this$_connections$ge9;
455
+ (_this$_connections$ge9 = this._connections.get(uid)) === null || _this$_connections$ge9 === void 0 || _this$_connections$ge9.end();
456
+ }
457
+ sendSocketError({
458
+ uid,
459
+ error
460
+ }) {
461
+ var _this$_connections$ge10;
462
+ (_this$_connections$ge10 = this._connections.get(uid)) === null || _this$_connections$ge10 === void 0 || _this$_connections$ge10.error(error);
463
+ }
464
+ }
465
+ exports.SocksProxy = SocksProxy;
466
+ SocksProxy.Events = {
467
+ SocksRequested: 'socksRequested',
468
+ SocksData: 'socksData',
469
+ SocksClosed: 'socksClosed'
470
+ };
471
+ class SocksProxyHandler extends _events.default {
472
+ constructor(pattern, redirectPortForTest) {
473
+ super();
474
+ this._sockets = new Map();
475
+ this._patternMatcher = () => false;
476
+ this._redirectPortForTest = void 0;
477
+ this._patternMatcher = parsePattern(pattern);
478
+ this._redirectPortForTest = redirectPortForTest;
479
+ }
480
+ cleanup() {
481
+ for (const uid of this._sockets.keys()) this.socketClosed({
482
+ uid
483
+ });
484
+ }
485
+ async socketRequested({
486
+ uid,
487
+ host,
488
+ port
489
+ }) {
490
+ _debugLogger.debugLogger.log('socks', `[${uid}] => request ${host}:${port}`);
491
+ if (!this._patternMatcher(host, port)) {
492
+ const payload = {
493
+ uid,
494
+ errorCode: 'ERULESET'
495
+ };
496
+ _debugLogger.debugLogger.log('socks', `[${uid}] <= pattern error ${payload.errorCode}`);
497
+ this.emit(SocksProxyHandler.Events.SocksFailed, payload);
498
+ return;
499
+ }
500
+ if (host === 'local.playwright') host = 'localhost';
501
+ try {
502
+ if (this._redirectPortForTest) port = this._redirectPortForTest;
503
+ const socket = await (0, _happyEyeballs.createSocket)(host, port);
504
+ socket.on('data', data => {
505
+ const payload = {
506
+ uid,
507
+ data
508
+ };
509
+ this.emit(SocksProxyHandler.Events.SocksData, payload);
510
+ });
511
+ socket.on('error', error => {
512
+ const payload = {
513
+ uid,
514
+ error: error.message
515
+ };
516
+ _debugLogger.debugLogger.log('socks', `[${uid}] <= network socket error ${payload.error}`);
517
+ this.emit(SocksProxyHandler.Events.SocksError, payload);
518
+ this._sockets.delete(uid);
519
+ });
520
+ socket.on('end', () => {
521
+ const payload = {
522
+ uid
523
+ };
524
+ _debugLogger.debugLogger.log('socks', `[${uid}] <= network socket closed`);
525
+ this.emit(SocksProxyHandler.Events.SocksEnd, payload);
526
+ this._sockets.delete(uid);
527
+ });
528
+ const localAddress = socket.localAddress;
529
+ const localPort = socket.localPort;
530
+ this._sockets.set(uid, socket);
531
+ const payload = {
532
+ uid,
533
+ host: localAddress,
534
+ port: localPort
535
+ };
536
+ _debugLogger.debugLogger.log('socks', `[${uid}] <= connected to network ${payload.host}:${payload.port}`);
537
+ this.emit(SocksProxyHandler.Events.SocksConnected, payload);
538
+ } catch (error) {
539
+ const payload = {
540
+ uid,
541
+ errorCode: error.code
542
+ };
543
+ _debugLogger.debugLogger.log('socks', `[${uid}] <= connect error ${payload.errorCode}`);
544
+ this.emit(SocksProxyHandler.Events.SocksFailed, payload);
545
+ }
546
+ }
547
+ sendSocketData({
548
+ uid,
549
+ data
550
+ }) {
551
+ var _this$_sockets$get;
552
+ (_this$_sockets$get = this._sockets.get(uid)) === null || _this$_sockets$get === void 0 || _this$_sockets$get.write(data);
553
+ }
554
+ socketClosed({
555
+ uid
556
+ }) {
557
+ var _this$_sockets$get2;
558
+ _debugLogger.debugLogger.log('socks', `[${uid}] <= browser socket closed`);
559
+ (_this$_sockets$get2 = this._sockets.get(uid)) === null || _this$_sockets$get2 === void 0 || _this$_sockets$get2.destroy();
560
+ this._sockets.delete(uid);
561
+ }
562
+ }
563
+ exports.SocksProxyHandler = SocksProxyHandler;
564
+ SocksProxyHandler.Events = {
565
+ SocksConnected: 'socksConnected',
566
+ SocksData: 'socksData',
567
+ SocksError: 'socksError',
568
+ SocksFailed: 'socksFailed',
569
+ SocksEnd: 'socksEnd'
570
+ };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.spawnAsync = spawnAsync;
7
+ var _child_process = require("child_process");
8
+ /**
9
+ * Copyright (c) Microsoft Corporation.
10
+ *
11
+ * Licensed under the Apache License, Version 2.0 (the "License");
12
+ * you may not use this file except in compliance with the License.
13
+ * You may obtain a copy of the License at
14
+ *
15
+ * http://www.apache.org/licenses/LICENSE-2.0
16
+ *
17
+ * Unless required by applicable law or agreed to in writing, software
18
+ * distributed under the License is distributed on an "AS IS" BASIS,
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ * See the License for the specific language governing permissions and
21
+ * limitations under the License.
22
+ */
23
+
24
+ function spawnAsync(cmd, args, options = {}) {
25
+ const process = (0, _child_process.spawn)(cmd, args, Object.assign({
26
+ windowsHide: true
27
+ }, options));
28
+ return new Promise(resolve => {
29
+ let stdout = '';
30
+ let stderr = '';
31
+ if (process.stdout) process.stdout.on('data', data => stdout += data.toString());
32
+ if (process.stderr) process.stderr.on('data', data => stderr += data.toString());
33
+ process.on('close', code => resolve({
34
+ stdout,
35
+ stderr,
36
+ code
37
+ }));
38
+ process.on('error', error => resolve({
39
+ stdout,
40
+ stderr,
41
+ code: 0,
42
+ error
43
+ }));
44
+ });
45
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.makeWaitForNextTask = makeWaitForNextTask;
7
+ /**
8
+ * Copyright (c) Microsoft Corporation.
9
+ *
10
+ * Licensed under the Apache License, Version 2.0 (the "License");
11
+ * you may not use this file except in compliance with the License.
12
+ * You may obtain a copy of the License at
13
+ *
14
+ * http://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ */
22
+
23
+ // See https://joel.tools/microtasks/
24
+ function makeWaitForNextTask() {
25
+ // As of Mar 2021, Electron v12 doesn't create new task with `setImmediate` despite
26
+ // using Node 14 internally, so we fallback to `setTimeout(0)` instead.
27
+ // @see https://github.com/electron/electron/issues/28261
28
+ if (process.versions.electron) return callback => setTimeout(callback, 0);
29
+ if (parseInt(process.versions.node, 10) >= 11) return setImmediate;
30
+
31
+ // Unlike Node 11, Node 10 and less have a bug with Task and MicroTask execution order:
32
+ // - https://github.com/nodejs/node/issues/22257
33
+ //
34
+ // So we can't simply run setImmediate to dispatch code in a following task.
35
+ // However, we can run setImmediate from-inside setImmediate to make sure we're getting
36
+ // in the following task.
37
+
38
+ let spinning = false;
39
+ const callbacks = [];
40
+ const loop = () => {
41
+ const callback = callbacks.shift();
42
+ if (!callback) {
43
+ spinning = false;
44
+ return;
45
+ }
46
+ setImmediate(loop);
47
+ // Make sure to call callback() as the last thing since it's
48
+ // untrusted code that might throw.
49
+ callback();
50
+ };
51
+ return callback => {
52
+ callbacks.push(callback);
53
+ if (!spinning) {
54
+ spinning = true;
55
+ setImmediate(loop);
56
+ }
57
+ };
58
+ }