Update app.py
Browse files
app.py
CHANGED
|
@@ -19,14 +19,18 @@ MONGO_URI = os.environ.get("MONGGODB_URI")
|
|
| 19 |
DB_NAME = "otp_bot"
|
| 20 |
COLLECTION_NAME = "accounts"
|
| 21 |
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
mongo_client = None
|
| 31 |
|
| 32 |
print = lambda *args, **kwargs: __builtins__.print(*args, **kwargs, flush=True)
|
|
@@ -39,6 +43,7 @@ GET_SMS_URL = f"{BASE}/portal/sms/received/getsms/number/sms"
|
|
| 39 |
|
| 40 |
TELEGRAM_PROXY_URL = "https://danihitambangetjir.termai.cc/api/proxy"
|
| 41 |
CUSTOM_DOMAIN = "https://fourstore-otp.hf.space"
|
|
|
|
| 42 |
|
| 43 |
def mask_email(email):
|
| 44 |
if not email or '@' not in email:
|
|
@@ -96,13 +101,57 @@ def save_accounts_to_mongodb(accounts_dict):
|
|
| 96 |
except Exception as e:
|
| 97 |
print(f"❌ Error save to MongoDB: {e}")
|
| 98 |
|
| 99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
app = Flask('')
|
| 102 |
app.secret_key = "fourstore-multi-account-secret"
|
| 103 |
sse_clients = []
|
| 104 |
|
| 105 |
-
# Decorator untuk cek owner via session
|
| 106 |
def owner_required(f):
|
| 107 |
@wraps(f)
|
| 108 |
def decorated_function(*args, **kwargs):
|
|
@@ -123,7 +172,7 @@ def login_account(account_id, username, password, bot_token, chat_id, owner_id):
|
|
| 123 |
try:
|
| 124 |
masked = mask_email(username)
|
| 125 |
print(f"\n{'='*60}")
|
| 126 |
-
print(f"🔐 PROSES LOGIN UNTUK: {masked} (ID: {account_id})")
|
| 127 |
print(f"{'='*60}")
|
| 128 |
|
| 129 |
session = httpx.Client(follow_redirects=True, timeout=30.0)
|
|
@@ -154,7 +203,11 @@ def login_account(account_id, username, password, bot_token, chat_id, owner_id):
|
|
| 154 |
accounts[account_id]["chat_id"] = chat_id
|
| 155 |
accounts[account_id]["owner_id"] = owner_id
|
| 156 |
accounts[account_id]["last_login"] = time.time()
|
| 157 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
return True, "Login berhasil"
|
| 159 |
else:
|
| 160 |
return False, "Login gagal"
|
|
@@ -442,7 +495,6 @@ def logout_owner():
|
|
| 442 |
def home():
|
| 443 |
owner_id = flask_session.get('owner_id')
|
| 444 |
|
| 445 |
-
# Filter accounts berdasarkan owner_id
|
| 446 |
user_accounts = {}
|
| 447 |
for acc_id, acc in accounts.items():
|
| 448 |
if acc.get("owner_id") == owner_id:
|
|
@@ -503,7 +555,6 @@ def home():
|
|
| 503 |
body {{ font-family: 'Inter', sans-serif; background: #0a0c10; color: #e4e6eb; padding: 24px; }}
|
| 504 |
.container {{ max-width: 1600px; margin: 0 auto; }}
|
| 505 |
|
| 506 |
-
/* Navbar */
|
| 507 |
.navbar {{ background: #1a1f2c; border-radius: 16px; padding: 16px 24px; margin-bottom: 24px; display: flex; justify-content: space-between; align-items: center; border: 1px solid #2d3540; }}
|
| 508 |
.nav-brand {{ font-size: 20px; font-weight: 700; color: #00f2fe; }}
|
| 509 |
.nav-menu {{ display: flex; gap: 20px; align-items: center; }}
|
|
@@ -567,7 +618,6 @@ def home():
|
|
| 567 |
</head>
|
| 568 |
<body>
|
| 569 |
<div class="container">
|
| 570 |
-
<!-- Navbar -->
|
| 571 |
<div class="navbar">
|
| 572 |
<div class="nav-brand">OTP MULTI ACCOUNT</div>
|
| 573 |
<div class="nav-menu">
|
|
@@ -595,7 +645,7 @@ def home():
|
|
| 595 |
</div>
|
| 596 |
|
| 597 |
<div class="add-account-form">
|
| 598 |
-
<h3 style="margin-bottom: 15px;">➕ Tambah Akun Baru
|
| 599 |
<form action="/add_account" method="POST" class="form-grid">
|
| 600 |
<input type="text" name="username" placeholder="Username/Email" class="form-input" required>
|
| 601 |
<input type="password" name="password" placeholder="Password" class="form-input" required>
|
|
@@ -606,7 +656,6 @@ def home():
|
|
| 606 |
</form>
|
| 607 |
</div>
|
| 608 |
|
| 609 |
-
<!-- Preview Akun (3 teratas) -->
|
| 610 |
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
| 611 |
<h3>📋 Akun Terbaru</h3>
|
| 612 |
<a href="/accounts" class="btn btn-small">Lihat Semua Akun →</a>
|
|
@@ -742,7 +791,6 @@ def generate_preview_accounts(accounts_list):
|
|
| 742 |
def accounts_page():
|
| 743 |
owner_id = flask_session.get('owner_id')
|
| 744 |
|
| 745 |
-
# Filter accounts berdasarkan owner_id
|
| 746 |
user_accounts = {}
|
| 747 |
for acc_id, acc in accounts.items():
|
| 748 |
if acc.get("owner_id") == owner_id:
|
|
@@ -954,10 +1002,13 @@ def add_account_route():
|
|
| 954 |
"last_cleanup": time.time(),
|
| 955 |
"created_at": time.time()
|
| 956 |
}
|
| 957 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 958 |
print(f"✅ Akun ditambahkan: {masked}")
|
| 959 |
|
| 960 |
-
# OTOMATIS LOGIN SETELAH TAMBAH AKUN
|
| 961 |
print(f"🔄 Mencoba login otomatis untuk {masked}...")
|
| 962 |
success, msg = login_account(
|
| 963 |
account_id,
|
|
@@ -984,7 +1035,6 @@ def delete_account_route(account_id):
|
|
| 984 |
owner_id = flask_session.get('owner_id')
|
| 985 |
|
| 986 |
if account_id in accounts:
|
| 987 |
-
# Cek apakah akun ini milik owner yang sedang login
|
| 988 |
if accounts[account_id].get("owner_id") != owner_id:
|
| 989 |
return "Unauthorized", 403
|
| 990 |
|
|
@@ -992,8 +1042,11 @@ def delete_account_route(account_id):
|
|
| 992 |
masked = mask_email(username)
|
| 993 |
print(f"\n🗑️ HAPUS AKUN: {masked} (ID: {account_id})")
|
| 994 |
del accounts[account_id]
|
|
|
|
| 995 |
if mongo_client:
|
| 996 |
accounts_collection.delete_one({"_id": account_id})
|
|
|
|
|
|
|
| 997 |
print(f"✅ Akun dihapus")
|
| 998 |
|
| 999 |
return redirect(request.referrer or '/')
|
|
@@ -1005,7 +1058,6 @@ def login_account_route(account_id):
|
|
| 1005 |
print(f"\n🔔🔔🔔 LOGIN ACCOUNT DIPANGGIL: {account_id} 🔔🔔🔔")
|
| 1006 |
|
| 1007 |
if account_id in accounts:
|
| 1008 |
-
# Cek apakah akun ini milik owner yang sedang login
|
| 1009 |
if accounts[account_id].get("owner_id") != owner_id:
|
| 1010 |
return "Unauthorized", 403
|
| 1011 |
|
|
@@ -1043,7 +1095,6 @@ def logout_account_route(account_id):
|
|
| 1043 |
owner_id = flask_session.get('owner_id')
|
| 1044 |
|
| 1045 |
if account_id in accounts:
|
| 1046 |
-
# Cek apakah akun ini milik owner yang sedang login
|
| 1047 |
if accounts[account_id].get("owner_id") != owner_id:
|
| 1048 |
return "Unauthorized", 403
|
| 1049 |
|
|
@@ -1053,7 +1104,11 @@ def logout_account_route(account_id):
|
|
| 1053 |
accounts[account_id]["status"] = False
|
| 1054 |
accounts[account_id]["session"] = None
|
| 1055 |
accounts[account_id]["csrf"] = None
|
| 1056 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1057 |
print(f"✅ Logout berhasil")
|
| 1058 |
|
| 1059 |
return redirect(request.referrer or '/')
|
|
@@ -1170,14 +1225,16 @@ def main():
|
|
| 1170 |
print(" 🔥 OTP MULTI ACCOUNT - FOURSTORE")
|
| 1171 |
print(" ⚡ PORT: 7860")
|
| 1172 |
print(f" 🌐 DOMAIN: {CUSTOM_DOMAIN}")
|
| 1173 |
-
|
|
|
|
|
|
|
|
|
|
| 1174 |
print(" 📋 LOGGING: FULL DETAIL")
|
| 1175 |
print(" 🔒 EMAIL SENSOR: AKTIF")
|
| 1176 |
print(" 🤖 AUTO LOGIN: AKTIF (setelah tambah akun)")
|
| 1177 |
-
print(" 👑 OWNER SYSTEM: AKTIF")
|
| 1178 |
print("="*60 + "\n")
|
| 1179 |
|
| 1180 |
-
# Auto login untuk akun yang sudah login sebelumnya
|
| 1181 |
for acc_id, acc in accounts.items():
|
| 1182 |
if acc.get("status"):
|
| 1183 |
masked = mask_email(acc['username'])
|
|
@@ -1197,7 +1254,10 @@ def main():
|
|
| 1197 |
else:
|
| 1198 |
print(f"❌ {masked} offline: {msg}")
|
| 1199 |
acc["status"] = False
|
| 1200 |
-
|
|
|
|
|
|
|
|
|
|
| 1201 |
|
| 1202 |
print("\n✅ BOT SIAP! Dashboard: https://fourstore-otp.hf.space")
|
| 1203 |
print("🔐 Login dengan Owner ID untuk mengakses")
|
|
@@ -1210,4 +1270,7 @@ if __name__ == "__main__":
|
|
| 1210 |
main()
|
| 1211 |
except KeyboardInterrupt:
|
| 1212 |
print("\n🛑 BOT STOPPED")
|
| 1213 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
DB_NAME = "otp_bot"
|
| 20 |
COLLECTION_NAME = "accounts"
|
| 21 |
|
| 22 |
+
if MONGO_URI:
|
| 23 |
+
try:
|
| 24 |
+
mongo_client = MongoClient(MONGO_URI)
|
| 25 |
+
db = mongo_client[DB_NAME]
|
| 26 |
+
accounts_collection = db[COLLECTION_NAME]
|
| 27 |
+
mongo_client.admin.command('ping')
|
| 28 |
+
print("✅ MongoDB Connected!")
|
| 29 |
+
except ConnectionFailure as e:
|
| 30 |
+
print(f"❌ MongoDB Connection Failed: {e}")
|
| 31 |
+
mongo_client = None
|
| 32 |
+
else:
|
| 33 |
+
print("⚠️ MONGO_URI tidak di set, menggunakan penyimpanan lokal")
|
| 34 |
mongo_client = None
|
| 35 |
|
| 36 |
print = lambda *args, **kwargs: __builtins__.print(*args, **kwargs, flush=True)
|
|
|
|
| 43 |
|
| 44 |
TELEGRAM_PROXY_URL = "https://danihitambangetjir.termai.cc/api/proxy"
|
| 45 |
CUSTOM_DOMAIN = "https://fourstore-otp.hf.space"
|
| 46 |
+
ACCOUNTS_FILE = "accounts.json"
|
| 47 |
|
| 48 |
def mask_email(email):
|
| 49 |
if not email or '@' not in email:
|
|
|
|
| 101 |
except Exception as e:
|
| 102 |
print(f"❌ Error save to MongoDB: {e}")
|
| 103 |
|
| 104 |
+
def load_accounts_from_file():
|
| 105 |
+
if os.path.exists(ACCOUNTS_FILE):
|
| 106 |
+
try:
|
| 107 |
+
with open(ACCOUNTS_FILE, 'r') as f:
|
| 108 |
+
data = json.load(f)
|
| 109 |
+
for acc_id in data:
|
| 110 |
+
data[acc_id]["session"] = None
|
| 111 |
+
data[acc_id]["csrf"] = None
|
| 112 |
+
data[acc_id]["status"] = False
|
| 113 |
+
data[acc_id]["otp_logs"] = []
|
| 114 |
+
data[acc_id]["sent_cache"] = []
|
| 115 |
+
data[acc_id]["sms_cache"] = {}
|
| 116 |
+
data[acc_id]["sms_counter"] = {}
|
| 117 |
+
data[acc_id]["range_counter"] = {}
|
| 118 |
+
data[acc_id]["last_cleanup"] = time.time()
|
| 119 |
+
print(f"📊 Loaded {len(data)} accounts from file")
|
| 120 |
+
return data
|
| 121 |
+
except:
|
| 122 |
+
return {}
|
| 123 |
+
return {}
|
| 124 |
+
|
| 125 |
+
def save_accounts_to_file(accounts_dict):
|
| 126 |
+
try:
|
| 127 |
+
accounts_to_save = {}
|
| 128 |
+
for acc_id, acc in accounts_dict.items():
|
| 129 |
+
acc_copy = acc.copy()
|
| 130 |
+
acc_copy.pop("session", None)
|
| 131 |
+
acc_copy.pop("csrf", None)
|
| 132 |
+
acc_copy.pop("otp_logs", None)
|
| 133 |
+
acc_copy.pop("sent_cache", None)
|
| 134 |
+
acc_copy.pop("sms_cache", None)
|
| 135 |
+
acc_copy.pop("sms_counter", None)
|
| 136 |
+
acc_copy.pop("range_counter", None)
|
| 137 |
+
acc_copy.pop("last_cleanup", None)
|
| 138 |
+
accounts_to_save[acc_id] = acc_copy
|
| 139 |
+
|
| 140 |
+
with open(ACCOUNTS_FILE, 'w') as f:
|
| 141 |
+
json.dump(accounts_to_save, f, indent=2)
|
| 142 |
+
print(f"💾 Accounts saved to file")
|
| 143 |
+
except Exception as e:
|
| 144 |
+
print(f"❌ Error save to file: {e}")
|
| 145 |
+
|
| 146 |
+
if mongo_client:
|
| 147 |
+
accounts = load_accounts_from_mongodb()
|
| 148 |
+
else:
|
| 149 |
+
accounts = load_accounts_from_file()
|
| 150 |
|
| 151 |
app = Flask('')
|
| 152 |
app.secret_key = "fourstore-multi-account-secret"
|
| 153 |
sse_clients = []
|
| 154 |
|
|
|
|
| 155 |
def owner_required(f):
|
| 156 |
@wraps(f)
|
| 157 |
def decorated_function(*args, **kwargs):
|
|
|
|
| 172 |
try:
|
| 173 |
masked = mask_email(username)
|
| 174 |
print(f"\n{'='*60}")
|
| 175 |
+
print(f"🔐 PROSES LOGIN UNTUK: {masked} (ID: {account_id}) (Owner: {owner_id})")
|
| 176 |
print(f"{'='*60}")
|
| 177 |
|
| 178 |
session = httpx.Client(follow_redirects=True, timeout=30.0)
|
|
|
|
| 203 |
accounts[account_id]["chat_id"] = chat_id
|
| 204 |
accounts[account_id]["owner_id"] = owner_id
|
| 205 |
accounts[account_id]["last_login"] = time.time()
|
| 206 |
+
|
| 207 |
+
if mongo_client:
|
| 208 |
+
save_accounts_to_mongodb(accounts)
|
| 209 |
+
else:
|
| 210 |
+
save_accounts_to_file(accounts)
|
| 211 |
return True, "Login berhasil"
|
| 212 |
else:
|
| 213 |
return False, "Login gagal"
|
|
|
|
| 495 |
def home():
|
| 496 |
owner_id = flask_session.get('owner_id')
|
| 497 |
|
|
|
|
| 498 |
user_accounts = {}
|
| 499 |
for acc_id, acc in accounts.items():
|
| 500 |
if acc.get("owner_id") == owner_id:
|
|
|
|
| 555 |
body {{ font-family: 'Inter', sans-serif; background: #0a0c10; color: #e4e6eb; padding: 24px; }}
|
| 556 |
.container {{ max-width: 1600px; margin: 0 auto; }}
|
| 557 |
|
|
|
|
| 558 |
.navbar {{ background: #1a1f2c; border-radius: 16px; padding: 16px 24px; margin-bottom: 24px; display: flex; justify-content: space-between; align-items: center; border: 1px solid #2d3540; }}
|
| 559 |
.nav-brand {{ font-size: 20px; font-weight: 700; color: #00f2fe; }}
|
| 560 |
.nav-menu {{ display: flex; gap: 20px; align-items: center; }}
|
|
|
|
| 618 |
</head>
|
| 619 |
<body>
|
| 620 |
<div class="container">
|
|
|
|
| 621 |
<div class="navbar">
|
| 622 |
<div class="nav-brand">OTP MULTI ACCOUNT</div>
|
| 623 |
<div class="nav-menu">
|
|
|
|
| 645 |
</div>
|
| 646 |
|
| 647 |
<div class="add-account-form">
|
| 648 |
+
<h3 style="margin-bottom: 15px;">➕ Tambah Akun Baru</h3>
|
| 649 |
<form action="/add_account" method="POST" class="form-grid">
|
| 650 |
<input type="text" name="username" placeholder="Username/Email" class="form-input" required>
|
| 651 |
<input type="password" name="password" placeholder="Password" class="form-input" required>
|
|
|
|
| 656 |
</form>
|
| 657 |
</div>
|
| 658 |
|
|
|
|
| 659 |
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
| 660 |
<h3>📋 Akun Terbaru</h3>
|
| 661 |
<a href="/accounts" class="btn btn-small">Lihat Semua Akun →</a>
|
|
|
|
| 791 |
def accounts_page():
|
| 792 |
owner_id = flask_session.get('owner_id')
|
| 793 |
|
|
|
|
| 794 |
user_accounts = {}
|
| 795 |
for acc_id, acc in accounts.items():
|
| 796 |
if acc.get("owner_id") == owner_id:
|
|
|
|
| 1002 |
"last_cleanup": time.time(),
|
| 1003 |
"created_at": time.time()
|
| 1004 |
}
|
| 1005 |
+
|
| 1006 |
+
if mongo_client:
|
| 1007 |
+
save_accounts_to_mongodb(accounts)
|
| 1008 |
+
else:
|
| 1009 |
+
save_accounts_to_file(accounts)
|
| 1010 |
print(f"✅ Akun ditambahkan: {masked}")
|
| 1011 |
|
|
|
|
| 1012 |
print(f"🔄 Mencoba login otomatis untuk {masked}...")
|
| 1013 |
success, msg = login_account(
|
| 1014 |
account_id,
|
|
|
|
| 1035 |
owner_id = flask_session.get('owner_id')
|
| 1036 |
|
| 1037 |
if account_id in accounts:
|
|
|
|
| 1038 |
if accounts[account_id].get("owner_id") != owner_id:
|
| 1039 |
return "Unauthorized", 403
|
| 1040 |
|
|
|
|
| 1042 |
masked = mask_email(username)
|
| 1043 |
print(f"\n🗑️ HAPUS AKUN: {masked} (ID: {account_id})")
|
| 1044 |
del accounts[account_id]
|
| 1045 |
+
|
| 1046 |
if mongo_client:
|
| 1047 |
accounts_collection.delete_one({"_id": account_id})
|
| 1048 |
+
else:
|
| 1049 |
+
save_accounts_to_file(accounts)
|
| 1050 |
print(f"✅ Akun dihapus")
|
| 1051 |
|
| 1052 |
return redirect(request.referrer or '/')
|
|
|
|
| 1058 |
print(f"\n🔔🔔🔔 LOGIN ACCOUNT DIPANGGIL: {account_id} 🔔🔔🔔")
|
| 1059 |
|
| 1060 |
if account_id in accounts:
|
|
|
|
| 1061 |
if accounts[account_id].get("owner_id") != owner_id:
|
| 1062 |
return "Unauthorized", 403
|
| 1063 |
|
|
|
|
| 1095 |
owner_id = flask_session.get('owner_id')
|
| 1096 |
|
| 1097 |
if account_id in accounts:
|
|
|
|
| 1098 |
if accounts[account_id].get("owner_id") != owner_id:
|
| 1099 |
return "Unauthorized", 403
|
| 1100 |
|
|
|
|
| 1104 |
accounts[account_id]["status"] = False
|
| 1105 |
accounts[account_id]["session"] = None
|
| 1106 |
accounts[account_id]["csrf"] = None
|
| 1107 |
+
|
| 1108 |
+
if mongo_client:
|
| 1109 |
+
save_accounts_to_mongodb(accounts)
|
| 1110 |
+
else:
|
| 1111 |
+
save_accounts_to_file(accounts)
|
| 1112 |
print(f"✅ Logout berhasil")
|
| 1113 |
|
| 1114 |
return redirect(request.referrer or '/')
|
|
|
|
| 1225 |
print(" 🔥 OTP MULTI ACCOUNT - FOURSTORE")
|
| 1226 |
print(" ⚡ PORT: 7860")
|
| 1227 |
print(f" 🌐 DOMAIN: {CUSTOM_DOMAIN}")
|
| 1228 |
+
if mongo_client:
|
| 1229 |
+
print(" 📁 Data tersimpan di MongoDB")
|
| 1230 |
+
else:
|
| 1231 |
+
print(" 📁 Data tersimpan di file accounts.json")
|
| 1232 |
print(" 📋 LOGGING: FULL DETAIL")
|
| 1233 |
print(" 🔒 EMAIL SENSOR: AKTIF")
|
| 1234 |
print(" 🤖 AUTO LOGIN: AKTIF (setelah tambah akun)")
|
| 1235 |
+
print(" 👑 OWNER SYSTEM: AKTIF (owner_id di input form)")
|
| 1236 |
print("="*60 + "\n")
|
| 1237 |
|
|
|
|
| 1238 |
for acc_id, acc in accounts.items():
|
| 1239 |
if acc.get("status"):
|
| 1240 |
masked = mask_email(acc['username'])
|
|
|
|
| 1254 |
else:
|
| 1255 |
print(f"❌ {masked} offline: {msg}")
|
| 1256 |
acc["status"] = False
|
| 1257 |
+
if mongo_client:
|
| 1258 |
+
save_accounts_to_mongodb(accounts)
|
| 1259 |
+
else:
|
| 1260 |
+
save_accounts_to_file(accounts)
|
| 1261 |
|
| 1262 |
print("\n✅ BOT SIAP! Dashboard: https://fourstore-otp.hf.space")
|
| 1263 |
print("🔐 Login dengan Owner ID untuk mengakses")
|
|
|
|
| 1270 |
main()
|
| 1271 |
except KeyboardInterrupt:
|
| 1272 |
print("\n🛑 BOT STOPPED")
|
| 1273 |
+
if mongo_client:
|
| 1274 |
+
save_accounts_to_mongodb(accounts)
|
| 1275 |
+
else:
|
| 1276 |
+
save_accounts_to_file(accounts)
|