stealth-ws 1.0.0

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.
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Fingerprint profile management
3
+ *
4
+ * Manages TLS fingerprint profiles for different browsers.
5
+ * These are passed to the Go bridge for TLS handshake spoofing.
6
+ */
7
+
8
+ import { readFileSync } from 'fs';
9
+ import { join, dirname } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+
14
+ /**
15
+ * Available fingerprint profiles
16
+ * Maps profile name to Go uTLS Hello spec name
17
+ */
18
+ export const PROFILES = {
19
+ // Chrome versions
20
+ 'chrome120': 'HelloChrome_120',
21
+ 'chrome119': 'HelloChrome_119',
22
+ 'chrome118': 'HelloChrome_118',
23
+ 'chrome117': 'HelloChrome_117',
24
+ 'chrome116': 'HelloChrome_116',
25
+ 'chrome115': 'HelloChrome_115',
26
+ 'chrome114': 'HelloChrome_114',
27
+ 'chrome113': 'HelloChrome_113',
28
+ 'chrome112': 'HelloChrome_112',
29
+ 'chrome110': 'HelloChrome_110',
30
+ 'chrome100': 'HelloChrome_100_Auto',
31
+ 'chromeAuto': 'HelloChrome_Auto',
32
+
33
+ // Firefox versions
34
+ 'firefox121': 'HelloFirefox_121',
35
+ 'firefox120': 'HelloFirefox_120',
36
+ 'firefox115': 'HelloFirefox_115',
37
+ 'firefox110': 'HelloFirefox_110',
38
+ 'firefox100': 'HelloFirefox_100',
39
+ 'firefoxAuto': 'HelloFirefox_Auto',
40
+
41
+ // Safari versions
42
+ 'safari17': 'HelloSafari_17_0',
43
+ 'safari16': 'HelloSafari_16_6',
44
+ 'safari15': 'HelloSafari_15_6',
45
+ 'safari14': 'HelloSafari_14_1',
46
+ 'safariAuto': 'HelloSafari_Auto',
47
+
48
+ // Edge versions
49
+ 'edge120': 'HelloEdge_120',
50
+ 'edge119': 'HelloEdge_119',
51
+ 'edge118': 'HelloEdge_118',
52
+ 'edge117': 'HelloEdge_117',
53
+ 'edge116': 'HelloEdge_116',
54
+ 'edgeAuto': 'HelloEdge_Auto',
55
+
56
+ // iOS
57
+ 'ios17': 'HelloIOS_17_1',
58
+ 'ios16': 'HelloIOS_16_1',
59
+ 'ios15': 'HelloIOS_15_5',
60
+ 'iosAuto': 'HelloIOS_Auto',
61
+
62
+ // Android
63
+ 'android12': 'HelloAndroid_12',
64
+ 'android11': 'HelloAndroid_11',
65
+ 'androidAuto': 'HelloAndroid_Auto'
66
+ };
67
+
68
+ /**
69
+ * FingerprintProfiles class for managing browser fingerprints
70
+ */
71
+ export class FingerprintProfiles {
72
+ /**
73
+ * List all available fingerprint profiles
74
+ *
75
+ * @returns {string[]} Array of profile names
76
+ */
77
+ static list() {
78
+ return Object.keys(PROFILES);
79
+ }
80
+
81
+ /**
82
+ * Get the Go Hello spec name for a profile
83
+ *
84
+ * @param {string} profile - Profile name
85
+ * @returns {string} Go Hello spec name
86
+ */
87
+ static getSpecName(profile) {
88
+ const specName = PROFILES[profile];
89
+ if (!specName) {
90
+ console.warn(`Unknown fingerprint profile: ${profile}, using chrome120`);
91
+ return 'HelloChrome_120';
92
+ }
93
+ return specName;
94
+ }
95
+
96
+ /**
97
+ * Validate a profile name
98
+ *
99
+ * @param {string} profile - Profile name
100
+ * @returns {boolean} True if valid
101
+ */
102
+ static isValid(profile) {
103
+ return profile in PROFILES;
104
+ }
105
+
106
+ /**
107
+ * Get profile by category
108
+ *
109
+ * @param {string} category - 'chrome', 'firefox', 'safari', 'edge', 'ios', 'android'
110
+ * @returns {string[]} Array of profile names in category
111
+ */
112
+ static byCategory(category) {
113
+ const prefix = category.toLowerCase();
114
+ return Object.keys(PROFILES).filter(name => name.startsWith(prefix));
115
+ }
116
+
117
+ /**
118
+ * Get recommended profile for general use
119
+ *
120
+ * @returns {string} Recommended profile name
121
+ */
122
+ static recommended() {
123
+ return 'chrome120';
124
+ }
125
+
126
+ /**
127
+ * Get profile with specific Chrome version
128
+ *
129
+ * @param {number} version - Chrome version (e.g., 120)
130
+ * @returns {string} Profile name
131
+ */
132
+ static chromeVersion(version) {
133
+ const profile = `chrome${version}`;
134
+ if (PROFILES[profile]) {
135
+ return profile;
136
+ }
137
+ // Find closest version
138
+ const versions = Object.keys(PROFILES)
139
+ .filter(k => k.startsWith('chrome') && k !== 'chromeAuto')
140
+ .map(k => parseInt(k.replace('chrome', '')))
141
+ .sort((a, b) => b - a);
142
+
143
+ const closest = versions.find(v => v <= version) || versions[0];
144
+ return `chrome${closest}`;
145
+ }
146
+
147
+ /**
148
+ * Get all Chrome profiles
149
+ *
150
+ * @returns {string[]} Chrome profile names
151
+ */
152
+ static chrome() {
153
+ return this.byCategory('chrome');
154
+ }
155
+
156
+ /**
157
+ * Get all Firefox profiles
158
+ *
159
+ * @returns {string[]} Firefox profile names
160
+ */
161
+ static firefox() {
162
+ return this.byCategory('firefox');
163
+ }
164
+
165
+ /**
166
+ * Get all Safari profiles
167
+ *
168
+ * @returns {string[]} Safari profile names
169
+ */
170
+ static safari() {
171
+ return this.byCategory('safari');
172
+ }
173
+
174
+ /**
175
+ * Get all Edge profiles
176
+ *
177
+ * @returns {string[]} Edge profile names
178
+ */
179
+ static edge() {
180
+ return this.byCategory('edge');
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Get default fingerprint configuration
186
+ *
187
+ * @returns {Object} Default fingerprint config
188
+ */
189
+ export function getDefaultFingerprint() {
190
+ return {
191
+ profile: 'chrome120',
192
+ specName: PROFILES['chrome120']
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Create a custom fingerprint configuration
198
+ *
199
+ * @param {Object} options - Custom fingerprint options
200
+ * @returns {Object} Fingerprint configuration
201
+ */
202
+ export function createCustomFingerprint(options = {}) {
203
+ return {
204
+ profile: options.profile || 'custom',
205
+ specName: options.specName || 'HelloChrome_Auto',
206
+ customSpec: options.customSpec || null
207
+ };
208
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,74 @@
1
+ /// <reference types="node" />
2
+
3
+ import { EventEmitter } from 'events';
4
+
5
+ export interface WebSocketOptions {
6
+ fingerprint?: string;
7
+ cookies?: string | Array<{ name: string; value: string }> | CookieJar;
8
+ proxy?: string;
9
+ headers?: Record<string, string>;
10
+ perMessageDeflate?: boolean;
11
+ debug?: boolean;
12
+ }
13
+
14
+ export declare class WebSocket extends EventEmitter {
15
+ static readonly CONNECTING: 0;
16
+ static readonly OPEN: 1;
17
+ static readonly CLOSING: 2;
18
+ static readonly CLOSED: 3;
19
+
20
+ readonly url: string;
21
+ readonly readyState: 0 | 1 | 2 | 3;
22
+ readonly protocol: string;
23
+ readonly extensions: string;
24
+ readonly bufferedAmount: number;
25
+ binaryType: 'nodebuffer' | 'arraybuffer' | 'fragments';
26
+
27
+ constructor(url: string, options?: WebSocketOptions);
28
+
29
+ send(data: string | Buffer, options?: { binary?: boolean }, callback?: (err?: Error) => void): void;
30
+ close(code?: number, reason?: string): void;
31
+ terminate(): void;
32
+ ping(data?: string | Buffer, mask?: boolean, callback?: (err?: Error) => void): void;
33
+ pong(data?: string | Buffer, mask?: boolean, callback?: (err?: Error) => void): void;
34
+ pause(): void;
35
+ resume(): void;
36
+
37
+ addEventListener(type: 'open', listener: () => void): void;
38
+ addEventListener(type: 'message', listener: (data: Buffer, isBinary: boolean) => void): void;
39
+ addEventListener(type: 'close', listener: (code: number, reason: string) => void): void;
40
+ addEventListener(type: 'error', listener: (err: Error) => void): void;
41
+ addEventListener(type: string, listener: (...args: unknown[]) => void): void;
42
+
43
+ removeEventListener(type: string, listener: (...args: unknown[]) => void): void;
44
+
45
+ on(event: 'open', listener: () => void): this;
46
+ on(event: 'message', listener: (data: Buffer, isBinary: boolean) => void): this;
47
+ on(event: 'close', listener: (code: number, reason: string) => void): this;
48
+ on(event: 'error', listener: (err: Error) => void): this;
49
+ on(event: 'ping', listener: (data?: Buffer) => void): this;
50
+ on(event: 'auth_required', listener: () => void): this;
51
+ on(event: string, listener: (...args: unknown[]) => void): this;
52
+ }
53
+
54
+ export declare class FingerprintProfiles {
55
+ static list(): string[];
56
+ static getSpecName(profile: string): string;
57
+ static isValid(profile: string): boolean;
58
+ static byCategory(category: 'chrome' | 'firefox' | 'safari' | 'edge' | 'ios' | 'android'): string[];
59
+ static recommended(): string;
60
+ static chromeVersion(version: number): string;
61
+ static chrome(): string[];
62
+ static firefox(): string[];
63
+ static safari(): string[];
64
+ static edge(): string[];
65
+ }
66
+
67
+ export declare class CookieJar {
68
+ loadFromFile(path: string): void;
69
+ getCookieString(url: string): string;
70
+ }
71
+
72
+ export declare const VERSION: string;
73
+
74
+ export default WebSocket;
package/lib/index.js ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * stealth-ws - WebSocket client with TLS fingerprint spoofing
3
+ *
4
+ * A drop-in replacement for the 'ws' package that spoofs browser
5
+ * TLS fingerprints to bypass Cloudflare and other bot detection systems.
6
+ */
7
+
8
+ import { WebSocket } from './websocket.js';
9
+ import { FingerprintProfiles } from './fingerprint.js';
10
+ import { CookieJar } from './cookie-jar.js';
11
+
12
+ // Re-export WebSocket class as default export
13
+ export default WebSocket;
14
+
15
+ // Export named exports
16
+ export {
17
+ WebSocket,
18
+ FingerprintProfiles,
19
+ CookieJar
20
+ };
21
+
22
+ // Static properties for compatibility with ws
23
+ WebSocket.CONNECTING = 0;
24
+ WebSocket.OPEN = 1;
25
+ WebSocket.CLOSING = 2;
26
+ WebSocket.CLOSED = 3;
27
+
28
+ // Version
29
+ export const VERSION = '1.0.0';