@prototypevip/baileys 0.0.9 → 0.1.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.
Files changed (50) hide show
  1. package/lib/Socket/index.js +12 -135
  2. package/lib/Socket/messages-send.js +27 -44
  3. package/package.json +2 -2
  4. package/lib/AntiBan/antiban.js +0 -922
  5. package/lib/AntiBan/banRecoveryOrchestrator.js +0 -284
  6. package/lib/AntiBan/cli.js +0 -177
  7. package/lib/AntiBan/contactGraph.js +0 -236
  8. package/lib/AntiBan/contentVariator.js +0 -150
  9. package/lib/AntiBan/credsSnapshot.js +0 -121
  10. package/lib/AntiBan/deliveryTracker.js +0 -107
  11. package/lib/AntiBan/deviceFingerprint.js +0 -106
  12. package/lib/AntiBan/fleetEventStore.js +0 -157
  13. package/lib/AntiBan/groupOperationGuard.js +0 -116
  14. package/lib/AntiBan/health.js +0 -207
  15. package/lib/AntiBan/humanEntropy.js +0 -337
  16. package/lib/AntiBan/index.js +0 -77
  17. package/lib/AntiBan/instanceCoordinator.js +0 -175
  18. package/lib/AntiBan/jidCanonicalizer.js +0 -256
  19. package/lib/AntiBan/jidCircuitBreaker.js +0 -186
  20. package/lib/AntiBan/legitimacySignalInjector.js +0 -231
  21. package/lib/AntiBan/lidFirstResolver.js +0 -174
  22. package/lib/AntiBan/lidResolver.js +0 -324
  23. package/lib/AntiBan/messageQueue.js +0 -187
  24. package/lib/AntiBan/messageRecovery.js +0 -283
  25. package/lib/AntiBan/messageTypeRegistry.js +0 -369
  26. package/lib/AntiBan/observability.js +0 -145
  27. package/lib/AntiBan/patch.js +0 -302
  28. package/lib/AntiBan/persist.js +0 -87
  29. package/lib/AntiBan/presenceChoreographer.js +0 -430
  30. package/lib/AntiBan/presets.js +0 -105
  31. package/lib/AntiBan/profiles.js +0 -31
  32. package/lib/AntiBan/proxyRotator.js +0 -306
  33. package/lib/AntiBan/rateLimiter.js +0 -261
  34. package/lib/AntiBan/readReceiptVariance.js +0 -88
  35. package/lib/AntiBan/reconnectThrottle.js +0 -180
  36. package/lib/AntiBan/replyRatio.js +0 -161
  37. package/lib/AntiBan/reputationVoucher.js +0 -373
  38. package/lib/AntiBan/retryReason.js +0 -91
  39. package/lib/AntiBan/retryTracker.js +0 -172
  40. package/lib/AntiBan/scheduler.js +0 -111
  41. package/lib/AntiBan/sessionFingerprint.js +0 -248
  42. package/lib/AntiBan/sessionStability.js +0 -330
  43. package/lib/AntiBan/stateAdapter.js +0 -73
  44. package/lib/AntiBan/stateExport.js +0 -152
  45. package/lib/AntiBan/stealthConnect.js +0 -130
  46. package/lib/AntiBan/timelockGuard.js +0 -181
  47. package/lib/AntiBan/topologyThrottler.js +0 -339
  48. package/lib/AntiBan/warmup.js +0 -140
  49. package/lib/AntiBan/webhooks.js +0 -80
  50. package/lib/AntiBan/wrapper.js +0 -456
@@ -1,231 +0,0 @@
1
- /**
2
- * LegitimacySignalInjector — Human imperfection signals
3
- *
4
- * WhatsApp's detection looks for accounts that are TOO perfect:
5
- * - Never make typos
6
- * - Always reply at consistent speeds
7
- * - Typing duration linearly correlates with message length
8
- *
9
- * This module injects realistic imperfections:
10
- * - Typos followed by corrections (2-3% of messages)
11
- * - Read-receipt without immediate reply (read gap)
12
- * - Mid-typing pauses for longer messages
13
- *
14
- * Note: Complements PresenceChoreographer, doesn't replace it.
15
- * PC handles timing/circadian rhythm; this handles content imperfections.
16
- */
17
- const DEFAULT_CONFIG = {
18
- enableTypos: true,
19
- typoProbability: 0.025,
20
- typoCorrectMinMs: 500,
21
- typoCorrectMaxMs: 2000,
22
- enableReadGaps: true,
23
- readGapProbability: 0.15,
24
- readGapMinMs: 300_000,
25
- readGapMaxMs: 3_600_000,
26
- enableTypingPauses: true,
27
- typingPauseLengthThreshold: 50,
28
- typingPauseProbability: 0.4,
29
- typingPauseMinMs: 1_500,
30
- typingPauseMaxMs: 6_000,
31
- };
32
- /**
33
- * QWERTY keyboard adjacency map for realistic typos.
34
- * Maps common keys to their adjacent neighbors.
35
- */
36
- const QWERTY_ADJACENT = {
37
- 'a': ['q', 's', 'w', 'z'],
38
- 'b': ['v', 'g', 'h', 'n'],
39
- 'c': ['x', 'd', 'f', 'v'],
40
- 'd': ['s', 'e', 'r', 'f', 'c', 'x'],
41
- 'e': ['w', 'r', 'd', 's'],
42
- 'f': ['d', 'r', 't', 'g', 'v', 'c'],
43
- 'g': ['f', 't', 'y', 'h', 'b', 'v'],
44
- 'h': ['g', 'y', 'u', 'j', 'n', 'b'],
45
- 'i': ['u', 'o', 'k', 'j'],
46
- 'j': ['h', 'u', 'i', 'k', 'n', 'm'],
47
- 'k': ['j', 'i', 'o', 'l', 'm'],
48
- 'l': ['k', 'o', 'p'],
49
- 'm': ['n', 'j', 'k'],
50
- 'n': ['b', 'h', 'j', 'm'],
51
- 'o': ['i', 'p', 'l', 'k'],
52
- 'p': ['o', 'l'],
53
- 'q': ['w', 'a'],
54
- 'r': ['e', 't', 'f', 'd'],
55
- 's': ['a', 'w', 'e', 'd', 'x', 'z'],
56
- 't': ['r', 'y', 'g', 'f'],
57
- 'u': ['y', 'i', 'j', 'h'],
58
- 'v': ['c', 'f', 'g', 'b'],
59
- 'w': ['q', 'e', 's', 'a'],
60
- 'x': ['z', 's', 'd', 'c'],
61
- 'y': ['t', 'u', 'h', 'g'],
62
- 'z': ['a', 's', 'x'],
63
- };
64
- export class LegitimacySignalInjector {
65
- config;
66
- stats = {
67
- typosInjected: 0,
68
- correctionsGenerated: 0,
69
- readGapsInjected: 0,
70
- typingPausesInjected: 0,
71
- };
72
- constructor(config = {}) {
73
- this.config = { ...DEFAULT_CONFIG, ...config };
74
- }
75
- /**
76
- * Determine if a typo should be injected for this message.
77
- * Returns typo version of text + correction delay, or null if no typo.
78
- */
79
- shouldInjectTypo(text) {
80
- if (!this.config.enableTypos) {
81
- return null;
82
- }
83
- // Only inject typos in messages > 10 chars
84
- if (text.length <= 10) {
85
- return null;
86
- }
87
- // Probability check
88
- if (Math.random() >= this.config.typoProbability) {
89
- return null;
90
- }
91
- // Don't inject typos in URLs
92
- if (this.containsUrl(text)) {
93
- return null;
94
- }
95
- // Extract words (excluding @mentions and numbers)
96
- const words = text.split(/\s+/);
97
- const eligibleWords = words.filter(word => word.length >= 3 && !word.startsWith('@') && !/^\d+$/.test(word));
98
- if (eligibleWords.length === 0) {
99
- return null;
100
- }
101
- // Pick a random eligible word
102
- const targetWord = eligibleWords[Math.floor(Math.random() * eligibleWords.length)];
103
- const typoWord = this.injectTypoInWord(targetWord);
104
- if (!typoWord || typoWord === targetWord) {
105
- return null;
106
- }
107
- // Generate typo text
108
- const typoText = text.replace(targetWord, typoWord);
109
- // Generate correction
110
- const correctionDelay = this.randomBetween(this.config.typoCorrectMinMs, this.config.typoCorrectMaxMs);
111
- // Correction format: "*correctedword" for single word, or full message for short texts
112
- let correctionText;
113
- if (text.length < 30) {
114
- // Short message: resend the whole thing
115
- correctionText = text;
116
- }
117
- else {
118
- // Long message: use WA correction convention
119
- correctionText = `*${targetWord}`;
120
- }
121
- this.stats.typosInjected++;
122
- this.stats.correctionsGenerated++;
123
- return {
124
- typoText,
125
- correctionDelay,
126
- correctionText,
127
- };
128
- }
129
- /**
130
- * Determine if a read gap should be injected before sending a reply.
131
- * Returns gap duration in ms, or null if no gap.
132
- */
133
- shouldInjectReadGap() {
134
- if (!this.config.enableReadGaps) {
135
- return null;
136
- }
137
- if (Math.random() >= this.config.readGapProbability) {
138
- return null;
139
- }
140
- const gapMs = this.randomBetween(this.config.readGapMinMs, this.config.readGapMaxMs);
141
- this.stats.readGapsInjected++;
142
- return gapMs;
143
- }
144
- /**
145
- * For a message of given length, calculate mid-typing pause positions.
146
- * Returns array of { afterChars, pauseDurationMs } or empty array.
147
- */
148
- getTypingPauses(messageLength) {
149
- if (!this.config.enableTypingPauses) {
150
- return [];
151
- }
152
- // Only for messages above threshold
153
- if (messageLength < this.config.typingPauseLengthThreshold) {
154
- return [];
155
- }
156
- // Probability check
157
- if (Math.random() >= this.config.typingPauseProbability) {
158
- return [];
159
- }
160
- const pauses = [];
161
- // Inject 1-2 pauses at natural break points
162
- const numPauses = Math.random() < 0.6 ? 1 : 2;
163
- for (let i = 0; i < numPauses; i++) {
164
- let position;
165
- if (i === 0) {
166
- // First pause around 40% mark
167
- position = Math.floor(messageLength * (0.35 + Math.random() * 0.15));
168
- }
169
- else {
170
- // Second pause around 70% mark
171
- position = Math.floor(messageLength * (0.65 + Math.random() * 0.15));
172
- }
173
- const pauseDurationMs = this.randomBetween(this.config.typingPauseMinMs, this.config.typingPauseMaxMs);
174
- pauses.push({
175
- afterChars: position,
176
- pauseDurationMs,
177
- });
178
- this.stats.typingPausesInjected++;
179
- }
180
- // Sort by position
181
- pauses.sort((a, b) => a.afterChars - b.afterChars);
182
- return pauses;
183
- }
184
- /**
185
- * Get statistics.
186
- */
187
- getStats() {
188
- return { ...this.stats };
189
- }
190
- /**
191
- * Reset statistics.
192
- */
193
- reset() {
194
- this.stats = {
195
- typosInjected: 0,
196
- correctionsGenerated: 0,
197
- readGapsInjected: 0,
198
- typingPausesInjected: 0,
199
- };
200
- }
201
- // Private helpers
202
- injectTypoInWord(word) {
203
- // Find a char that has QWERTY neighbors
204
- const chars = word.toLowerCase().split('');
205
- const eligibleIndices = chars
206
- .map((char, idx) => ({ char, idx }))
207
- .filter(({ char }) => QWERTY_ADJACENT[char] !== undefined);
208
- if (eligibleIndices.length === 0) {
209
- return null;
210
- }
211
- // Pick random position
212
- const target = eligibleIndices[Math.floor(Math.random() * eligibleIndices.length)];
213
- const neighbors = QWERTY_ADJACENT[target.char];
214
- const replacement = neighbors[Math.floor(Math.random() * neighbors.length)];
215
- // Preserve original casing
216
- const originalChar = word[target.idx];
217
- const replacementChar = originalChar === originalChar.toUpperCase()
218
- ? replacement.toUpperCase()
219
- : replacement;
220
- // Build typo word
221
- const typoChars = word.split('');
222
- typoChars[target.idx] = replacementChar;
223
- return typoChars.join('');
224
- }
225
- containsUrl(text) {
226
- return /https?:\/\/|www\./i.test(text);
227
- }
228
- randomBetween(min, max) {
229
- return Math.floor(Math.random() * (max - min + 1)) + min;
230
- }
231
- }
@@ -1,174 +0,0 @@
1
- /**
2
- * LidFirstResolver — Standalone LID↔Phone mapper for Baileys auth state
3
- *
4
- * Lightweight drop-in utility that:
5
- * - Loads LID↔phone mappings from Baileys' auth state directory
6
- * - Resolves phone numbers to LID JIDs and vice versa
7
- * - Learns new mappings from Baileys events
8
- * - Works independently of the full AntiBan system
9
- *
10
- * Usage:
11
- * ```typescript
12
- * import { LidFirstResolver } from 'baileys-antiban';
13
- * const resolver = new LidFirstResolver();
14
- * resolver.loadFromAuthDir('./whatsapp-auth/my-session');
15
- * const jid = resolver.resolveToLID('27825651069'); // → "210543692497008@lid" or null
16
- * ```
17
- *
18
- * @author Kobus Wentzel <kobie@pop.co.za>
19
- * @license MIT
20
- */
21
- import * as fs from 'fs';
22
- import * as path from 'path';
23
- export class LidFirstResolver {
24
- lidToPhone = new Map();
25
- phoneToLid = new Map(); // phone → lid (quick reverse lookup)
26
- /**
27
- * Load mappings from Baileys auth state directory.
28
- * Looks for lid-mapping-*_reverse.json files.
29
- */
30
- loadFromAuthDir(authDir) {
31
- try {
32
- if (!fs.existsSync(authDir)) {
33
- return; // Directory doesn't exist, nothing to load
34
- }
35
- const files = fs.readdirSync(authDir);
36
- const reverseMappingFiles = files.filter(f => f.startsWith('lid-mapping-') && f.endsWith('_reverse.json'));
37
- for (const file of reverseMappingFiles) {
38
- const filePath = path.join(authDir, file);
39
- const content = fs.readFileSync(filePath, 'utf-8');
40
- const data = JSON.parse(content);
41
- // Baileys reverse mapping format: { "lid@lid": "phone@s.whatsapp.net" }
42
- for (const [lid, pnJid] of Object.entries(data)) {
43
- if (typeof pnJid === 'string') {
44
- const phone = this.extractPhone(pnJid);
45
- if (phone && lid.endsWith('@lid')) {
46
- const mapping = {
47
- lid: this.normalizeLid(lid),
48
- phone,
49
- learnedAt: Date.now(),
50
- source: 'auth-dir',
51
- };
52
- this.lidToPhone.set(mapping.lid, mapping);
53
- this.phoneToLid.set(phone, mapping.lid);
54
- }
55
- }
56
- }
57
- }
58
- }
59
- catch (error) {
60
- // Silently fail — don't crash if auth dir is malformed
61
- }
62
- }
63
- /**
64
- * Learn a new mapping from a Baileys event (messages, contacts, etc.).
65
- * Accepts partial data — will extract what it can.
66
- */
67
- learnFromEvent(event) {
68
- try {
69
- // Extract from message event structure
70
- if (event.key?.remoteJid) {
71
- const jid = event.key.remoteJid;
72
- this.learnJid(jid, 'event');
73
- }
74
- // Extract from participant field (group messages)
75
- if (event.key?.participant) {
76
- const jid = event.key.participant;
77
- this.learnJid(jid, 'event');
78
- }
79
- // Extract from contact event
80
- if (event.id) {
81
- this.learnJid(event.id, 'event');
82
- }
83
- // Extract from pushName field (has phone)
84
- if (event.pushName && event.key?.remoteJid) {
85
- this.learnJid(event.key.remoteJid, 'event');
86
- }
87
- }
88
- catch (error) {
89
- // Silently fail — don't crash on malformed events
90
- }
91
- }
92
- /**
93
- * Resolve phone number or phone JID to LID JID.
94
- * Returns null if not known.
95
- */
96
- resolveToLID(phoneOrJid) {
97
- const phone = this.extractPhone(phoneOrJid);
98
- if (!phone)
99
- return null;
100
- return this.phoneToLid.get(phone) || null;
101
- }
102
- /**
103
- * Resolve LID JID to phone number.
104
- * Returns null if not known.
105
- */
106
- resolveToPhone(lid) {
107
- const normalized = this.normalizeLid(lid);
108
- const mapping = this.lidToPhone.get(normalized);
109
- return mapping ? mapping.phone : null;
110
- }
111
- /**
112
- * Get full mapping for a given JID (either LID or phone).
113
- * Returns null if not known.
114
- */
115
- getMapping(jid) {
116
- const normalized = this.normalizeLid(jid);
117
- // Try as LID
118
- const byLid = this.lidToPhone.get(normalized);
119
- if (byLid)
120
- return byLid;
121
- // Try as phone
122
- const phone = this.extractPhone(jid);
123
- if (phone) {
124
- const lid = this.phoneToLid.get(phone);
125
- if (lid)
126
- return this.lidToPhone.get(lid) || null;
127
- }
128
- return null;
129
- }
130
- /**
131
- * Get total number of known mappings.
132
- */
133
- size() {
134
- return this.lidToPhone.size;
135
- }
136
- /**
137
- * Clear all mappings.
138
- */
139
- clear() {
140
- this.lidToPhone.clear();
141
- this.phoneToLid.clear();
142
- }
143
- // Private helpers
144
- learnJid(_jid, _source) {
145
- // Check if this is a LID JID with a phone equivalent we can learn
146
- // For now, we can only learn from auth dir or from paired data
147
- // Single JID without context can't create a mapping
148
- // This is intentionally limited — real learning happens in loadFromAuthDir
149
- }
150
- extractPhone(jid) {
151
- if (!jid)
152
- return null;
153
- // Remove @s.whatsapp.net suffix if present
154
- let cleaned = jid.replace('@s.whatsapp.net', '');
155
- // Remove device suffix :N if present
156
- cleaned = cleaned.replace(/:\d+$/, '');
157
- // Check if it's a phone number (digits only)
158
- if (/^\d+$/.test(cleaned)) {
159
- return cleaned;
160
- }
161
- return null;
162
- }
163
- normalizeLid(lid) {
164
- // Remove device suffix :N if present
165
- return lid.replace(/:\d+@/, '@');
166
- }
167
- }
168
- /**
169
- * Factory function for creating a singleton resolver instance.
170
- * Useful for shared state across modules.
171
- */
172
- export function createLidFirstResolver() {
173
- return new LidFirstResolver();
174
- }