advanced-tls-client 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +27 -3
- package/dist/index.js +30 -201
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
1
2
|
import { Readable, PassThrough } from 'stream';
|
|
2
3
|
interface TLSFingerprint {
|
|
3
4
|
cipherSuites: number[];
|
|
@@ -119,13 +120,36 @@ interface RequestOptions {
|
|
|
119
120
|
content_type?: string;
|
|
120
121
|
uri_modifier?: Function;
|
|
121
122
|
}
|
|
123
|
+
interface Response extends EventEmitter {
|
|
124
|
+
statusCode: number;
|
|
125
|
+
headers: Record<string, string | string[]>;
|
|
126
|
+
body: Buffer | Readable | any;
|
|
127
|
+
text?: string;
|
|
128
|
+
json?: any;
|
|
129
|
+
timing: {
|
|
130
|
+
socket: number;
|
|
131
|
+
lookup: number;
|
|
132
|
+
connect: number;
|
|
133
|
+
secureConnect: number;
|
|
134
|
+
response: number;
|
|
135
|
+
end: number;
|
|
136
|
+
total: number;
|
|
137
|
+
};
|
|
138
|
+
fingerprints: {
|
|
139
|
+
ja3: string;
|
|
140
|
+
ja3Hash: string;
|
|
141
|
+
akamai: string;
|
|
142
|
+
};
|
|
143
|
+
bytes?: number;
|
|
144
|
+
raw?: Buffer;
|
|
145
|
+
cookies?: Record<string, string>;
|
|
146
|
+
parser?: string;
|
|
147
|
+
}
|
|
122
148
|
declare class ProfileRegistry {
|
|
123
149
|
private static getGrease;
|
|
124
150
|
static chromeMobile143Android(): ChromeProfile;
|
|
125
151
|
static chrome133PSK(): ChromeProfile;
|
|
126
152
|
static chrome133(): ChromeProfile;
|
|
127
|
-
static firefox117(): ChromeProfile;
|
|
128
|
-
static safariIOS18(): ChromeProfile;
|
|
129
153
|
static get(name: string): ChromeProfile;
|
|
130
154
|
static get latest(): ChromeProfile;
|
|
131
155
|
static get latestMobile(): ChromeProfile;
|
|
@@ -140,7 +164,7 @@ declare class AdvancedTLSClient {
|
|
|
140
164
|
private defaults;
|
|
141
165
|
constructor(profileName?: string);
|
|
142
166
|
private setup;
|
|
143
|
-
request(uri: string, data?: any, options?: RequestOptions, callback?:
|
|
167
|
+
request(uri: string, data?: any, options?: RequestOptions, callback?: (err: any, res?: Response) => void): Promise<FullResponse | PassThrough>;
|
|
144
168
|
private generateJA3;
|
|
145
169
|
private buildMultipart;
|
|
146
170
|
private generateMultipart;
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.ProfileRegistry = exports.AdvancedTLSClient = void 0;
|
|
37
37
|
const tls = __importStar(require("tls"));
|
|
38
38
|
const net = __importStar(require("net"));
|
|
39
|
+
const https = __importStar(require("https"));
|
|
39
40
|
const http2 = __importStar(require("http2"));
|
|
40
41
|
const crypto = __importStar(require("crypto"));
|
|
41
42
|
const events_1 = require("events");
|
|
@@ -413,202 +414,16 @@ class ProfileRegistry {
|
|
|
413
414
|
secFetchDest: 'document'
|
|
414
415
|
};
|
|
415
416
|
}
|
|
416
|
-
static firefox117() {
|
|
417
|
-
return {
|
|
418
|
-
name: 'firefox_117',
|
|
419
|
-
version: '117.0',
|
|
420
|
-
tls: {
|
|
421
|
-
cipherSuites: [
|
|
422
|
-
4865,
|
|
423
|
-
4867,
|
|
424
|
-
4866,
|
|
425
|
-
49195,
|
|
426
|
-
49199,
|
|
427
|
-
52393,
|
|
428
|
-
52392,
|
|
429
|
-
49196,
|
|
430
|
-
49200,
|
|
431
|
-
159,
|
|
432
|
-
158,
|
|
433
|
-
49161,
|
|
434
|
-
49162,
|
|
435
|
-
156,
|
|
436
|
-
157,
|
|
437
|
-
47,
|
|
438
|
-
53
|
|
439
|
-
],
|
|
440
|
-
extensions: [0, 23, 65281, 10, 11, 35, 16, 5, 34, 51, 43, 13, 45, 28, 21],
|
|
441
|
-
supportedGroups: [
|
|
442
|
-
29,
|
|
443
|
-
23,
|
|
444
|
-
24,
|
|
445
|
-
25,
|
|
446
|
-
256,
|
|
447
|
-
257
|
|
448
|
-
],
|
|
449
|
-
signatureAlgorithms: [
|
|
450
|
-
1027,
|
|
451
|
-
1283,
|
|
452
|
-
1539,
|
|
453
|
-
2052,
|
|
454
|
-
2053,
|
|
455
|
-
2054,
|
|
456
|
-
1025,
|
|
457
|
-
1281,
|
|
458
|
-
1537,
|
|
459
|
-
513,
|
|
460
|
-
515
|
|
461
|
-
],
|
|
462
|
-
supportedVersions: [
|
|
463
|
-
772,
|
|
464
|
-
771
|
|
465
|
-
],
|
|
466
|
-
ecPointFormats: [0],
|
|
467
|
-
alpnProtocols: ['h2', 'http/1.1'],
|
|
468
|
-
pskKeyExchangeModes: [1],
|
|
469
|
-
compressionMethods: [0],
|
|
470
|
-
grease: false
|
|
471
|
-
},
|
|
472
|
-
http2: {
|
|
473
|
-
windowUpdate: 12517377,
|
|
474
|
-
headerTableSize: 65536,
|
|
475
|
-
enablePush: 0,
|
|
476
|
-
initialWindowSize: 131072,
|
|
477
|
-
maxFrameSize: 16384,
|
|
478
|
-
settingsOrder: [1, 4, 5],
|
|
479
|
-
connectionPreface: Buffer.from('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'),
|
|
480
|
-
priorityFrames: [
|
|
481
|
-
{ streamId: 3, weight: 200, dependency: 0, exclusive: false },
|
|
482
|
-
{ streamId: 5, weight: 100, dependency: 0, exclusive: false },
|
|
483
|
-
{ streamId: 7, weight: 0, dependency: 0, exclusive: false },
|
|
484
|
-
{ streamId: 9, weight: 0, dependency: 7, exclusive: false },
|
|
485
|
-
{ streamId: 11, weight: 0, dependency: 3, exclusive: false },
|
|
486
|
-
{ streamId: 13, weight: 240, dependency: 0, exclusive: false }
|
|
487
|
-
],
|
|
488
|
-
pseudoHeaderOrder: [':method', ':path', ':authority', ':scheme'],
|
|
489
|
-
headerPriority: { streamDep: 13, exclusive: false, weight: 41 },
|
|
490
|
-
headerOrder: []
|
|
491
|
-
},
|
|
492
|
-
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:117.0) Gecko/20100101 Firefox/117.0',
|
|
493
|
-
secChUa: '',
|
|
494
|
-
secChUaPlatform: '',
|
|
495
|
-
secChUaMobile: '',
|
|
496
|
-
secFetchSite: 'none',
|
|
497
|
-
secFetchMode: 'navigate',
|
|
498
|
-
secFetchDest: 'document'
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
static safariIOS18() {
|
|
502
|
-
const grease1 = this.getGrease();
|
|
503
|
-
const grease2 = this.getGrease();
|
|
504
|
-
return {
|
|
505
|
-
name: 'safari_ios_18_0',
|
|
506
|
-
version: '18.0',
|
|
507
|
-
tls: {
|
|
508
|
-
cipherSuites: [
|
|
509
|
-
grease1,
|
|
510
|
-
4865,
|
|
511
|
-
4866,
|
|
512
|
-
4867,
|
|
513
|
-
49196,
|
|
514
|
-
49195,
|
|
515
|
-
52393,
|
|
516
|
-
49200,
|
|
517
|
-
49199,
|
|
518
|
-
52392,
|
|
519
|
-
159,
|
|
520
|
-
158,
|
|
521
|
-
49162,
|
|
522
|
-
49161,
|
|
523
|
-
157,
|
|
524
|
-
156,
|
|
525
|
-
53,
|
|
526
|
-
47,
|
|
527
|
-
49188,
|
|
528
|
-
49187,
|
|
529
|
-
60
|
|
530
|
-
],
|
|
531
|
-
extensions: [
|
|
532
|
-
grease2,
|
|
533
|
-
0,
|
|
534
|
-
23,
|
|
535
|
-
65281,
|
|
536
|
-
10,
|
|
537
|
-
11,
|
|
538
|
-
16,
|
|
539
|
-
5,
|
|
540
|
-
13,
|
|
541
|
-
18,
|
|
542
|
-
51,
|
|
543
|
-
45,
|
|
544
|
-
43,
|
|
545
|
-
21
|
|
546
|
-
],
|
|
547
|
-
supportedGroups: [
|
|
548
|
-
29,
|
|
549
|
-
23,
|
|
550
|
-
24,
|
|
551
|
-
25
|
|
552
|
-
],
|
|
553
|
-
signatureAlgorithms: [
|
|
554
|
-
1027,
|
|
555
|
-
2052,
|
|
556
|
-
1025,
|
|
557
|
-
1283,
|
|
558
|
-
513,
|
|
559
|
-
2053,
|
|
560
|
-
2053,
|
|
561
|
-
1281,
|
|
562
|
-
2054,
|
|
563
|
-
1537,
|
|
564
|
-
515
|
|
565
|
-
],
|
|
566
|
-
supportedVersions: [
|
|
567
|
-
772,
|
|
568
|
-
771,
|
|
569
|
-
770,
|
|
570
|
-
769
|
|
571
|
-
],
|
|
572
|
-
ecPointFormats: [0],
|
|
573
|
-
alpnProtocols: ['h2', 'http/1.1'],
|
|
574
|
-
pskKeyExchangeModes: [1],
|
|
575
|
-
compressionMethods: [0],
|
|
576
|
-
grease: true
|
|
577
|
-
},
|
|
578
|
-
http2: {
|
|
579
|
-
windowUpdate: 10420225,
|
|
580
|
-
headerTableSize: 4096,
|
|
581
|
-
enablePush: 0,
|
|
582
|
-
maxConcurrentStreams: 100,
|
|
583
|
-
initialWindowSize: 2097152,
|
|
584
|
-
maxFrameSize: 16384,
|
|
585
|
-
settingsOrder: [2, 3, 4, 8, 9],
|
|
586
|
-
connectionPreface: Buffer.from('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'),
|
|
587
|
-
priorityFrames: [],
|
|
588
|
-
pseudoHeaderOrder: [':method', ':scheme', ':authority', ':path'],
|
|
589
|
-
headerOrder: []
|
|
590
|
-
},
|
|
591
|
-
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1',
|
|
592
|
-
secChUa: '',
|
|
593
|
-
secChUaPlatform: '',
|
|
594
|
-
secChUaMobile: '?1',
|
|
595
|
-
secFetchSite: 'none',
|
|
596
|
-
secFetchMode: 'navigate',
|
|
597
|
-
secFetchDest: 'document'
|
|
598
|
-
};
|
|
599
|
-
}
|
|
600
417
|
static get(name) {
|
|
601
418
|
switch (name.toLowerCase()) {
|
|
602
419
|
case 'chrome_mobile_143_android': return this.chromeMobile143Android();
|
|
603
420
|
case 'chrome_133_psk': return this.chrome133PSK();
|
|
604
421
|
case 'chrome_133': return this.chrome133();
|
|
605
|
-
|
|
606
|
-
case 'safari_ios_18_0': return this.safariIOS18();
|
|
607
|
-
default: return this.chrome133();
|
|
422
|
+
default: return this.chromeMobile143Android();
|
|
608
423
|
}
|
|
609
424
|
}
|
|
610
425
|
static get latest() {
|
|
611
|
-
return this.
|
|
426
|
+
return this.chromeMobile143Android();
|
|
612
427
|
}
|
|
613
428
|
static get latestMobile() {
|
|
614
429
|
return this.chromeMobile143Android();
|
|
@@ -747,11 +562,12 @@ class UnifiedClientManager extends events_1.EventEmitter {
|
|
|
747
562
|
}
|
|
748
563
|
}
|
|
749
564
|
async requestHttp2(path, options, timingStart, headers, post_data, out, callback) {
|
|
565
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
750
566
|
const reqHeaders = {
|
|
751
567
|
':method': options.method?.toUpperCase() || 'GET',
|
|
752
568
|
':authority': this.hostname,
|
|
753
569
|
':scheme': 'https',
|
|
754
|
-
':path':
|
|
570
|
+
':path': normalizedPath,
|
|
755
571
|
...headers
|
|
756
572
|
};
|
|
757
573
|
const stream = this.http2Client.request(reqHeaders);
|
|
@@ -765,6 +581,7 @@ class UnifiedClientManager extends events_1.EventEmitter {
|
|
|
765
581
|
const chunks = [];
|
|
766
582
|
const rawChunks = [];
|
|
767
583
|
let finished = false;
|
|
584
|
+
let hasHeaders = false;
|
|
768
585
|
const finish = async (error) => {
|
|
769
586
|
if (finished)
|
|
770
587
|
return;
|
|
@@ -805,10 +622,9 @@ class UnifiedClientManager extends events_1.EventEmitter {
|
|
|
805
622
|
response.timing.total = response.timing.end;
|
|
806
623
|
if (!out.writableEnded && !out.destroyed)
|
|
807
624
|
out.end();
|
|
808
|
-
if (callback)
|
|
809
|
-
setImmediate(() => callback(null, response, response.body));
|
|
810
625
|
};
|
|
811
626
|
stream.once('response', (hdrs) => {
|
|
627
|
+
hasHeaders = true;
|
|
812
628
|
response.statusCode = hdrs[':status'];
|
|
813
629
|
response.headers = hdrs;
|
|
814
630
|
if (hdrs['set-cookie'])
|
|
@@ -816,6 +632,8 @@ class UnifiedClientManager extends events_1.EventEmitter {
|
|
|
816
632
|
response.timing.response = Date.now() - timingStart;
|
|
817
633
|
out.emit('header', response.statusCode, hdrs);
|
|
818
634
|
out.emit('headers', hdrs);
|
|
635
|
+
if (callback)
|
|
636
|
+
setImmediate(() => callback(null, response));
|
|
819
637
|
});
|
|
820
638
|
stream.on('data', (chunk) => {
|
|
821
639
|
if (finished || out.destroyed || out.writableEnded)
|
|
@@ -868,7 +686,7 @@ class UnifiedClientManager extends events_1.EventEmitter {
|
|
|
868
686
|
headers: { host: this.hostname, ...headers },
|
|
869
687
|
createConnection: () => this.tlsSocket
|
|
870
688
|
};
|
|
871
|
-
const req =
|
|
689
|
+
const req = https.request(reqOptions);
|
|
872
690
|
const response = new events_1.EventEmitter();
|
|
873
691
|
response.timing = { socket: timingStart, lookup: 0, connect: 0, secureConnect: 0, response: 0, end: 0, total: 0 };
|
|
874
692
|
response.fingerprints = {
|
|
@@ -879,6 +697,7 @@ class UnifiedClientManager extends events_1.EventEmitter {
|
|
|
879
697
|
const chunks = [];
|
|
880
698
|
const rawChunks = [];
|
|
881
699
|
let finished = false;
|
|
700
|
+
let hasHeaders = false;
|
|
882
701
|
const finish = async (error, res) => {
|
|
883
702
|
if (finished)
|
|
884
703
|
return;
|
|
@@ -921,10 +740,9 @@ class UnifiedClientManager extends events_1.EventEmitter {
|
|
|
921
740
|
response.timing.total = response.timing.end;
|
|
922
741
|
if (!out.writableEnded && !out.destroyed)
|
|
923
742
|
out.end();
|
|
924
|
-
if (callback)
|
|
925
|
-
setImmediate(() => callback(null, response, response.body));
|
|
926
743
|
};
|
|
927
744
|
req.once('response', (res) => {
|
|
745
|
+
hasHeaders = true;
|
|
928
746
|
response.statusCode = res.statusCode;
|
|
929
747
|
response.headers = res.headers;
|
|
930
748
|
if (res.headers['set-cookie'])
|
|
@@ -932,6 +750,8 @@ class UnifiedClientManager extends events_1.EventEmitter {
|
|
|
932
750
|
response.timing.response = Date.now() - timingStart;
|
|
933
751
|
out.emit('header', response.statusCode, res.headers);
|
|
934
752
|
out.emit('headers', res.headers);
|
|
753
|
+
if (callback)
|
|
754
|
+
setImmediate(() => callback(null, response));
|
|
935
755
|
res.on('data', (chunk) => {
|
|
936
756
|
if (finished || out.destroyed || out.writableEnded)
|
|
937
757
|
return;
|
|
@@ -1133,7 +953,7 @@ class AdvancedTLSClient {
|
|
|
1133
953
|
follow_if_same_location: false,
|
|
1134
954
|
use_proxy_from_env_var: true
|
|
1135
955
|
};
|
|
1136
|
-
this.profile = ProfileRegistry.get(profileName || '
|
|
956
|
+
this.profile = ProfileRegistry.get(profileName || 'chrome_mobile_143_android');
|
|
1137
957
|
this.cleanupInterval = setInterval(() => {
|
|
1138
958
|
const now = Date.now();
|
|
1139
959
|
for (const [key, session] of this.sessionCache) {
|
|
@@ -1147,7 +967,7 @@ class AdvancedTLSClient {
|
|
|
1147
967
|
}
|
|
1148
968
|
setup(uri, options) {
|
|
1149
969
|
const config = {
|
|
1150
|
-
headers: {
|
|
970
|
+
headers: {},
|
|
1151
971
|
proxy: options.proxy || this.defaults.proxy,
|
|
1152
972
|
decompress: options.decompress !== undefined ? options.decompress : true
|
|
1153
973
|
};
|
|
@@ -1165,6 +985,10 @@ class AdvancedTLSClient {
|
|
|
1165
985
|
config.headers['upgrade-insecure-requests'] = this.profile.upgradeInsecureRequests;
|
|
1166
986
|
if (this.profile.priority)
|
|
1167
987
|
config.headers['priority'] = this.profile.priority;
|
|
988
|
+
// Override with user headers
|
|
989
|
+
if (options.headers) {
|
|
990
|
+
Object.assign(config.headers, options.headers);
|
|
991
|
+
}
|
|
1168
992
|
return config;
|
|
1169
993
|
}
|
|
1170
994
|
async request(uri, data, options = {}, callback) {
|
|
@@ -1172,6 +996,9 @@ class AdvancedTLSClient {
|
|
|
1172
996
|
callback = options;
|
|
1173
997
|
options = {};
|
|
1174
998
|
}
|
|
999
|
+
if (data && typeof data !== 'object' && !Buffer.isBuffer(data) && !(data instanceof stream_1.Readable)) {
|
|
1000
|
+
throw new Error('Invalid data type');
|
|
1001
|
+
}
|
|
1175
1002
|
const parsed = new url.URL(uri);
|
|
1176
1003
|
const hostname = parsed.hostname;
|
|
1177
1004
|
const port = parsed.port ? +parsed.port : 443;
|
|
@@ -1197,7 +1024,10 @@ class AdvancedTLSClient {
|
|
|
1197
1024
|
session.lastUsed = Date.now();
|
|
1198
1025
|
const config = this.setup(uri, options);
|
|
1199
1026
|
let post_data = null;
|
|
1200
|
-
let json = options.json
|
|
1027
|
+
let json = options.json !== undefined ? options.json : false;
|
|
1028
|
+
if (json === undefined && config.headers['content-type']?.includes('application/json')) {
|
|
1029
|
+
json = true;
|
|
1030
|
+
}
|
|
1201
1031
|
if (data) {
|
|
1202
1032
|
if (options.multipart) {
|
|
1203
1033
|
const boundary = options.boundary || this.defaults.boundary;
|
|
@@ -1233,10 +1063,9 @@ class AdvancedTLSClient {
|
|
|
1233
1063
|
return out;
|
|
1234
1064
|
}
|
|
1235
1065
|
if (callback) {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
typedCallback(err);
|
|
1066
|
+
session.clientManager.request(path, options, startTime, config.headers, post_data, out, callback).catch(err => {
|
|
1067
|
+
if (callback)
|
|
1068
|
+
callback(err);
|
|
1240
1069
|
});
|
|
1241
1070
|
return out;
|
|
1242
1071
|
}
|