Update app.py
Browse files
app.py
CHANGED
|
@@ -10,6 +10,10 @@ import json
|
|
| 10 |
from queue import Queue
|
| 11 |
import os
|
| 12 |
import uuid
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
BASE = "http://159.69.3.189"
|
| 15 |
LOGIN_URL = f"{BASE}/login"
|
|
@@ -27,16 +31,22 @@ def load_accounts():
|
|
| 27 |
try:
|
| 28 |
with open(ACCOUNTS_FILE, 'r') as f:
|
| 29 |
return json.load(f)
|
| 30 |
-
except:
|
|
|
|
| 31 |
return {}
|
| 32 |
return {}
|
| 33 |
|
| 34 |
def save_accounts(accounts):
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
# Inisialisasi accounts
|
| 39 |
accounts = load_accounts()
|
|
|
|
| 40 |
|
| 41 |
# Tambahkan runtime data ke setiap account
|
| 42 |
for acc_id in accounts:
|
|
@@ -49,6 +59,7 @@ for acc_id in accounts:
|
|
| 49 |
accounts[acc_id]["sms_counter"] = {}
|
| 50 |
accounts[acc_id]["range_counter"] = {}
|
| 51 |
accounts[acc_id]["last_cleanup"] = time.time()
|
|
|
|
| 52 |
|
| 53 |
app = Flask('')
|
| 54 |
app.secret_key = "fourstore-multi-account-secret"
|
|
@@ -63,23 +74,43 @@ def get_search_date():
|
|
| 63 |
|
| 64 |
def login_account(account_id, username, password, bot_token, chat_id):
|
| 65 |
try:
|
| 66 |
-
print(f"\n
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
session = httpx.Client(follow_redirects=True, timeout=30.0)
|
| 68 |
|
|
|
|
| 69 |
r = session.get(LOGIN_URL, timeout=30)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
soup = BeautifulSoup(r.text, "html.parser")
|
| 71 |
token = soup.find("input", {"name": "_token"})
|
| 72 |
if not token:
|
|
|
|
|
|
|
| 73 |
return False, "Token tidak ditemukan"
|
| 74 |
|
| 75 |
csrf_token = token.get("value")
|
|
|
|
|
|
|
|
|
|
| 76 |
r = session.post(LOGIN_URL, data={
|
| 77 |
"_token": csrf_token,
|
| 78 |
"email": username,
|
| 79 |
"password": password
|
| 80 |
}, timeout=30)
|
| 81 |
-
|
|
|
|
| 82 |
if "dashboard" in r.text.lower() or "logout" in r.text.lower():
|
|
|
|
|
|
|
|
|
|
| 83 |
accounts[account_id]["session"] = session
|
| 84 |
accounts[account_id]["csrf"] = csrf_token
|
| 85 |
accounts[account_id]["status"] = True
|
|
@@ -89,10 +120,15 @@ def login_account(account_id, username, password, bot_token, chat_id):
|
|
| 89 |
accounts[account_id]["chat_id"] = chat_id
|
| 90 |
accounts[account_id]["last_login"] = time.time()
|
| 91 |
save_accounts(accounts)
|
|
|
|
| 92 |
return True, "Login berhasil"
|
| 93 |
else:
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
| 95 |
except Exception as e:
|
|
|
|
| 96 |
return False, str(e)
|
| 97 |
|
| 98 |
def tg_send(account_id, msg):
|
|
@@ -647,6 +683,8 @@ def add_account_route():
|
|
| 647 |
bot_token = request.form.get('bot_token', '')
|
| 648 |
chat_id = request.form.get('chat_id', '')
|
| 649 |
|
|
|
|
|
|
|
| 650 |
accounts[account_id] = {
|
| 651 |
"id": account_id,
|
| 652 |
"username": username,
|
|
@@ -665,19 +703,28 @@ def add_account_route():
|
|
| 665 |
"created_at": time.time()
|
| 666 |
}
|
| 667 |
save_accounts(accounts)
|
|
|
|
| 668 |
return redirect('/')
|
| 669 |
|
| 670 |
@app.route('/delete_account/<account_id>')
|
| 671 |
def delete_account_route(account_id):
|
| 672 |
if account_id in accounts:
|
|
|
|
|
|
|
| 673 |
del accounts[account_id]
|
| 674 |
save_accounts(accounts)
|
|
|
|
| 675 |
return redirect('/')
|
| 676 |
|
| 677 |
@app.route('/login_account/<account_id>', methods=['POST'])
|
| 678 |
def login_account_route(account_id):
|
|
|
|
|
|
|
| 679 |
if account_id in accounts:
|
| 680 |
acc = accounts[account_id]
|
|
|
|
|
|
|
|
|
|
| 681 |
success, msg = login_account(
|
| 682 |
account_id,
|
| 683 |
acc['username'],
|
|
@@ -685,19 +732,31 @@ def login_account_route(account_id):
|
|
| 685 |
acc.get('bot_token', ''),
|
| 686 |
acc.get('chat_id', '')
|
| 687 |
)
|
|
|
|
|
|
|
|
|
|
| 688 |
if success:
|
| 689 |
-
|
| 690 |
thread = Thread(target=run_account_scraper, args=(account_id,), daemon=True)
|
| 691 |
thread.start()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 692 |
return redirect('/')
|
| 693 |
|
| 694 |
@app.route('/logout_account/<account_id>', methods=['POST'])
|
| 695 |
def logout_account_route(account_id):
|
| 696 |
if account_id in accounts:
|
|
|
|
|
|
|
| 697 |
accounts[account_id]["status"] = False
|
| 698 |
accounts[account_id]["session"] = None
|
| 699 |
accounts[account_id]["csrf"] = None
|
| 700 |
save_accounts(accounts)
|
|
|
|
| 701 |
return redirect('/')
|
| 702 |
|
| 703 |
@app.route('/stream')
|
|
@@ -719,18 +778,25 @@ def run_account_scraper(account_id):
|
|
| 719 |
return
|
| 720 |
|
| 721 |
username = account['username']
|
| 722 |
-
print(f"π
|
|
|
|
| 723 |
|
| 724 |
while account.get("status"):
|
|
|
|
| 725 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 726 |
if time.time() - account.get("last_cleanup", 0) > 300:
|
| 727 |
account["sms_cache"] = {}
|
| 728 |
account["sms_counter"] = {}
|
| 729 |
account["range_counter"] = {}
|
| 730 |
account["last_cleanup"] = time.time()
|
| 731 |
-
print(f"π§Ή
|
| 732 |
|
| 733 |
ranges_data = get_ranges_with_count(account_id)
|
|
|
|
| 734 |
|
| 735 |
for range_item in ranges_data:
|
| 736 |
if not account.get("status"):
|
|
@@ -743,9 +809,11 @@ def run_account_scraper(account_id):
|
|
| 743 |
if current_count > prev_count:
|
| 744 |
country = clean_country(rng)
|
| 745 |
print(f"\nπ₯ RANGE BERUBAH: {country} ({username})")
|
|
|
|
| 746 |
account["range_counter"][rng] = current_count
|
| 747 |
|
| 748 |
numbers_data = get_numbers_with_count(account_id, rng)
|
|
|
|
| 749 |
|
| 750 |
for number_item in numbers_data:
|
| 751 |
if not account.get("status"):
|
|
@@ -757,6 +825,8 @@ def run_account_scraper(account_id):
|
|
| 757 |
prev_num_count = account["sms_counter"].get(key, 0)
|
| 758 |
|
| 759 |
if num_count > prev_num_count:
|
|
|
|
|
|
|
| 760 |
account["sms_counter"][key] = num_count
|
| 761 |
|
| 762 |
all_sms = get_sms_fast(account_id, rng, num)
|
|
@@ -768,22 +838,27 @@ def run_account_scraper(account_id):
|
|
| 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 |
if tg_send(account_id, msg):
|
| 772 |
account["sent_cache"].append(sms_id)
|
| 773 |
if len(account["sent_cache"]) > 1000:
|
| 774 |
account["sent_cache"] = account["sent_cache"][-1000:]
|
| 775 |
add_otp_log(account_id, country, masked, service, otp, sms)
|
| 776 |
-
print(f" β
OTP: {otp} - {service}")
|
| 777 |
|
| 778 |
time.sleep(0.5)
|
|
|
|
|
|
|
| 779 |
|
|
|
|
| 780 |
time.sleep(2)
|
| 781 |
|
| 782 |
except Exception as e:
|
| 783 |
-
print(f"β
|
| 784 |
time.sleep(5)
|
| 785 |
|
| 786 |
-
print(f"π
|
| 787 |
|
| 788 |
def run_server():
|
| 789 |
app.run(host='0.0.0.0', port=7860, debug=False, threaded=True)
|
|
@@ -797,6 +872,7 @@ def main():
|
|
| 797 |
print(" β‘ PORT: 7860")
|
| 798 |
print(f" π DOMAIN: {CUSTOM_DOMAIN}")
|
| 799 |
print(" π Data tersimpan di accounts.json")
|
|
|
|
| 800 |
print("="*60 + "\n")
|
| 801 |
|
| 802 |
# Login otomatis untuk akun yang sudah login sebelumnya
|
|
@@ -819,7 +895,8 @@ def main():
|
|
| 819 |
acc["status"] = False
|
| 820 |
save_accounts(accounts)
|
| 821 |
|
| 822 |
-
print("\nβ
BOT SIAP! Dashboard:
|
|
|
|
| 823 |
|
| 824 |
# Keep main thread alive
|
| 825 |
while True:
|
|
|
|
| 10 |
from queue import Queue
|
| 11 |
import os
|
| 12 |
import uuid
|
| 13 |
+
import sys
|
| 14 |
+
|
| 15 |
+
# Force print to flush immediately
|
| 16 |
+
print = lambda *args, **kwargs: __builtins__.print(*args, **kwargs, flush=True)
|
| 17 |
|
| 18 |
BASE = "http://159.69.3.189"
|
| 19 |
LOGIN_URL = f"{BASE}/login"
|
|
|
|
| 31 |
try:
|
| 32 |
with open(ACCOUNTS_FILE, 'r') as f:
|
| 33 |
return json.load(f)
|
| 34 |
+
except Exception as e:
|
| 35 |
+
print(f"β Error load accounts: {e}")
|
| 36 |
return {}
|
| 37 |
return {}
|
| 38 |
|
| 39 |
def save_accounts(accounts):
|
| 40 |
+
try:
|
| 41 |
+
with open(ACCOUNTS_FILE, 'w') as f:
|
| 42 |
+
json.dump(accounts, f, indent=2)
|
| 43 |
+
print(f"πΎ Accounts saved to {ACCOUNTS_FILE}")
|
| 44 |
+
except Exception as e:
|
| 45 |
+
print(f"β Error save accounts: {e}")
|
| 46 |
|
| 47 |
# Inisialisasi accounts
|
| 48 |
accounts = load_accounts()
|
| 49 |
+
print(f"\nπ Loaded {len(accounts)} accounts from file")
|
| 50 |
|
| 51 |
# Tambahkan runtime data ke setiap account
|
| 52 |
for acc_id in accounts:
|
|
|
|
| 59 |
accounts[acc_id]["sms_counter"] = {}
|
| 60 |
accounts[acc_id]["range_counter"] = {}
|
| 61 |
accounts[acc_id]["last_cleanup"] = time.time()
|
| 62 |
+
print(f" β
Account {acc_id}: {accounts[acc_id].get('username')}")
|
| 63 |
|
| 64 |
app = Flask('')
|
| 65 |
app.secret_key = "fourstore-multi-account-secret"
|
|
|
|
| 74 |
|
| 75 |
def login_account(account_id, username, password, bot_token, chat_id):
|
| 76 |
try:
|
| 77 |
+
print(f"\n{'='*60}")
|
| 78 |
+
print(f"π PROSES LOGIN UNTUK: {username} (ID: {account_id})")
|
| 79 |
+
print(f"{'='*60}")
|
| 80 |
+
|
| 81 |
+
print(f"π€ Membuat session baru...")
|
| 82 |
session = httpx.Client(follow_redirects=True, timeout=30.0)
|
| 83 |
|
| 84 |
+
print(f"π₯ GET login page: {LOGIN_URL}")
|
| 85 |
r = session.get(LOGIN_URL, timeout=30)
|
| 86 |
+
print(f"π Status code: {r.status_code}")
|
| 87 |
+
|
| 88 |
+
if r.status_code != 200:
|
| 89 |
+
print(f"β Gagal load login page")
|
| 90 |
+
return False, f"HTTP {r.status_code}"
|
| 91 |
+
|
| 92 |
soup = BeautifulSoup(r.text, "html.parser")
|
| 93 |
token = soup.find("input", {"name": "_token"})
|
| 94 |
if not token:
|
| 95 |
+
print(f"β Token CSRF tidak ditemukan dalam HTML")
|
| 96 |
+
print(f"π Preview HTML: {r.text[:200]}")
|
| 97 |
return False, "Token tidak ditemukan"
|
| 98 |
|
| 99 |
csrf_token = token.get("value")
|
| 100 |
+
print(f"β
CSRF Token: {csrf_token[:20]}...")
|
| 101 |
+
|
| 102 |
+
print(f"π€ POST login data...")
|
| 103 |
r = session.post(LOGIN_URL, data={
|
| 104 |
"_token": csrf_token,
|
| 105 |
"email": username,
|
| 106 |
"password": password
|
| 107 |
}, timeout=30)
|
| 108 |
+
print(f"π Response status: {r.status_code}")
|
| 109 |
+
|
| 110 |
if "dashboard" in r.text.lower() or "logout" in r.text.lower():
|
| 111 |
+
print(f"β
β
β
LOGIN BERHASIL! β
β
β
")
|
| 112 |
+
print(f"π¦ Menyimpan session untuk {username}")
|
| 113 |
+
|
| 114 |
accounts[account_id]["session"] = session
|
| 115 |
accounts[account_id]["csrf"] = csrf_token
|
| 116 |
accounts[account_id]["status"] = True
|
|
|
|
| 120 |
accounts[account_id]["chat_id"] = chat_id
|
| 121 |
accounts[account_id]["last_login"] = time.time()
|
| 122 |
save_accounts(accounts)
|
| 123 |
+
|
| 124 |
return True, "Login berhasil"
|
| 125 |
else:
|
| 126 |
+
print(f"βββ LOGIN GAGAL! βββ")
|
| 127 |
+
print(f"π Response preview: {r.text[:300]}")
|
| 128 |
+
return False, "Login gagal - cek username/password"
|
| 129 |
+
|
| 130 |
except Exception as e:
|
| 131 |
+
print(f"β EXCEPTION: {str(e)}")
|
| 132 |
return False, str(e)
|
| 133 |
|
| 134 |
def tg_send(account_id, msg):
|
|
|
|
| 683 |
bot_token = request.form.get('bot_token', '')
|
| 684 |
chat_id = request.form.get('chat_id', '')
|
| 685 |
|
| 686 |
+
print(f"\nβ TAMBAH AKUN BARU: {username} (ID: {account_id})")
|
| 687 |
+
|
| 688 |
accounts[account_id] = {
|
| 689 |
"id": account_id,
|
| 690 |
"username": username,
|
|
|
|
| 703 |
"created_at": time.time()
|
| 704 |
}
|
| 705 |
save_accounts(accounts)
|
| 706 |
+
print(f"β
Akun ditambahkan: {username}")
|
| 707 |
return redirect('/')
|
| 708 |
|
| 709 |
@app.route('/delete_account/<account_id>')
|
| 710 |
def delete_account_route(account_id):
|
| 711 |
if account_id in accounts:
|
| 712 |
+
username = accounts[account_id].get('username', 'Unknown')
|
| 713 |
+
print(f"\nποΈ HAPUS AKUN: {username} (ID: {account_id})")
|
| 714 |
del accounts[account_id]
|
| 715 |
save_accounts(accounts)
|
| 716 |
+
print(f"β
Akun dihapus")
|
| 717 |
return redirect('/')
|
| 718 |
|
| 719 |
@app.route('/login_account/<account_id>', methods=['POST'])
|
| 720 |
def login_account_route(account_id):
|
| 721 |
+
print(f"\nπππ LOGIN ACCOUNT DIPANGGIL: {account_id} πππ")
|
| 722 |
+
|
| 723 |
if account_id in accounts:
|
| 724 |
acc = accounts[account_id]
|
| 725 |
+
print(f"π Data akun: {acc.get('username')}")
|
| 726 |
+
print(f"π Mencoba login...")
|
| 727 |
+
|
| 728 |
success, msg = login_account(
|
| 729 |
account_id,
|
| 730 |
acc['username'],
|
|
|
|
| 732 |
acc.get('bot_token', ''),
|
| 733 |
acc.get('chat_id', '')
|
| 734 |
)
|
| 735 |
+
|
| 736 |
+
print(f"π Result: {success} - {msg}")
|
| 737 |
+
|
| 738 |
if success:
|
| 739 |
+
print(f"β
β
β
LOGIN BERHASIL! Memulai thread scraper...")
|
| 740 |
thread = Thread(target=run_account_scraper, args=(account_id,), daemon=True)
|
| 741 |
thread.start()
|
| 742 |
+
print(f"β
Thread scraper dimulai untuk {acc['username']}")
|
| 743 |
+
else:
|
| 744 |
+
print(f"βββ LOGIN GAGAL: {msg}")
|
| 745 |
+
else:
|
| 746 |
+
print(f"β Account ID {account_id} tidak ditemukan!")
|
| 747 |
+
|
| 748 |
return redirect('/')
|
| 749 |
|
| 750 |
@app.route('/logout_account/<account_id>', methods=['POST'])
|
| 751 |
def logout_account_route(account_id):
|
| 752 |
if account_id in accounts:
|
| 753 |
+
username = accounts[account_id].get('username', 'Unknown')
|
| 754 |
+
print(f"\nπ LOGOUT: {username} (ID: {account_id})")
|
| 755 |
accounts[account_id]["status"] = False
|
| 756 |
accounts[account_id]["session"] = None
|
| 757 |
accounts[account_id]["csrf"] = None
|
| 758 |
save_accounts(accounts)
|
| 759 |
+
print(f"β
Logout berhasil")
|
| 760 |
return redirect('/')
|
| 761 |
|
| 762 |
@app.route('/stream')
|
|
|
|
| 778 |
return
|
| 779 |
|
| 780 |
username = account['username']
|
| 781 |
+
print(f"\nπππ STARTING SCRAPER FOR: {username} πππ")
|
| 782 |
+
loop_count = 0
|
| 783 |
|
| 784 |
while account.get("status"):
|
| 785 |
+
loop_count += 1
|
| 786 |
try:
|
| 787 |
+
print(f"\n{'='*60}")
|
| 788 |
+
print(f"π [{username}] LOOP #{loop_count}")
|
| 789 |
+
print(f"{'='*60}")
|
| 790 |
+
|
| 791 |
if time.time() - account.get("last_cleanup", 0) > 300:
|
| 792 |
account["sms_cache"] = {}
|
| 793 |
account["sms_counter"] = {}
|
| 794 |
account["range_counter"] = {}
|
| 795 |
account["last_cleanup"] = time.time()
|
| 796 |
+
print(f"π§Ή [{username}] Cache cleared")
|
| 797 |
|
| 798 |
ranges_data = get_ranges_with_count(account_id)
|
| 799 |
+
print(f"π [{username}] Total ranges: {len(ranges_data)}")
|
| 800 |
|
| 801 |
for range_item in ranges_data:
|
| 802 |
if not account.get("status"):
|
|
|
|
| 809 |
if current_count > prev_count:
|
| 810 |
country = clean_country(rng)
|
| 811 |
print(f"\nπ₯ RANGE BERUBAH: {country} ({username})")
|
| 812 |
+
print(f" π {prev_count} β {current_count} SMS")
|
| 813 |
account["range_counter"][rng] = current_count
|
| 814 |
|
| 815 |
numbers_data = get_numbers_with_count(account_id, rng)
|
| 816 |
+
print(f" π Total nomor: {len(numbers_data)}")
|
| 817 |
|
| 818 |
for number_item in numbers_data:
|
| 819 |
if not account.get("status"):
|
|
|
|
| 825 |
prev_num_count = account["sms_counter"].get(key, 0)
|
| 826 |
|
| 827 |
if num_count > prev_num_count:
|
| 828 |
+
print(f" π± Nomor: {mask_number(num)}")
|
| 829 |
+
print(f" π¨ {prev_num_count} β {num_count} SMS")
|
| 830 |
account["sms_counter"][key] = num_count
|
| 831 |
|
| 832 |
all_sms = get_sms_fast(account_id, rng, num)
|
|
|
|
| 838 |
if sms_id not in account["sent_cache"]:
|
| 839 |
masked = mask_number(num)
|
| 840 |
msg = f"π *NEW OTP*\nπ {country}\nπ `{masked}`\nπ¬ {service}\nπ `{otp}`\n\n{sms[:300]}"
|
| 841 |
+
print(f" π€ Mengirim OTP {otp} ke Telegram...")
|
| 842 |
+
|
| 843 |
if tg_send(account_id, msg):
|
| 844 |
account["sent_cache"].append(sms_id)
|
| 845 |
if len(account["sent_cache"]) > 1000:
|
| 846 |
account["sent_cache"] = account["sent_cache"][-1000:]
|
| 847 |
add_otp_log(account_id, country, masked, service, otp, sms)
|
| 848 |
+
print(f" β
OTP: {otp} - {service} TERKIRIM!")
|
| 849 |
|
| 850 |
time.sleep(0.5)
|
| 851 |
+
else:
|
| 852 |
+
print(f" βοΈ Range {clean_country(rng)} tidak berubah (count: {current_count})")
|
| 853 |
|
| 854 |
+
print(f"\nβ³ [{username}] Tidur 2 detik...")
|
| 855 |
time.sleep(2)
|
| 856 |
|
| 857 |
except Exception as e:
|
| 858 |
+
print(f"β ERROR in scraper for {username}: {str(e)}")
|
| 859 |
time.sleep(5)
|
| 860 |
|
| 861 |
+
print(f"\nπππ SCRAPER STOPPED FOR: {username} πππ")
|
| 862 |
|
| 863 |
def run_server():
|
| 864 |
app.run(host='0.0.0.0', port=7860, debug=False, threaded=True)
|
|
|
|
| 872 |
print(" β‘ PORT: 7860")
|
| 873 |
print(f" π DOMAIN: {CUSTOM_DOMAIN}")
|
| 874 |
print(" π Data tersimpan di accounts.json")
|
| 875 |
+
print(" π LOGGING: FULL DETAIL (FLUSH ENABLED)")
|
| 876 |
print("="*60 + "\n")
|
| 877 |
|
| 878 |
# Login otomatis untuk akun yang sudah login sebelumnya
|
|
|
|
| 895 |
acc["status"] = False
|
| 896 |
save_accounts(accounts)
|
| 897 |
|
| 898 |
+
print("\nβ
BOT SIAP! Dashboard: https://fourstore-otp.hf.space")
|
| 899 |
+
print("π Log akan muncul di terminal ini setiap ada aktivitas\n")
|
| 900 |
|
| 901 |
# Keep main thread alive
|
| 902 |
while True:
|