1234ty commited on
Commit
f6deb97
·
verified ·
1 Parent(s): d767b05

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -326
app.py CHANGED
@@ -1,331 +1,154 @@
1
- import time
2
- import base64
3
- import hashlib
4
- import re
5
- from fastapi import FastAPI, Request, HTTPException
6
  from fastapi.responses import HTMLResponse
7
- from fastapi.middleware.cors import CORSMiddleware
8
- from sqlitedict import SqliteDict
9
 
10
  app = FastAPI()
11
 
12
- # --- เปิด CORS ให้ทำงานร่วมกับหน้าเว็บหลักได้อย่างเสถียร ---
13
- app.add_middleware(
14
- CORSMiddleware,
15
- allow_origins=["*"],
16
- allow_credentials=True,
17
- allow_methods=["*"],
18
- allow_headers=["*"],
19
- )
20
-
21
- # --- CONFIGURATION ---
22
- TARGET_WEBSITE_URL = "https://rov3.vercel.app"
23
- FIREWALL_DB = "firewall.sqlite"
24
- MAX_REQUESTS_PER_MINUTE = 20
25
- BLOCK_TIME_SECONDS = 3600
26
- SECRET_KEY = "TANZAi_SUPER_SECRET_CORE_PRO"
27
-
28
- # บัญชีดำสำหรับบอท, โปรแกรมแสกน และแฮกเกอร์ทูล
29
- BOT_BLACKLIST = [
30
- "sqlmap", "nmap", "dirbuster", "nikto", "hound", "scan", "headless",
31
- "python-requests", "go-http-client", "java/", "curl/", "wget", "zmeu",
32
- "masscan", "acunetix", "netsparker", "openvas", "censys", "shodan",
33
- "headlesschrome", "puppeteer", "selenium", "playwright", "scrapy",
34
- "postmanruntime", "insomnia", "cyberscan", "gobuster", "wuzz"
35
- ]
36
-
37
- # สแกนรูปแบบคำสั่งแฮกเกอร์ XSS, SQLi, RCE, Path Traversal, LFI/RFI
38
- EXPLOIT_PAYLOADS = [
39
- r"select\s+.*\s+from", r"insert\s+into", r"union\s+select", r"drop\s+table",
40
- r"<\s*script", r"javascript:", r"onerror\s*=", r"onload\s*=", r"\'\s*or\s*.*=.*",
41
- r"\.\.\/", r"etc\/passwd", r"boot\.ini", r"\{\s*\{\s*.*\}\s*\}", r"\$\{.*\}",
42
- r"exec\s*\(\s*", r"eval\s*\(\s*", r"union\s+all\s+select"
43
- ]
44
-
45
- def get_client_ip(request: Request):
46
- for header in ["cf-connecting-ip", "x-real-ip", "x-forwarded-for"]:
47
- value = request.headers.get(header)
48
- if value:
49
- return value.split(',')[0].strip()
50
- return request.client.host
51
-
52
- def generate_token(ip):
53
- # เปลี่ยนแปลงค่า Token ทุกๆ 10 นาที ผูกกับเวลาปัจจุบันของระบบ
54
- time_window = int(time.time() / 600)
55
- return hashlib.md5(f"{ip}{SECRET_KEY}{time_window}".encode()).hexdigest()
56
-
57
- def is_blocked(ip):
58
- with SqliteDict(FIREWALL_DB, autocommit=True) as db:
59
- if ip in db:
60
- blocked_until = db[ip].get("blocked_until", 0)
61
- if blocked_until > time.time(): return True
62
- else: del db[ip]
63
- return False
64
-
65
- def check_rate_limit_and_block(ip):
66
- with SqliteDict(FIREWALL_DB, autocommit=True) as db:
67
- data = db.get(ip, {"count": 0, "first_request": time.time()})
68
- data["count"] += 1
69
- db[ip] = data
70
- if time.time() - data["first_request"] > 60:
71
- del db[ip]
72
- return
73
- if data["count"] > MAX_REQUESTS_PER_MINUTE:
74
- data["blocked_until"] = time.time() + BLOCK_TIME_SECONDS
75
- db[ip] = data
76
-
77
- def force_block_ip(ip):
78
- with SqliteDict(FIREWALL_DB, autocommit=True) as db:
79
- db[ip] = {
80
- "count": 999,
81
- "first_request": time.time(),
82
- "blocked_until": time.time() + BLOCK_TIME_SECONDS
83
- }
84
-
85
- def cyber_security_waf(request: Request):
86
- user_agent = request.headers.get("user-agent", "").lower()
87
-
88
- # 1. ตรวจสอบลักษณะพื้นฐานและบัญชีดำของบอท
89
- if not user_agent or len(user_agent) < 12:
90
- return False
91
- for bot in BOT_BLACKLIST:
92
- if bot in user_agent:
93
- return False
94
-
95
- # ตรวจสอบว่ามี Headers ที่เบราว์เซอร์ปกติควรมีหรือไม่
96
- if not request.headers.get("accept") or not request.headers.get("accept-language"):
97
- return False
98
 
99
- # 2. Deep Input Inspection (สแกนการพยายามเจาะระบบผ่านทาง URL, Query, Path)
100
- query_params = str(request.query_params).lower()
101
- url_path = str(request.url.path).lower()
102
-
103
- for pattern in EXPLOIT_PAYLOADS:
104
- if re.search(pattern, query_params) or re.search(pattern, url_path):
105
- return False
106
-
107
- return True
108
-
109
- # หน้า UI ด่านตรวจความปลอดภัยระดับสูง
110
- def generate_challenge_html(ip):
111
- html = f"""
112
- <!DOCTYPE html>
113
- <html lang="th">
114
- <head>
115
- <meta charset="UTF-8">
116
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
117
- <title>TANZAi | กำลังทำการตรวจสอบความปลอดภัย</title>
118
- <style>
119
- body {{ font-family: -apple-system, system-ui, sans-serif; background: white; color: black; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; text-align: center; }}
120
- .container {{ max-width: 500px; width: 90%; }}
121
- h1 {{ font-size: 40px; font-weight: 500; margin-bottom: 0px; color: #10b981; }}
122
- h2 {{ font-size: 28px; font-weight: 500; margin-top: 10px; margin-bottom: 5px; }}
123
- p {{ font-size: 16px; color: #555; line-height: 1.4; }}
124
- #cf-widget-container {{ border: 1px solid #ddd; border-radius: 8px; background: #fafafa; padding: 15px; display: flex; align-items: center; justify-content: space-between; margin-top: 25px; }}
125
- .cf-left {{ display: flex; align-items: center; }}
126
- .cf-logo {{ width: 100px; filter: hue-rotate(140deg); }}
127
- .cf-ip-info {{ font-size: 12px; color: #666; margin-top: 20px; }}
128
- .captcha-box {{ display: flex; align-items: center; cursor: pointer; user-select: none; }}
129
- .captcha-checkbox {{ width: 24px; height: 24px; border: 2px solid #ccc; border-radius: 4px; margin-right: 12px; display: flex; align-items: center; justify-content: center; background: #ffffff; }}
130
- .captcha-checkbox.checked {{ background: #10b981; border-color: #10b981; }}
131
- .captcha-checkbox.checked::after {{ content: '✔'; color: white; font-size: 14px; font-weight: bold; }}
132
- .cf-spinner {{ border: 4px solid #eee; border-top: 4px solid #10b981; border-radius: 50%; width: 25px; height: 25px; animation: spin 1s linear infinite; margin-right: 15px; display: none; }}
133
- @keyframes spin {{ 0% {{ transform: rotate(0deg); }} 100% {{ transform: rotate(360deg); }} }}
134
- </style>
135
- </head>
136
- <body>
137
- <div class="container">
138
- <h1>TANZAi</h1>
139
- <h2>กำลังทำการตรวจสอบความปลอดภัย</h2>
140
- <p>กรุณาติ๊กเลือกช่องด้านล่างเพื่อยืนยันว่าคุณไม่ใช่สคริปต์อัตโนมัติ</p>
141
- <div id="cf-widget-container">
142
- <div class="cf-left">
143
- <div class="cf-spinner" id="main-spinner"></div>
144
- <div id="status-area">
145
- <div class="captcha-box" id="click-target" onclick="triggerChallenge()">
146
- <div class="captcha-checkbox" id="check-visual"></div>
147
- <span style="font-size: 15px; color: #333; font-weight: 500;">ฉันไม่ใช่โปรแกรมอัตโนมัติ</span>
148
- </div>
149
- </div>
150
- </div>
151
- <div class="cf-right">
152
- <img src="https://upload.wikimedia.org/wikipedia/commons/4/4b/Cloudflare_Logo.svg" alt="Cloudflare" class="cf-logo">
153
- </div>
154
- </div>
155
- <div class="cf-ip-info">IP ของคุณ: {ip}</div>
156
- </div>
157
-
158
- <script>
159
- let isProcessing = false;
160
- let humanVerified = false;
161
-
162
- // ดักจับการขยับเาส์หือทัชหน้าจอจริง ป้องกันบอทส่งคำสั่งคลิกตรงๆ
163
- window.addEventListener('mousemove', () => humanVerified = true);
164
- window.addEventListener('touchstart', () => humanVerified = true);
165
-
166
- async function triggerChallenge() {{
167
- if(isProcessing) return;
168
- isProcessing = true;
169
- document.getElementById('check-visual').classList.add('checked');
170
-
171
- setTimeout(async () => {{
172
- document.getElementById('click-target').style.display = 'none';
173
- document.getElementById('main-spinner').style.display = 'block';
174
- const statusArea = document.getElementById('status-area');
175
- statusArea.innerHTML = '<span style="font-size:14px;">กำลังตรวจสอบคุณลักษณะเบราว์เซอร์...</span>';
176
-
177
- // ด่านตรวจจับ Client-Side Security แบบเข้มข้นสูงสุด
178
- const isBot = navigator.webdriver ||
179
- !navigator.userAgent ||
180
- window.outerWidth === 0 ||
181
- window.outerHeight === 0 ||
182
- (window.chrome && !window.chrome.runtime) ||
183
- !humanVerified;
184
-
185
- if (isBot) {{
186
- statusArea.innerHTML = '<span style="color:#ef4444;font-size:14px;">ตรวจพบข้อผิดพลาดการเชื่อมต่ออัตโนมัติ!</span>';
187
- await fetch('/report_spam');
188
- return;
189
- }}
190
-
191
- try {{
192
- const res = await fetch('/get_token');
193
- if(res.status != 200) {{ throw new Error("Server Error"); }}
194
- const data = await res.json();
195
- if(data.token) {{
196
- statusArea.innerHTML = '<span style="color:#10b981;font-size:14px;">ตรวจสอบสำเร็จ! กำลังนำทาง...</span>';
197
- setTimeout(() => {{
198
- window.location.href = "{TARGET_WEBSITE_URL}?tz_token=" + data.token;
199
- }}, 500);
200
- }} else {{ location.reload(); }}
201
- }} catch(e) {{
202
- // แสดงผลเ่อหลังบ้าค้าง/หลับ
203
- document.body.innerHTML = '<div style="font-family:-apple-system,sans-serif;background:#0f172a;color:#f8fafc;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;text-align:center;"><div style="max-width:450px;width:90%;background:#1e1b4b;border:2px solid #ef4444;padding:40px;border-radius:16px;box-shadow:0 10px 25px rgba(239,68,68,0.2);"><div style="font-size:4rem;margin-bottom:20px;">⚠️</div><h1 style="color:#ef4444;font-size:1.8rem;margin:0 0 12px 0;">เกิดข้อผิดลาด</h1><p style="color:#cbd5e1;font-size:1.1rem;margin:0 0 10px 0;">ไม่สามาถเชื่อม่อกับเซิร์ฟเวอร์ได</p><p style="color:#64748b;font-size:0.9rem;margin-bottom:25px;">เซิร์ฟเวร์อาจจะกำังหลับหือมีัญหชั่วคาว</p><button onclick="window.location.reload()" style="background:#ef4444;color:white;border:none;padding:12px 24px;border-radius:6px;font-size:1rem;font-weight:bold;cursor:pointer;">ลองใหม่อีครั้</button></div></div>';
204
- }}
205
- }}, 400);
206
- }}
207
- </script>
208
- </body>
209
- </html>
210
- """
211
- return HTMLResponse(content=html)
212
-
213
- @app.get("/")
214
- async def gatekeeper(request: Request):
215
- ip = get_client_ip(request)
216
- if not cyber_security_waf(request):
217
- force_block_ip(ip)
218
- raise HTTPException(status_code=400, detail="Security Violation Detected")
219
- if is_blocked(ip):
220
- return HTMLResponse(content='<div style="font-family:-apple-system,sans-serif;background:#0f172a;color:#f8fafc;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;text-align:center;"><div style="max-width:450px;width:90%;background:#1e1b4b;border:2px solid #ef4444;padding:40px;border-radius:16px;"><h1 style="color:#ef4444;">เกิดข้อผิดพลาด</h1><p>ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้ (IP Blocked)</p></div></div>', status_code=403)
221
- check_rate_limit_and_block(ip)
222
- return generate_challenge_html(ip)
223
-
224
- @app.get("/verify")
225
- async def verify(token: str, request: Request):
226
- ip = get_client_ip(request)
227
- if is_blocked(ip):
228
- return {"status": "error", "valid": False, "banned": True}
229
- is_valid = (token == generate_token(ip))
230
- return {"status": "ok" if is_valid else "error", "valid": is_valid, "banned": False}
231
-
232
- @app.get("/get_token")
233
- async def get_token(request: Request):
234
- ip = get_client_ip(request)
235
- if is_blocked(ip):
236
- raise HTTPException(status_code=403, detail="Blocked")
237
- return {"token": generate_token(ip)}
238
-
239
- @app.get("/report_spam")
240
- async def report_spam(request: Request):
241
- ip = get_client_ip(request)
242
- force_block_ip(ip)
243
- return {"status": "banned"}
244
-
245
- # --- แทร็กสคริปต์ส่งไปฝังหน้าเว็บหลัก Vercel (ระบบความปลอดภัยขั้นสูง + ดักจับเซิร์ฟเวอร์หลับ + หน้าต่างยินยอมคุกกี้) ---
246
- @app.get("/js")
247
- async def get_js_script(request: Request):
248
- ip = get_client_ip(request)
249
- hf_url = f"{request.url.scheme}://{request.url.netloc}"
250
-
251
- error_layout = """<div style='font-family:-apple-system,sans-serif;background:#0f172a;color:#f8fafc;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;text-align:center;position:fixed;top:0;left:0;width:100vw;z-index:999999;'><div style='max-width:450px;width:90%;background:#1e1b4b;border:2px solid #ef4444;padding:40px;border-radius:16px;box-shadow:0 10px 25px rgba(239,68,68,0.2);'><div style='font-size:4rem;margin-bottom:20px;'>⚠️</div><h1 style='color:#ef4444;font-size:1.8rem;margin:0 0 12px 0;'>เกิดข้อผิดพลาด</h1><p style='color:#cbd5e1;font-size:1.1rem;margin:0 0 10px 0;'>ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้</p><p style='color:#64748b;font-size:0.9rem;margin-bottom:25px;'>เซิร์ฟเวอร์อาจจะกำลังหลับหรือมีปัญหาชั่วคราว</p><button onclick='window.location.reload()' style='background:#ef4444;color:white;border:none;padding:12px 24px;border-radius:6px;font-size:1rem;font-weight:bold;cursor:pointer;'>ลองใหม่อีกครั้ง</button></div></div>"""
252
-
253
- if is_blocked(ip):
254
- js_code = f"""
255
- (function() {{
256
- localStorage.clear();
257
- document.body.innerHTML="{error_layout}";
258
- }})();
259
- """
260
- return HTMLResponse(content=js_code, media_type="application/javascript")
261
-
262
- js_code = f"""
263
- (function() {{
264
- const h='{hf_url}',u=new URL(location),t=u.searchParams.get('tz_token')||localStorage.tz;let c=[];
265
-
266
- function showErrPage() {{
267
- localStorage.clear();
268
- document.body.innerHTML="{error_layout}";
269
- }}
270
-
271
- // ฟังก์ชันสร้างหน้าต่างยอมรับคุกกี้ (Cookie Consent Banner)
272
- function initCookieBanner() {{
273
- if (localStorage.cookieAccepted === 'true') return;
274
- const b = document.createElement('div');
275
- b.id = 'tz-cookie-banner';
276
- b.style = 'position:fixed;bottom:20px;left:50%;transform:translateX(-50%);width:90%;max-width:400px;background:#1e293b;color:#f8fafc;padding:16px;border-radius:12px;box-shadow:0 10px 25px rgba(0,0,0,0.3);z-index:99999;font-family:-apple-system,sans-serif;display:flex;flex-direction:column;gap:12px;border:1px solid #334155;';
277
- b.innerHTML = '<div style="font-size:14px;line-height:1.4;">🍪 เว็บไซต์นี้ใช้คุกกี้และระบบจัดเก็บข้อมูลในเบราว์เซอร์เพื่อความปลอดภัยและมอบประสบการณ์การใช้งานที่ดีที่สุดให้กับคุณ</div><button id="tz-accept-cookie" style="background:#10b981;color:white;border:none;padding:8px 16px;border-radius:6px;font-weight:bold;cursor:pointer;font-size:13px;transition:background 0.2s;">ยอมรับทั้งหมด</button>';
278
- document.body.appendChild(b);
279
- document.getElementById('tz-accept-cookie').onclick = function() {{
280
- localStorage.cookieAccepted = 'true';
281
- b.remove();
282
- }};
283
- }}
284
-
285
- // 1. ตรวจสอบความปลอดภัยระดับลึกบนเบราว์เซอร์เป้าหมาย
286
- const isSpamBot = navigator.webdriver ||
287
- window.outerWidth === 0 ||
288
- self !== top ||
289
- (window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized);
290
-
291
- if (isSpamBot) {{ showErrPage(); return; }}
292
-
293
- // 2. ดักจับการสแปมคลิกถี่เกินความจริง (Anti-Click Spam)
294
- window.addEventListener('click',()=>{{
295
- c=c.filter(x=>Date.now()-x<1000);c.push(Date.now());
296
- if(c.length>=5){'{'}
297
- fetch(h+'/report_spam').then(()=>{{ showErrPage(); }}).catch(()=>{{ showErrPage(); }});
298
- {'}'}
299
- }});
300
-
301
- if(t){{
302
- if(t.length !== 32) {{ showErrPage(); return; }}
303
- localStorage.tz=t;
304
- if(u.searchParams.has('tz_token')){{u.searchParams.delete('tz_token');history.replaceState({{}},'',u);}}
305
-
306
- const controller = new AbortController();
307
- const timeoutId = setTimeout(() => {{ controller.abort(); showErrPage(); }}, 5000);
308
-
309
- fetch(h+'/verify?token='+t, {{ signal: controller.signal }})
310
- .then(r=>{{
311
- clearTimeout(timeoutId);
312
- if(r.status !== 200) {{ showErrPage(); return; }}
313
- return r.json();
314
- }})
315
- .then(d=>{{
316
- if(!d || !d.valid || d.banned){{ showErrPage(); }}
317
- else {{ initCookieBanner(); }} // เมื่อ Token ผ่าน ให้รันระบบคุกกี้ขึ้นมา
318
- }})
319
- .catch(()=>{{ showErrPage(); }});
320
- }}else{{
321
- // ระบบตรวจสอบและปลุกเซิร์ฟเวอร์ (ดักจับ Error/หลับ)
322
- const controller = new AbortController();
323
- const timeoutId = setTimeout(() => {{ controller.abort(); showErrPage(); }}, 5000);
324
-
325
- fetch(h, {{ method: 'HEAD', mode: 'no-cors', signal: controller.signal }})
326
- .then(() => {{ window.location.href = h; }})
327
- .catch(() => {{ showErrPage(); }});
328
- }}
329
- })();
330
- """
331
- return HTMLResponse(content=js_code, media_type="application/javascript")
 
1
+ import os
2
+ import io
3
+ import json
4
+ from fastapi import FastAPI, File, UploadFile, Form
 
5
  from fastapi.responses import HTMLResponse
6
+ from PIL import Image
7
+ import imagehash
8
 
9
  app = FastAPI()
10
 
11
+ DATABASE_DIR = "scam_database"
12
+ VOTES_FILE = "votes.json"
13
+
14
+ # ฟังก์ชันโหลดข้อมูลโหวตจากไฟล์ JSON
15
+ def load_votes():
16
+ if os.path.exists(VOTES_FILE):
17
+ try:
18
+ with open(VOTES_FILE, "r", encoding="utf-8") as f:
19
+ return json.load(f)
20
+ except Exception:
21
+ return {}
22
+ return {}
23
+
24
+ # ฟังก์ชันบันทึกข้อมูลโหวตลงไฟล์ JSON
25
+ def save_votes(votes_data):
26
+ with open(VOTES_FILE, "w", encoding="utf-8") as f:
27
+ json.dump(votes_data, f, ensure_ascii=False, indent=2)
28
+
29
+ # ฟังก์ชันดึง Hash ของรูปทั้งหมดในฐานข้อมูล
30
+ def get_database_hashes():
31
+ hashes = {}
32
+ if not os.path.exists(DATABASE_DIR):
33
+ os.makedirs(DATABASE_DIR)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
+ for filename in os.listdir(DATABASE_DIR):
36
+ if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.webp')):
37
+ filepath = os.path.join(DATABASE_DIR, filename)
38
+ try:
39
+ img = Image.open(filepath)
40
+ h = str(imagehash.phash(img))
41
+ hashes[filename] = h
42
+ except Exception as e:
43
+ print(f"Error loading {filename}: {e}")
44
+ return hashes
45
+
46
+ @app.get("/", response_class=HTMLResponse)
47
+ def serve_index():
48
+ if os.path.exists("index.html"):
49
+ with open("index.html", "r", encoding="utf-8") as f:
50
+ return f.read()
51
+ return "<h1>index.html not found</h1>"
52
+
53
+ @app.post("/check")
54
+ async def check_image(file: UploadFile = File(...)):
55
+ try:
56
+ contents = await file.read()
57
+ uploaded_img = Image.open(io.BytesIO(contents))
58
+ uploaded_hash_obj = imagehash.phash(uploaded_img)
59
+ uploaded_hash_str = str(uploaded_hash_obj)
60
+
61
+ db_hashes = get_database_hashes()
62
+ votes_data = load_votes()
63
+
64
+ MATCH_THRESHOLD = 12
65
+ matched_hash_key = None
66
+ is_in_db = False
67
+
68
+ # เปรียบเทียบกับภาพในฐานข้อมูล
69
+ for filename, db_hash_str in db_hashes.items():
70
+ db_hash_obj = imagehash.hex_to_hash(db_hash_str)
71
+ distance = uploaded_hash_obj - db_hash_obj
72
+ if distance <= MATCH_THRESHOLD:
73
+ matched_hash_key = db_hash_str
74
+ is_in_db = True
75
+ break
76
+
77
+ # ถ้าไม่เจอในฐานข้อมูล ใช้ Hash ของภาพที่อัปโหลดเป็น Key
78
+ if not matched_hash_key:
79
+ matched_hash_key = uploaded_hash_str
80
+
81
+ # ดึงคะแนนโหวต
82
+ image_vote = votes_data.get(matched_hash_key, {"likes": 0, "dislikes": 0})
83
+ likes = image_vote.get("likes", 0)
84
+ dislikes = image_vote.get("dislikes", 0)
85
+
86
+ # เงื่อนไขตรวจสอบสถานะ
87
+ if likes >= 100:
88
+ is_scam = False
89
+ result_text = "ปลอดภัย"
90
+ detail_text = f"รูปภาพนี้ได้รับการยืนยันว่าปลอดภัยจากผู้ใช้งาน (กดไลก์ {likes} คน)"
91
+ elif is_in_db:
92
+ is_scam = True
93
+ result_text = "มิจแน่นอน100%"
94
+ detail_text = "พบรูปภาพตรงกับฐานข้อมูลรูปภาพโปรโมทหลอกลวง"
95
+ else:
96
+ is_scam = False
97
+ result_text = "ไม่สามารถตรวจสอบได้"
98
+ detail_text = "ยังไ่พบูปภาพในฐนข้อมูจฉาชีพ"
99
+
100
+ return {
101
+ "is_scam": is_scam,
102
+ "result": result_text,
103
+ "detail": detail_text,
104
+ "image_hash": matched_hash_key,
105
+ "likes": likes,
106
+ "dislikes": dislikes
107
+ }
108
+ except Exception as e:
109
+ return {"error": f"เกิดข้อผิดพลาดในการประมวลผล: {str(e)}"}
110
+
111
+ @app.post("/vote")
112
+ async def vote_image(image_hash: str = Form(...), vote_type: str = Form(...)):
113
+ try:
114
+ votes_data = load_votes()
115
+ if image_hash not in votes_data:
116
+ votes_data[image_hash] = {"likes": 0, "dislikes": 0}
117
+
118
+ if vote_type == "like":
119
+ votes_data[image_hash]["likes"] += 1
120
+ elif vote_type == "dislike":
121
+ votes_data[image_hash]["dislikes"] += 1
122
+
123
+ save_votes(votes_data)
124
+
125
+ likes = votes_data[image_hash]["likes"]
126
+ dislikes = votes_data[image_hash]["dislikes"]
127
+
128
+ # คำนวณสถานะใหม่หลังกดโหวต
129
+ db_hashes = get_database_hashes()
130
+ is_in_db = image_hash in db_hashes.values()
131
+
132
+ if likes >= 100:
133
+ is_scam = False
134
+ result_text = "ปลอดภัย"
135
+ detail_text = f"รูปภาพนี้ได้รับการยืนยันว่าปลอดภัยจากผู้ใช้งาน (กดไลก์ {likes} คน)"
136
+ elif is_in_db:
137
+ is_scam = True
138
+ result_text = "ิจแนอน100%"
139
+ detail_text = "พูปภาพรงกับฐานข้อมูลรพโ���โมทหลอกลว"
140
+ else:
141
+ is_scam = False
142
+ result_text = "ไม่สามารถตรวจสอบได้"
143
+ detail_text = "ยังไม่พบรูปภาพนี้ในฐานข้อมูลมิจฉาชีพ"
144
+
145
+ return {
146
+ "success": True,
147
+ "likes": likes,
148
+ "dislikes": dislikes,
149
+ "is_scam": is_scam,
150
+ "result": result_text,
151
+ "detail": detail_text
152
+ }
153
+ except Exception as e:
154
+ return {"error": f"เกิดข้อผิดพลาดในการโหวต: {str(e)}"}