Forgets commited on
Commit
e2fe8e8
·
verified ·
1 Parent(s): 7358211

Update endpoints/antibot.js

Browse files
Files changed (1) hide show
  1. endpoints/antibot.js +84 -159
endpoints/antibot.js CHANGED
@@ -1,75 +1,40 @@
1
  const fs = require('fs');
2
  const path = require('path');
3
- const { extractTextFromImage, uploadImageToHosting } = require('./imageProcessor');
 
4
 
5
- // Map angka kata -> digit
6
  const NUMBER_WORDS = {
7
  'nol': '0', 'satu': '1', 'dua': '2', 'tiga': '3', 'empat': '4', 'lima': '5',
8
  'enam': '6', 'tujuh': '7', 'delapan': '8', 'sembilan': '9', 'sepuluh': '10',
9
- 'sebelas': '11', 'belas': '', 'puluh': '', 'ratus': '', 'ribu': ''
 
10
  };
11
 
12
- // Simple leet replacements
13
  const LEET_MAP = {
14
  '4': 'a', '@': 'a', '8': 'b', '3': 'e', '6': 'g', '1': 'i', '!': 'i', '0': 'o',
15
  '5': 's', '$': 's', '7': 't', '+': 't', '2': 'z'
16
  };
17
 
18
- function safeString(s) {
19
- return (s || '').toString();
20
- }
21
-
22
- async function extractTextFromBuffer(imageBuffer) {
23
- try {
24
- if (!imageBuffer) throw new Error('No image buffer provided');
25
- if (!Buffer.isBuffer(imageBuffer)) throw new Error('extractTextFromBuffer expects a Buffer');
26
-
27
- console.log('🖼️ DEBUG extractTextFromBuffer: Received buffer, size:', imageBuffer.length, 'bytes');
28
-
29
- const result = await extractTextFromImage(imageBuffer);
30
- console.log('✅ DEBUG extractTextFromBuffer: Hasil ekstraksi:', result);
31
- return result;
32
- } catch (error) {
33
- console.error('❌ DEBUG extractTextFromBuffer Error:', error.message);
34
- return { status: false, response: 'Gagal memproses gambar' };
35
- }
36
- }
37
-
38
- function removeAccents(str) {
39
- return safeString(str).normalize('NFD').replace(/[\u0300-\u036f]/g, '');
40
- }
41
-
42
- function applyLeetMap(str) {
43
- let out = '';
44
- for (const ch of str) {
45
- out += (LEET_MAP[ch] !== undefined) ? LEET_MAP[ch] : ch;
46
- }
47
- return out;
48
- }
49
-
50
- function wordsToNumbers(str) {
51
- // Very simple conversion for single-word numbers in Indonesian (e.g., "tujuh" -> "7")
52
- const tokens = str.split(/\s+/);
53
- return tokens.map(t => {
54
- const low = t.toLowerCase();
55
- return NUMBER_WORDS[low] !== undefined ? NUMBER_WORDS[low] : t;
56
- }).join(' ');
57
- }
58
 
59
  function normalizeText(text) {
60
  const original = safeString(text);
61
- let normalized = removeAccents(original);
62
  normalized = normalized.toLowerCase();
63
- normalized = applyLeetMap(normalized);
64
- // keep letters, numbers and spaces only
 
 
 
65
  normalized = normalized.replace(/[^a-z0-9\s]/g, ' ').replace(/\s+/g, ' ').trim();
66
- // map simple number words
67
- normalized = wordsToNumbers(normalized);
68
- console.log(`🔤 DEBUG normalizeText: "${original}" -> "${normalized}"`);
69
  return normalized;
70
  }
71
 
72
- // Levenshtein distance for fuzzy matching
73
  function levenshtein(a = '', b = '') {
74
  const alen = a.length, blen = b.length;
75
  if (alen === 0) return blen;
@@ -80,133 +45,93 @@ function levenshtein(a = '', b = '') {
80
  for (let i = 1; i <= alen; i++) {
81
  for (let j = 1; j <= blen; j++) {
82
  const cost = a[i - 1] === b[j - 1] ? 0 : 1;
83
- matrix[i][j] = Math.min(
84
- matrix[i - 1][j] + 1,
85
- matrix[i][j - 1] + 1,
86
- matrix[i - 1][j - 1] + cost
87
- );
88
  }
89
  }
90
  return matrix[alen][blen];
91
  }
92
 
93
  function similarity(a, b) {
94
- a = safeString(a);
95
- b = safeString(b);
96
  if (a === b) return 1;
97
  const dist = levenshtein(a, b);
98
  const maxLen = Math.max(a.length, b.length);
99
  return maxLen === 0 ? 1 : 1 - (dist / maxLen);
100
  }
101
 
102
- function tryEvaluateMathExpression(s) {
103
- // allow simple expressions like "3+4", " 7 - 2 ", "2 * (3+1)"
104
  try {
105
- const cleaned = s.replace(/[^0-9+\-*/().\s]/g, '');
106
- if (!/[0-9]/.test(cleaned)) return null;
107
- // eslint-disable-next-line no-new-func
108
- const val = Function(`"use strict"; return (${cleaned});`)();
109
- if (typeof val === 'number' && isFinite(val)) return String(val);
110
- return null;
111
- } catch {
112
- return null;
113
- }
114
- }
115
-
116
- // compare OCR value with expected soal (question) with multiple heuristics
117
- function isValueMatch(value, soal, options = {}) {
118
- const { fuzzyThreshold = 0.75 } = options;
119
- console.log('🔍 DEBUG isValueMatch: Value="%s", Soal="%s"', value, soal);
120
- if (!value && !soal) return false;
121
-
122
- const vNorm = normalizeText(safeString(value));
123
- const sNorm = normalizeText(safeString(soal));
124
-
125
- // exact match
126
- if (vNorm === sNorm) {
127
- console.log('✅ DEBUG exact match');
128
- return true;
129
- }
130
-
131
- // try math evaluation for both sides
132
- const vMath = tryEvaluateMathExpression(vNorm);
133
- const sMath = tryEvaluateMathExpression(sNorm);
134
- if (vMath !== null && sMath !== null && vMath === sMath) {
135
- console.log('✅ DEBUG math match:', vMath);
136
- return true;
137
- }
138
- if (vMath !== null && sMath === null && vMath === sNorm) {
139
- console.log('✅ DEBUG math->soal match:', vMath);
140
- return true;
141
- }
142
- if (sMath !== null && vMath === null && sMath === vNorm) {
143
- console.log('✅ DEBUG soal->math match:', sMath);
144
- return true;
145
- }
146
-
147
- // numeric comparison if either is numeric
148
- const vNum = parseFloat(vNorm);
149
- const sNum = parseFloat(sNorm);
150
- if (!isNaN(vNum) && !isNaN(sNum) && Math.abs(vNum - sNum) < 1e-9) {
151
- console.log('✅ DEBUG numeric equal');
152
- return true;
153
- }
154
 
155
- // fuzzy text similarity
156
- const sim = similarity(vNorm, sNorm);
157
- console.log('📊 DEBUG Similarity:', sim);
158
- if (sim >= fuzzyThreshold) {
159
- console.log('✅ DEBUG fuzzy match (threshold=', fuzzyThreshold, ')');
160
- return true;
161
- }
 
 
 
 
 
 
 
 
162
 
163
- // partial match: one contains the other with decent length
164
- if (vNorm && sNorm) {
165
- if (vNorm.includes(sNorm) || sNorm.includes(vNorm)) {
166
- const longer = Math.max(vNorm.length, sNorm.length);
167
- if (longer >= 3) {
168
- console.log('✅ DEBUG partial contains match');
169
- return true;
170
  }
171
  }
172
- }
173
 
174
- console.log('❌ DEBUG: No match found');
175
- return false;
176
- }
 
 
 
177
 
178
- function mapAnswer(soalArray, jawaban, botIndex) {
179
- console.log(`🤖 DEBUG mapAnswer: Bot ${botIndex}, Jawaban: "${jawaban}"`);
180
- // jawaban can be object or string; normalize to string for now
181
- if (jawaban && typeof jawaban === 'object' && jawaban.response) {
182
- return jawaban.response;
183
- }
184
- return jawaban;
185
- }
186
 
187
- // --- Integrated helper from userscript: countPairs ---
188
- function countPairs(s1 = '', s2 = '') {
189
- s1 = safeString(s1).toLowerCase().replace(/[^a-z]/g, '');
190
- s2 = safeString(s2).toLowerCase().replace(/[^a-z]/g, '');
191
- const n1 = s1.length, n2 = s2.length;
192
- const freq1 = Array(26).fill(0);
193
- const freq2 = Array(26).fill(0);
194
- for (let i = 0; i < n1; i++) freq1[s1.charCodeAt(i) - 97] = (freq1[s1.charCodeAt(i) - 97] || 0) + 1;
195
- for (let i = 0; i < n2; i++) freq2[s2.charCodeAt(i) - 97] = (freq2[s2.charCodeAt(i) - 97] || 0) + 1;
196
- let count = 0;
197
- for (let i = 0; i < 26; i++) count += Math.min(freq1[i], freq2[i]);
198
- return count;
199
  }
200
 
201
- // Export utilities
202
- module.exports = {
203
- extractTextFromBuffer,
204
- mapAnswer,
205
- normalizeText,
206
- isValueMatch,
207
- levenshtein,
208
- similarity,
209
- NUMBER_WORDS,
210
- LEET_MAP,
211
- countPairs
212
- };
 
1
  const fs = require('fs');
2
  const path = require('path');
3
+ // Pastikeun file imageProcessor.js aya dina folder anu sarua
4
+ const { extractTextFromImage } = require('./imageProcessor');
5
 
6
+ // --- KONFIGURASI & MAPPING ---
7
  const NUMBER_WORDS = {
8
  'nol': '0', 'satu': '1', 'dua': '2', 'tiga': '3', 'empat': '4', 'lima': '5',
9
  'enam': '6', 'tujuh': '7', 'delapan': '8', 'sembilan': '9', 'sepuluh': '10',
10
+ 'sebelas': '11', 'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5',
11
+ 'six': '6', 'seven': '7', 'eight': '8', 'nine': '9', 'ten': '10'
12
  };
13
 
 
14
  const LEET_MAP = {
15
  '4': 'a', '@': 'a', '8': 'b', '3': 'e', '6': 'g', '1': 'i', '!': 'i', '0': 'o',
16
  '5': 's', '$': 's', '7': 't', '+': 't', '2': 'z'
17
  };
18
 
19
+ // --- FUNGSI HELPER ---
20
+ function safeString(s) { return (s || '').toString(); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  function normalizeText(text) {
23
  const original = safeString(text);
24
+ let normalized = original.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
25
  normalized = normalized.toLowerCase();
26
+ // Apply Leet Map
27
+ let leetOut = '';
28
+ for (const ch of normalized) { leetOut += (LEET_MAP[ch] !== undefined) ? LEET_MAP[ch] : ch; }
29
+ normalized = leetOut;
30
+ // Keep alphanumeric only
31
  normalized = normalized.replace(/[^a-z0-9\s]/g, ' ').replace(/\s+/g, ' ').trim();
32
+ // Map words to numbers
33
+ const tokens = normalized.split(/\s+/);
34
+ normalized = tokens.map(t => NUMBER_WORDS[t] !== undefined ? NUMBER_WORDS[t] : t).join(' ');
35
  return normalized;
36
  }
37
 
 
38
  function levenshtein(a = '', b = '') {
39
  const alen = a.length, blen = b.length;
40
  if (alen === 0) return blen;
 
45
  for (let i = 1; i <= alen; i++) {
46
  for (let j = 1; j <= blen; j++) {
47
  const cost = a[i - 1] === b[j - 1] ? 0 : 1;
48
+ matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
 
 
 
 
49
  }
50
  }
51
  return matrix[alen][blen];
52
  }
53
 
54
  function similarity(a, b) {
55
+ a = normalizeText(a); b = normalizeText(b);
 
56
  if (a === b) return 1;
57
  const dist = levenshtein(a, b);
58
  const maxLen = Math.max(a.length, b.length);
59
  return maxLen === 0 ? 1 : 1 - (dist / maxLen);
60
  }
61
 
62
+ // --- LOGIKA UTAMA SOLVER ---
63
+ async function solve(data) {
64
  try {
65
+ console.log("🛠️ Ngamimitian prosés Antibot Solver...");
66
+
67
+ // 1. Convert Base64 ti PHP ka Buffer
68
+ const mainBuffer = Buffer.from(data.main, 'base64');
69
+ const botsBuffers = data.bots.map(b => Buffer.from(b, 'base64'));
70
+
71
+ // 2. OCR Gambar Instruksi Utama
72
+ const mainOCR = await extractTextFromImage(mainBuffer);
73
+ const mainText = mainOCR.response || "";
74
+ console.log("🎯 Instruksi ditéwak:", mainText);
75
+
76
+ // Pecah instruksi jadi daptar target (misal: "cat, dog" -> ["cat", "dog"])
77
+ const targets = mainText.toLowerCase()
78
+ .replace(/please click on the anti-bot links in the following order/gi, '')
79
+ .replace(/[,.+]/g, ' ')
80
+ .split(/\s+/)
81
+ .filter(t => t.length > 1);
82
+
83
+ // 3. OCR Kabéh Gambar Pilihan (Bots)
84
+ const botResults = [];
85
+ for (let i = 0; i < botsBuffers.length; i++) {
86
+ const res = await extractTextFromImage(botsBuffers[i]);
87
+ botResults.push({
88
+ index: (i + 1).toString(),
89
+ text: normalizeText(res.response || "")
90
+ });
91
+ console.log(`🖼️ Bot Pilihan ${i+1} OCR: "${res.response}"`);
92
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
+ // 4. Nyocogkeun (Matching Strategy)
95
+ let finalOrder = [];
96
+ let usedIndices = new Set();
97
+
98
+ for (const target of targets) {
99
+ let bestMatch = { index: null, score: -1 };
100
+
101
+ for (const bot of botResults) {
102
+ if (usedIndices.has(bot.index)) continue;
103
+
104
+ const score = similarity(bot.text, target);
105
+ if (score > bestMatch.score) {
106
+ bestMatch = { index: bot.index, score: score };
107
+ }
108
+ }
109
 
110
+ // Mun tingkat kamiripanana lumayan (di luhur 40%), asupkeun kana urutan
111
+ if (bestMatch.index && bestMatch.score > 0.4) {
112
+ finalOrder.push(bestMatch.index);
113
+ usedIndices.add(bestMatch.index);
 
 
 
114
  }
115
  }
 
116
 
117
+ // Fallback mun aya nu nyesa/gagal deteksi
118
+ if (finalOrder.length < botsBuffers.length) {
119
+ botResults.forEach(b => {
120
+ if(!usedIndices.has(b.index)) finalOrder.push(b.index);
121
+ });
122
+ }
123
 
124
+ console.log("✅ Solusi kapendak:", finalOrder.join(", "));
125
+ return {
126
+ status: "Success",
127
+ result: finalOrder // Ieu nu bakal dikirim balik ka PHP
128
+ };
 
 
 
129
 
130
+ } catch (error) {
131
+ console.error("❌ Error dina antibot.js:", error.message);
132
+ return { status: "Error", message: error.message, result: ["1", "2", "3"] };
133
+ }
 
 
 
 
 
 
 
 
134
  }
135
 
136
+ // --- PENTING: EXPORT SALAKU FUNGSI TUNGGAL ---
137
+ module.exports = solve;