Fourstore commited on
Commit
a114d8b
Β·
1 Parent(s): c510d40
Files changed (1) hide show
  1. app.py +105 -17
app.py CHANGED
@@ -59,36 +59,61 @@ def get_search_date():
59
 
60
  def login_account(account_id, username, password):
61
  try:
 
 
62
  session = httpx.Client(follow_redirects=True, timeout=30.0)
 
 
63
  r = session.get(LOGIN_URL, timeout=30)
 
 
 
 
 
 
64
  soup = BeautifulSoup(r.text, "html.parser")
65
  token = soup.find("input", {"name": "_token"})
66
  if not token:
 
 
67
  return False, "Token tidak ditemukan"
68
 
69
  csrf_token = token.get("value")
 
 
 
70
  r = session.post(LOGIN_URL, data={
71
  "_token": csrf_token,
72
  "email": username,
73
  "password": password
74
  }, timeout=30)
 
75
 
76
  if "dashboard" in r.text.lower() or "logout" in r.text.lower():
 
 
 
77
  accounts[account_id]["session"] = session
78
  accounts[account_id]["csrf"] = csrf_token
79
  accounts[account_id]["status"] = True
80
  accounts[account_id]["last_login"] = time.time()
81
  save_accounts(accounts)
 
82
  return True, "Login berhasil"
83
  else:
84
- return False, "Login gagal"
 
 
 
85
  except Exception as e:
 
86
  return False, str(e)
87
 
88
  def tg_send(account_id, msg):
89
  try:
90
  account = accounts.get(account_id)
91
  if not account or not account.get("bot_token") or not account.get("chat_id"):
 
92
  return False
93
 
94
  url = f"{TELEGRAM_PROXY_URL}?url=https://api.telegram.org/bot{account['bot_token']}/sendMessage"
@@ -97,9 +122,12 @@ def tg_send(account_id, msg):
97
  "text": msg,
98
  "parse_mode": "Markdown"
99
  }
100
- httpx.post(url, json=payload, timeout=30)
 
 
101
  return True
102
- except:
 
103
  return False
104
 
105
  def clean_country(rng):
@@ -140,16 +168,21 @@ def extract_otp(text):
140
  def get_ranges_with_count(account_id):
141
  account = accounts.get(account_id)
142
  if not account or not account.get("session") or not account.get("csrf"):
 
143
  return []
144
 
145
  try:
146
  date = get_search_date()
 
 
147
  r = account["session"].post(GET_RANGE_URL, data={
148
  "_token": account["csrf"],
149
  "from": date,
150
  "to": date
151
  }, timeout=15)
152
-
 
 
153
  soup = BeautifulSoup(r.text, "html.parser")
154
  ranges_data = []
155
 
@@ -165,9 +198,11 @@ def get_ranges_with_count(account_id):
165
  "name": rng,
166
  "count": count
167
  })
 
168
 
169
  return ranges_data
170
- except:
 
171
  return []
172
 
173
  def get_numbers_with_count(account_id, rng):
@@ -177,6 +212,8 @@ def get_numbers_with_count(account_id, rng):
177
 
178
  try:
179
  date = get_search_date()
 
 
180
  r = account["session"].post(GET_NUMBER_URL, data={
181
  "_token": account["csrf"],
182
  "start": date,
@@ -212,9 +249,11 @@ def get_numbers_with_count(account_id, rng):
212
  "number": num,
213
  "count": count
214
  })
 
215
 
216
  return numbers_data
217
- except:
 
218
  return []
219
 
220
  def get_sms_fast(account_id, rng, number):
@@ -229,8 +268,10 @@ def get_sms_fast(account_id, rng, number):
229
  if cache_key in account["sms_cache"]:
230
  timestamp, results = account["sms_cache"][cache_key]
231
  if time.time() - timestamp < 5:
 
232
  return results
233
 
 
234
  r = account["session"].post(GET_SMS_URL, data={
235
  "_token": account["csrf"],
236
  "start": date,
@@ -256,12 +297,14 @@ def get_sms_fast(account_id, rng, number):
256
  otp = extract_otp(sms)
257
  if otp:
258
  results.append((service, sms, otp))
 
259
  except:
260
  continue
261
 
262
  account["sms_cache"][cache_key] = (time.time(), results)
263
  return results
264
- except:
 
265
  return []
266
 
267
  def add_otp_log(account_id, country, number, service, otp, sms):
@@ -290,6 +333,7 @@ def add_otp_log(account_id, country, number, service, otp, sms):
290
 
291
  broadcast_sse(log_entry)
292
  save_accounts(accounts)
 
293
  return log_entry
294
 
295
  def broadcast_sse(data):
@@ -582,6 +626,7 @@ def generate_otp_rows(logs, search_query):
582
  @app.route('/add_account', methods=['POST'])
583
  def add_account_route():
584
  account_id = str(uuid.uuid4())[:8]
 
585
  accounts[account_id] = {
586
  "id": account_id,
587
  "username": request.form['username'],
@@ -600,33 +645,45 @@ def add_account_route():
600
  "created_at": time.time()
601
  }
602
  save_accounts(accounts)
 
603
  return redirect('/')
604
 
605
  @app.route('/delete_account/<account_id>')
606
  def delete_account_route(account_id):
607
  if account_id in accounts:
 
608
  del accounts[account_id]
609
  save_accounts(accounts)
 
610
  return redirect('/')
611
 
612
  @app.route('/login_account/<account_id>', methods=['POST'])
613
  def login_account_route(account_id):
614
  if account_id in accounts:
615
  acc = accounts[account_id]
 
616
  success, msg = login_account(account_id, acc['username'], acc['password'])
 
 
617
  if success:
618
- # Start thread untuk akun ini
619
  thread = Thread(target=run_account_scraper, args=(account_id,), daemon=True)
620
  thread.start()
 
 
 
 
621
  return redirect('/')
622
 
623
  @app.route('/logout_account/<account_id>', methods=['POST'])
624
  def logout_account_route(account_id):
625
  if account_id in accounts:
 
626
  accounts[account_id]["status"] = False
627
  accounts[account_id]["session"] = None
628
  accounts[account_id]["csrf"] = None
629
  save_accounts(accounts)
 
630
  return redirect('/')
631
 
632
  @app.route('/stream')
@@ -647,18 +704,26 @@ def run_account_scraper(account_id):
647
  if not account:
648
  return
649
 
650
- print(f"πŸš€ Starting scraper for {account['username']}")
 
 
651
 
652
  while account.get("status"):
 
653
  try:
 
 
 
 
654
  if time.time() - account.get("last_cleanup", 0) > 300:
655
  account["sms_cache"] = {}
656
  account["sms_counter"] = {}
657
  account["range_counter"] = {}
658
  account["last_cleanup"] = time.time()
659
- print(f"🧹 Cache cleared for {account['username']}")
660
 
661
  ranges_data = get_ranges_with_count(account_id)
 
662
 
663
  for range_item in ranges_data:
664
  if not account.get("status"):
@@ -668,11 +733,15 @@ def run_account_scraper(account_id):
668
  current_count = range_item["count"]
669
  prev_count = account["range_counter"].get(rng, 0)
670
 
 
 
671
  if current_count > prev_count:
672
  country = clean_country(rng)
 
673
  account["range_counter"][rng] = current_count
674
 
675
  numbers_data = get_numbers_with_count(account_id, rng)
 
676
 
677
  for number_item in numbers_data:
678
  if not account.get("status"):
@@ -683,11 +752,15 @@ def run_account_scraper(account_id):
683
  key = f"{rng}-{num}"
684
  prev_num_count = account["sms_counter"].get(key, 0)
685
 
 
 
686
  if num_count > prev_num_count:
 
687
  account["sms_counter"][key] = num_count
688
 
689
  all_sms = get_sms_fast(account_id, rng, num)
690
  new_sms = all_sms[prev_num_count:]
 
691
 
692
  for service, sms, otp in new_sms:
693
  if otp:
@@ -695,6 +768,8 @@ def run_account_scraper(account_id):
695
  if sms_id not in account["sent_cache"]:
696
  masked = mask_number(num)
697
  msg = f"πŸ”” *NEW OTP*\n🌍 {country}\nπŸ“ž `{masked}`\nπŸ’¬ {service}\nπŸ” `{otp}`\n\n{sms[:300]}"
 
 
698
  if tg_send(account_id, msg):
699
  if "sent_cache" not in account:
700
  account["sent_cache"] = []
@@ -702,42 +777,55 @@ def run_account_scraper(account_id):
702
  if len(account["sent_cache"]) > 1000:
703
  account["sent_cache"] = account["sent_cache"][-1000:]
704
  add_otp_log(account_id, country, masked, service, otp, sms)
 
705
 
706
  time.sleep(0.5)
 
 
707
 
 
708
  time.sleep(2)
709
 
710
  except Exception as e:
711
- print(f"❌ Error in scraper for {account['username']}: {e}")
712
  time.sleep(5)
 
 
713
 
714
  def run_server():
715
  app.run(host='0.0.0.0', port=7860, debug=False, threaded=True)
716
 
717
- # Start server thread
718
  Thread(target=run_server, daemon=True).start()
719
 
720
- # Start scraper untuk semua akun yang sudah login
721
  def main():
722
  print("\n" + "="*60)
723
  print(" πŸ”₯ OTP MULTI ACCOUNT - FOURSTORE")
724
  print(" ⚑ PORT: 7860")
725
  print(f" 🌐 DOMAIN: {CUSTOM_DOMAIN}")
726
  print(" πŸ“ Data tersimpan di accounts.json")
 
727
  print("="*60 + "\n")
728
 
729
- # Login semua akun yang punya status True
 
730
  for acc_id, acc in accounts.items():
 
 
 
731
  if acc.get("status"):
 
732
  success, msg = login_account(acc_id, acc['username'], acc['password'])
733
  if success:
734
  thread = Thread(target=run_account_scraper, args=(acc_id,), daemon=True)
735
  thread.start()
736
- print(f"βœ… {acc['username']} online")
737
  else:
738
- print(f"❌ {acc['username']} offline: {msg}")
 
 
 
 
739
 
740
- # Keep main thread alive
741
  while True:
742
  time.sleep(60)
743
 
 
59
 
60
  def login_account(account_id, username, password):
61
  try:
62
+ print(f"\nπŸ” LOGIN ACCOUNT: {username}")
63
+ print(f"πŸ“€ Membuat session baru...")
64
  session = httpx.Client(follow_redirects=True, timeout=30.0)
65
+
66
+ print(f"πŸ“₯ GET login page: {LOGIN_URL}")
67
  r = session.get(LOGIN_URL, timeout=30)
68
+ print(f"πŸ“Š Status code: {r.status_code}")
69
+
70
+ if r.status_code != 200:
71
+ print(f"❌ Gagal load login page")
72
+ return False, f"HTTP {r.status_code}"
73
+
74
  soup = BeautifulSoup(r.text, "html.parser")
75
  token = soup.find("input", {"name": "_token"})
76
  if not token:
77
+ print(f"❌ Token CSRF tidak ditemukan dalam HTML")
78
+ print(f"πŸ“„ Preview HTML: {r.text[:200]}")
79
  return False, "Token tidak ditemukan"
80
 
81
  csrf_token = token.get("value")
82
+ print(f"βœ… CSRF Token: {csrf_token[:20]}...")
83
+
84
+ print(f"πŸ“€ POST login data...")
85
  r = session.post(LOGIN_URL, data={
86
  "_token": csrf_token,
87
  "email": username,
88
  "password": password
89
  }, timeout=30)
90
+ print(f"πŸ“Š Response status: {r.status_code}")
91
 
92
  if "dashboard" in r.text.lower() or "logout" in r.text.lower():
93
+ print(f"βœ…βœ…βœ… LOGIN BERHASIL! βœ…βœ…βœ…")
94
+ print(f"πŸ“¦ Session aktif, menyimpan data...")
95
+
96
  accounts[account_id]["session"] = session
97
  accounts[account_id]["csrf"] = csrf_token
98
  accounts[account_id]["status"] = True
99
  accounts[account_id]["last_login"] = time.time()
100
  save_accounts(accounts)
101
+
102
  return True, "Login berhasil"
103
  else:
104
+ print(f"❌❌❌ LOGIN GAGAL! ❌❌❌")
105
+ print(f"πŸ“„ Response preview: {r.text[:300]}")
106
+ return False, "Login gagal - cek username/password"
107
+
108
  except Exception as e:
109
+ print(f"❌ EXCEPTION: {str(e)}")
110
  return False, str(e)
111
 
112
  def tg_send(account_id, msg):
113
  try:
114
  account = accounts.get(account_id)
115
  if not account or not account.get("bot_token") or not account.get("chat_id"):
116
+ print(f"⚠️ Telegram: No bot_token/chat_id for {account_id}")
117
  return False
118
 
119
  url = f"{TELEGRAM_PROXY_URL}?url=https://api.telegram.org/bot{account['bot_token']}/sendMessage"
 
122
  "text": msg,
123
  "parse_mode": "Markdown"
124
  }
125
+ print(f"πŸ“€ Send to Telegram: {msg[:50]}...")
126
+ r = httpx.post(url, json=payload, timeout=30)
127
+ print(f"πŸ“Š Telegram response: {r.status_code}")
128
  return True
129
+ except Exception as e:
130
+ print(f"❌ Telegram error: {e}")
131
  return False
132
 
133
  def clean_country(rng):
 
168
  def get_ranges_with_count(account_id):
169
  account = accounts.get(account_id)
170
  if not account or not account.get("session") or not account.get("csrf"):
171
+ print(f"⚠️ Account {account_id} invalid")
172
  return []
173
 
174
  try:
175
  date = get_search_date()
176
+ print(f"\nπŸ” AMBIL RANGE - {account['username']} - Tanggal: {date}")
177
+
178
  r = account["session"].post(GET_RANGE_URL, data={
179
  "_token": account["csrf"],
180
  "from": date,
181
  "to": date
182
  }, timeout=15)
183
+
184
+ print(f"πŸ“Š Status: {r.status_code}")
185
+
186
  soup = BeautifulSoup(r.text, "html.parser")
187
  ranges_data = []
188
 
 
198
  "name": rng,
199
  "count": count
200
  })
201
+ print(f" βœ… {rng} - {count} SMS")
202
 
203
  return ranges_data
204
+ except Exception as e:
205
+ print(f"❌ Error get_ranges: {e}")
206
  return []
207
 
208
  def get_numbers_with_count(account_id, rng):
 
212
 
213
  try:
214
  date = get_search_date()
215
+ print(f"\n πŸ“ž AMBIL NOMOR: {rng}")
216
+
217
  r = account["session"].post(GET_NUMBER_URL, data={
218
  "_token": account["csrf"],
219
  "start": date,
 
249
  "number": num,
250
  "count": count
251
  })
252
+ print(f" βœ… {mask_number(num)} - {count} SMS")
253
 
254
  return numbers_data
255
+ except Exception as e:
256
+ print(f" ❌ Error get_numbers: {e}")
257
  return []
258
 
259
  def get_sms_fast(account_id, rng, number):
 
268
  if cache_key in account["sms_cache"]:
269
  timestamp, results = account["sms_cache"][cache_key]
270
  if time.time() - timestamp < 5:
271
+ print(f" πŸ’Ύ Cache: {len(results)} SMS")
272
  return results
273
 
274
+ print(f" πŸ“¨ AMBIL SMS: {mask_number(number)}")
275
  r = account["session"].post(GET_SMS_URL, data={
276
  "_token": account["csrf"],
277
  "start": date,
 
297
  otp = extract_otp(sms)
298
  if otp:
299
  results.append((service, sms, otp))
300
+ print(f" βœ… OTP: {otp} - {service}")
301
  except:
302
  continue
303
 
304
  account["sms_cache"][cache_key] = (time.time(), results)
305
  return results
306
+ except Exception as e:
307
+ print(f" ❌ Error get_sms: {e}")
308
  return []
309
 
310
  def add_otp_log(account_id, country, number, service, otp, sms):
 
333
 
334
  broadcast_sse(log_entry)
335
  save_accounts(accounts)
336
+ print(f" πŸ“Š OTP LOGGED: {otp}")
337
  return log_entry
338
 
339
  def broadcast_sse(data):
 
626
  @app.route('/add_account', methods=['POST'])
627
  def add_account_route():
628
  account_id = str(uuid.uuid4())[:8]
629
+ print(f"\nβž• TAMBAH AKUN BARU: {request.form['username']}")
630
  accounts[account_id] = {
631
  "id": account_id,
632
  "username": request.form['username'],
 
645
  "created_at": time.time()
646
  }
647
  save_accounts(accounts)
648
+ print(f"βœ… Akun ditambahkan: {account_id}")
649
  return redirect('/')
650
 
651
  @app.route('/delete_account/<account_id>')
652
  def delete_account_route(account_id):
653
  if account_id in accounts:
654
+ print(f"\nπŸ—‘οΈ HAPUS AKUN: {accounts[account_id]['username']}")
655
  del accounts[account_id]
656
  save_accounts(accounts)
657
+ print(f"βœ… Akun dihapus")
658
  return redirect('/')
659
 
660
  @app.route('/login_account/<account_id>', methods=['POST'])
661
  def login_account_route(account_id):
662
  if account_id in accounts:
663
  acc = accounts[account_id]
664
+ print(f"\nπŸ” Mencoba login untuk: {acc['username']}")
665
  success, msg = login_account(account_id, acc['username'], acc['password'])
666
+ print(f"πŸ“ Result: {success} - {msg}")
667
+
668
  if success:
669
+ print(f"βœ… Login BERHASIL! Memulai thread scraper...")
670
  thread = Thread(target=run_account_scraper, args=(account_id,), daemon=True)
671
  thread.start()
672
+ print(f"βœ… Thread scraper dimulai untuk {acc['username']}")
673
+ else:
674
+ print(f"❌ Login GAGAL: {msg}")
675
+
676
  return redirect('/')
677
 
678
  @app.route('/logout_account/<account_id>', methods=['POST'])
679
  def logout_account_route(account_id):
680
  if account_id in accounts:
681
+ print(f"\nπŸ”Œ LOGOUT: {accounts[account_id]['username']}")
682
  accounts[account_id]["status"] = False
683
  accounts[account_id]["session"] = None
684
  accounts[account_id]["csrf"] = None
685
  save_accounts(accounts)
686
+ print(f"βœ… Logout berhasil")
687
  return redirect('/')
688
 
689
  @app.route('/stream')
 
704
  if not account:
705
  return
706
 
707
+ username = account['username']
708
+ print(f"\nπŸš€ STARTING SCRAPER FOR: {username}")
709
+ loop_count = 0
710
 
711
  while account.get("status"):
712
+ loop_count += 1
713
  try:
714
+ print(f"\n{'='*60}")
715
+ print(f"πŸ”„ [{username}] LOOP #{loop_count}")
716
+ print(f"{'='*60}")
717
+
718
  if time.time() - account.get("last_cleanup", 0) > 300:
719
  account["sms_cache"] = {}
720
  account["sms_counter"] = {}
721
  account["range_counter"] = {}
722
  account["last_cleanup"] = time.time()
723
+ print(f"🧹 [{username}] Cache cleared")
724
 
725
  ranges_data = get_ranges_with_count(account_id)
726
+ print(f"πŸ“Š [{username}] Total ranges: {len(ranges_data)}")
727
 
728
  for range_item in ranges_data:
729
  if not account.get("status"):
 
733
  current_count = range_item["count"]
734
  prev_count = account["range_counter"].get(rng, 0)
735
 
736
+ print(f"\n πŸ“Œ RANGE: {rng} | current: {current_count} | prev: {prev_count}")
737
+
738
  if current_count > prev_count:
739
  country = clean_country(rng)
740
+ print(f" πŸ”₯ RANGE BERUBAH: {country} | {prev_count} β†’ {current_count}")
741
  account["range_counter"][rng] = current_count
742
 
743
  numbers_data = get_numbers_with_count(account_id, rng)
744
+ print(f" πŸ“ž Total nomor: {len(numbers_data)}")
745
 
746
  for number_item in numbers_data:
747
  if not account.get("status"):
 
752
  key = f"{rng}-{num}"
753
  prev_num_count = account["sms_counter"].get(key, 0)
754
 
755
+ print(f"\n πŸ“± Nomor: {mask_number(num)} | count: {num_count} | prev: {prev_num_count}")
756
+
757
  if num_count > prev_num_count:
758
+ print(f" πŸ“¨ SMS baru: {prev_num_count} β†’ {num_count}")
759
  account["sms_counter"][key] = num_count
760
 
761
  all_sms = get_sms_fast(account_id, rng, num)
762
  new_sms = all_sms[prev_num_count:]
763
+ print(f" πŸ“¦ Total SMS baru: {len(new_sms)}")
764
 
765
  for service, sms, otp in new_sms:
766
  if otp:
 
768
  if sms_id not in account["sent_cache"]:
769
  masked = mask_number(num)
770
  msg = f"πŸ”” *NEW OTP*\n🌍 {country}\nπŸ“ž `{masked}`\nπŸ’¬ {service}\nπŸ” `{otp}`\n\n{sms[:300]}"
771
+ print(f" πŸ“€ Mengirim OTP {otp} ke Telegram...")
772
+
773
  if tg_send(account_id, msg):
774
  if "sent_cache" not in account:
775
  account["sent_cache"] = []
 
777
  if len(account["sent_cache"]) > 1000:
778
  account["sent_cache"] = account["sent_cache"][-1000:]
779
  add_otp_log(account_id, country, masked, service, otp, sms)
780
+ print(f" βœ… OTP {otp} TERKIRIM!")
781
 
782
  time.sleep(0.5)
783
+ else:
784
+ print(f" ⏭️ Range tidak berubah")
785
 
786
+ print(f"\n⏳ [{username}] Tidur 2 detik...")
787
  time.sleep(2)
788
 
789
  except Exception as e:
790
+ print(f"❌ ERROR in scraper for {username}: {str(e)}")
791
  time.sleep(5)
792
+
793
+ print(f"\nπŸ›‘ SCRAPER STOPPED FOR: {username}")
794
 
795
  def run_server():
796
  app.run(host='0.0.0.0', port=7860, debug=False, threaded=True)
797
 
 
798
  Thread(target=run_server, daemon=True).start()
799
 
 
800
  def main():
801
  print("\n" + "="*60)
802
  print(" πŸ”₯ OTP MULTI ACCOUNT - FOURSTORE")
803
  print(" ⚑ PORT: 7860")
804
  print(f" 🌐 DOMAIN: {CUSTOM_DOMAIN}")
805
  print(" πŸ“ Data tersimpan di accounts.json")
806
+ print(" πŸ“‹ LOGGING: FULL DETAIL")
807
  print("="*60 + "\n")
808
 
809
+ print(f"πŸ“Š Total akun terload: {len(accounts)}")
810
+
811
  for acc_id, acc in accounts.items():
812
+ print(f"\nπŸ“ Account: {acc['username']}")
813
+ print(f" Status: {'ONLINE' if acc.get('status') else 'OFFLINE'}")
814
+
815
  if acc.get("status"):
816
+ print(f" πŸ”„ Mencoba login ulang...")
817
  success, msg = login_account(acc_id, acc['username'], acc['password'])
818
  if success:
819
  thread = Thread(target=run_account_scraper, args=(acc_id,), daemon=True)
820
  thread.start()
821
+ print(f" βœ… {acc['username']} online")
822
  else:
823
+ print(f" ❌ {acc['username']} offline: {msg}")
824
+ acc["status"] = False
825
+ save_accounts(accounts)
826
+
827
+ print("\nβœ… BOT SIAP! Dashboard: http://localhost:7860")
828
 
 
829
  while True:
830
  time.sleep(60)
831