JavaScript · 8113 bytes Raw Blame History
1 // Unified Message Handler for Chrome Manifest V3
2 // Handles messages from all supported platforms
3
4 export class UnifiedMessageHandler {
5 constructor() {
6 this.serverUrl = 'http://localhost:8765';
7 this.activeConversations = new Map();
8 this.responseQueue = [];
9 this.isProcessing = false;
10 this.settings = {
11 autoActivateOnScammer: true,
12 scammerThreshold: 0.7,
13 maxResponseDelay: 15000,
14 minResponseDelay: 2000,
15 personalityRotation: false
16 };
17 }
18
19 async processMessage(data) {
20 try {
21 // Add to conversation on server
22 const contextResponse = await fetch(`${this.serverUrl}/conversation/add`, {
23 method: 'POST',
24 headers: { 'Content-Type': 'application/json' },
25 body: JSON.stringify({
26 chatId: data.chatId,
27 platform: data.platform || this.detectPlatform(data.url),
28 message: data
29 })
30 });
31
32 const context = await contextResponse.json();
33
34 // Check for auto-activation
35 if (this.settings.autoActivateOnScammer &&
36 context.scammerScore > this.settings.scammerThreshold &&
37 !this.isConversationActive(data.chatId, data.platform)) {
38
39 this.activateConversation(data.chatId, data.platform, data.tabId);
40
41 // Notify content script
42 chrome.tabs.sendMessage(data.tabId, {
43 type: 'SCAMMER_DETECTED',
44 data: {
45 score: context.scammerScore,
46 autoActivated: true
47 }
48 });
49 }
50
51 // Only generate response if active
52 if (!this.isConversationActive(data.chatId, data.platform)) {
53 return {
54 processed: false,
55 reason: 'Conversation not active',
56 scammerScore: context.scammerScore
57 };
58 }
59
60 // Get response suggestions
61 const suggestionsResponse = await fetch(`${this.serverUrl}/suggestions`, {
62 method: 'POST',
63 headers: { 'Content-Type': 'application/json' },
64 body: JSON.stringify({
65 chatId: data.chatId,
66 platform: data.platform,
67 context
68 })
69 });
70
71 const suggestions = await suggestionsResponse.json();
72
73 // Select personality
74 const personality = await this.selectPersonality(data.chatId, context);
75
76 // Generate response
77 const generateResponse = await fetch(`${this.serverUrl}/generate`, {
78 method: 'POST',
79 headers: { 'Content-Type': 'application/json' },
80 body: JSON.stringify({
81 message: data.content || data.text,
82 personality,
83 chatId: data.chatId,
84 platform: data.platform || this.detectPlatform(data.url),
85 context,
86 suggestions,
87 timestamp: data.timestamp
88 })
89 });
90
91 const result = await generateResponse.json();
92
93 // Calculate delay
94 const delay = this.calculateResponseDelay(result.reply, context);
95
96 // Queue response
97 await this.queueResponse({
98 tabId: data.tabId,
99 platform: data.platform || this.detectPlatform(data.url),
100 chatId: data.chatId,
101 reply: result.reply,
102 delay,
103 personality
104 });
105
106 return {
107 queued: true,
108 reply: result.reply,
109 delay,
110 personality,
111 scammerScore: context.scammerScore
112 };
113
114 } catch (error) {
115 console.error('[UnifiedHandler] Error:', error);
116
117 const fallback = this.getFallbackResponse(data.platform);
118 return {
119 reply: fallback,
120 delay: 3000,
121 error: error.message
122 };
123 }
124 }
125
126 detectPlatform(url) {
127 if (!url) return 'unknown';
128
129 if (url.includes('whatsapp.com')) return 'whatsapp';
130 if (url.includes('telegram.org')) return 'telegram';
131 if (url.includes('messenger.com')) return 'messenger';
132
133 return 'unknown';
134 }
135
136 async selectPersonality(chatId, context) {
137 if (!this.settings.personalityRotation) {
138 return context.personality || 'default';
139 }
140
141 // Load available personalities
142 const stored = await chrome.storage.local.get('personalities');
143 const personalities = stored.personalities || ['default'];
144
145 // Rotate based on message count
146 const messageCount = context.messageCount || 0;
147 const index = Math.floor(messageCount / 5) % personalities.length;
148
149 return personalities[index];
150 }
151
152 calculateResponseDelay(text, context) {
153 const wordCount = text.split(' ').length;
154 const baseDelay = this.settings.minResponseDelay;
155 const perWordDelay = 150;
156
157 let delay = baseDelay + (wordCount * perWordDelay);
158
159 // Adjust based on context
160 if (context.conversationTone === 'urgent') {
161 delay *= 1.5; // Be slower for urgent scammers
162 }
163
164 // Add random variation
165 const variation = 0.3;
166 const randomFactor = 1 + (Math.random() * 2 * variation - variation);
167 delay *= randomFactor;
168
169 return Math.min(delay, this.settings.maxResponseDelay);
170 }
171
172 async queueResponse(response) {
173 this.responseQueue.push({
174 ...response,
175 queuedAt: Date.now()
176 });
177
178 if (!this.isProcessing) {
179 this.processQueue();
180 }
181 }
182
183 async processQueue() {
184 if (this.responseQueue.length === 0) {
185 this.isProcessing = false;
186 return;
187 }
188
189 this.isProcessing = true;
190 const response = this.responseQueue.shift();
191
192 // Calculate remaining delay
193 const elapsed = Date.now() - response.queuedAt;
194 const remainingDelay = Math.max(0, response.delay - elapsed);
195
196 // Wait
197 await this.sleep(remainingDelay);
198
199 // Send response
200 try {
201 await chrome.tabs.sendMessage(response.tabId, {
202 type: 'SEND_MESSAGE',
203 data: {
204 text: response.reply,
205 delay: 0
206 }
207 });
208
209 console.log(`[UnifiedHandler] Sent response to ${response.platform}:${response.chatId}`);
210 } catch (error) {
211 console.error('[UnifiedHandler] Failed to send response:', error);
212 }
213
214 // Process next
215 this.processQueue();
216 }
217
218 activateConversation(chatId, platform, tabId) {
219 const key = `${platform}:${chatId}`;
220 this.activeConversations.set(key, {
221 chatId,
222 platform,
223 tabId,
224 activatedAt: Date.now(),
225 messageCount: 0
226 });
227
228 console.log(`[UnifiedHandler] Activated ${key}`);
229 }
230
231 deactivateConversation(chatId, platform) {
232 const key = `${platform}:${chatId}`;
233 this.activeConversations.delete(key);
234 console.log(`[UnifiedHandler] Deactivated ${key}`);
235 }
236
237 isConversationActive(chatId, platform) {
238 const key = `${platform}:${chatId}`;
239 return this.activeConversations.has(key);
240 }
241
242 getFallbackResponse(platform) {
243 const fallbacks = {
244 whatsapp: [
245 "Sorry, what was that? My WhatsApp is acting strange.",
246 "Can you repeat? The message came through garbled.",
247 "Hold on, my phone is being slow..."
248 ],
249 telegram: [
250 "Telegram is glitching for me, one second...",
251 "Strange, I'm getting errors. What did you say?",
252 "My Telegram is updating, please wait..."
253 ],
254 messenger: [
255 "Facebook is being weird, can you resend?",
256 "Messenger crashed, what were you saying?",
257 "Sorry, Facebook is slow today..."
258 ],
259 default: [
260 "I didn't catch that, can you repeat?",
261 "Sorry, technical difficulties...",
262 "One moment please..."
263 ]
264 };
265
266 const platformFallbacks = fallbacks[platform] || fallbacks.default;
267 return platformFallbacks[Math.floor(Math.random() * platformFallbacks.length)];
268 }
269
270 async getStatistics() {
271 const stats = {
272 activeConversations: this.activeConversations.size,
273 queuedResponses: this.responseQueue.length,
274 platformBreakdown: {}
275 };
276
277 this.activeConversations.forEach(conv => {
278 stats.platformBreakdown[conv.platform] =
279 (stats.platformBreakdown[conv.platform] || 0) + 1;
280 });
281
282 return stats;
283 }
284
285 sleep(ms) {
286 return new Promise(resolve => setTimeout(resolve, ms));
287 }
288 }
289
290 // Export for use in service worker
291 if (typeof module !== 'undefined' && module.exports) {
292 module.exports = UnifiedMessageHandler;
293 }