GmailTrust commited on
Commit
28b3d23
·
verified ·
1 Parent(s): a36092f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -127
app.py CHANGED
@@ -8,22 +8,17 @@ import threading
8
  import time
9
  import pandas as pd
10
 
11
- # Lấy ZGM API Token từ biến môi trường (Secrets trên Hugging Face)
12
  ZGM_API_TOKEN = os.getenv("ZGM_API_TOKEN")
13
  if not ZGM_API_TOKEN:
14
- raise ValueError("ZGM_API_TOKEN không được tìm thấy trong biến môi trường!")
15
 
16
- # Lấy địa chỉ IP của VPS từ Secrets
17
  VPS_IP = os.getenv("VPS_IP")
18
  if not VPS_IP:
19
- raise ValueError("VPS_IP không được tìm thấy trong biến môi trường!")
20
 
21
- # URL của API trên VPS (dùng port 3000)
22
  KEY_API_URL = f"http://{VPS_IP}:3000"
23
 
24
  class ZGMApiClient:
25
- """Lớp client để tương tác với ZGM API"""
26
-
27
  def __init__(self, base_url: str, api_token: str):
28
  self.base_url = base_url.rstrip('/')
29
  self.api_token = api_token
@@ -47,15 +42,15 @@ class ZGMApiClient:
47
  response.raise_for_status()
48
  return response.json()
49
  except requests.exceptions.ConnectTimeout:
50
- return {"error": f"Không thể kết nối đến {self.base_url}. Vui lòng kiểm tra URL hoặc mạng.", "status_code": 0}
51
  except requests.exceptions.HTTPError as e:
52
  if response.status_code == 401:
53
- return {"error": "Chưa đăng nhập. Vui lòng kiểm tra API Token.", "status_code": 401}
54
  elif response.status_code == 500:
55
- return {"error": "Lỗi server từ ZGM API.", "status_code": 500}
56
- return {"error": f"Lỗi HTTP: {str(e)}", "status_code": response.status_code}
57
  except requests.exceptions.RequestException as e:
58
- return {"error": f"Lỗi kết nối: {str(e)}", "status_code": 0}
59
 
60
  def rent_otp(self, service: str) -> Dict:
61
  data = {"service": service}
@@ -66,63 +61,51 @@ class ZGMApiClient:
66
  UUID(order_id)
67
  return self._make_request('GET', '/api/mail/otp-get', params={"orderId": order_id})
68
  except ValueError:
69
- return {"error": "order_id phải là UUID hợp lệ", "status_code": 400}
70
 
71
- # Khởi tạo client
72
  client = ZGMApiClient("https://gm.haivl.wtf", ZGM_API_TOKEN)
73
 
74
- # Hàm kiểm tra key từ API trên VPS mà không xóa
75
  def validate_key_from_api(access_key: str) -> tuple[bool, str]:
76
  try:
77
  response = requests.get(f"{KEY_API_URL}/api/keys/validate", params={"key": access_key}, timeout=5)
78
- print(f"Validate API Response: {response.text}") # Debug log
79
  response.raise_for_status()
80
  data = response.json()
81
  if data["valid"]:
82
- return True, f"Còn lại {data['remaining']} key."
83
  else:
84
- return False, "Key không hợp lệ! Vui lòng nhập key hợp lệ để tiếp tục."
85
  except requests.exceptions.RequestException as e:
86
- print(f"Validate API Error: {str(e)}") # Debug log
87
- return False, f"Lỗi khi kiểm tra key từ API: {str(e)}"
88
 
89
- # Hàm xóa key từ API trên VPS
90
  def remove_key_from_api(access_key: str) -> tuple[bool, str]:
91
  try:
92
  response = requests.delete(f"{KEY_API_URL}/api/keys/remove", params={"key": access_key}, timeout=5)
93
- print(f"Remove API Response: {response.text}") # Debug log
94
  response.raise_for_status()
95
  data = response.json()
96
  if data["success"]:
97
- return True, f"Còn lại {data['remaining']} key."
98
  else:
99
- return False, "Không thể xóa key."
100
  except requests.exceptions.RequestException as e:
101
- print(f"Remove API Error: {str(e)}") # Debug log
102
- return False, f"Lỗi khi xóa key từ API: {str(e)}"
103
 
104
- # Hàm xác thực và xóa key
105
  def validate_and_remove_key(access_key: str, result: Dict) -> tuple[bool, str]:
106
- # Kiểm tra key có hợp lệ không
107
  is_valid, message = validate_key_from_api(access_key)
108
- print(f"Input Key: {access_key}, Valid: {is_valid}") # Debug log
109
  if not is_valid:
110
  return False, message
111
-
112
- # Chỉ xóa key khi thuê OTP thành công
113
  if result.get("code") == 200 and result.get("data") and "orderId" in result["data"] and "email" in result["data"]:
114
  success, remove_message = remove_key_from_api(access_key)
115
  if not success:
116
- return True, f"Thuê OTP thành công nhưng {remove_message}"
117
- remaining_keys = int(remove_message.split("Còn lại ")[1].split(" key")[0])
118
- remaining_message = f"Còn lại {remaining_keys} key."
119
  if remaining_keys < 100:
120
- remaining_message += " Số lượng key còn ít! Vui lòng tạo thêm key mới."
121
  return True, remaining_message
122
  else:
123
- return True, f"Lỗi: {result.get('message', 'Không thể thuê Gmail.')}\nKey không bị xóa."
124
 
125
- # Hàm xử lý bất đồng bộ với chỉ báo tải
126
  def execute_with_loading(func, *args, **kwargs):
127
  result = [None]
128
  is_loading = [True]
@@ -137,7 +120,7 @@ def execute_with_loading(func, *args, **kwargs):
137
  chars = "|/-\\"
138
  i = 0
139
  while is_loading[0]:
140
- print(f"\rĐang tải {chars[i % len(chars)]}", end="")
141
  i += 1
142
  time.sleep(0.1)
143
  print("\r", end="")
@@ -145,65 +128,51 @@ def execute_with_loading(func, *args, **kwargs):
145
  api_thread.join()
146
  return result[0]
147
 
148
- # Hàm định dạng kết quả "Thuê OTP" thành bảng (chỉ Order ID và Email)
149
  def format_rent_otp_result(data: Dict) -> pd.DataFrame:
150
  if not data or "data" not in data:
151
- return pd.DataFrame([["Không có dữ liệu để hiển thị."]], columns=["Message"])
152
  order_info = data["data"]
153
- df = pd.DataFrame([{
154
- "Order ID": order_info.get("orderId", "N/A"),
155
- "Email": order_info.get("email", "N/A")
156
- }])
157
  return df
158
 
159
- # Hàm định dạng kết quả "Lấy OTP" thành bảng (Service, Email, OTP Code, và nội dung thư)
160
  def format_get_otp_result(data: Dict, selected_service: str) -> pd.DataFrame:
161
  if not data or "data" not in data:
162
- return pd.DataFrame([["Không có dữ liệu để hiển thị."]], columns=["Message"])
163
-
164
  otp_data = data["data"]
165
-
166
- # Nếu là đối tượng đơn (không phải danh sách)
167
  if isinstance(otp_data, dict):
168
- otp_data = [otp_data] # Chuyển thành danh sách để xử lý thống nhất
169
-
170
- # Nếu không phải danh sách, dữ liệu không hợp lệ
171
  if not isinstance(otp_data, list):
172
- return pd.DataFrame([["Dữ liệu không hợp lệ."]], columns=["Message"])
173
-
174
  df = pd.DataFrame([
175
  {
176
- "Service": selected_service, # Sử dụng dịch vụ đã chọn khi thuê
177
- "Email": item.get("email", "N/A"), # Thêm email vào log
178
  "OTP Code": item.get("otpCode", "N/A"),
179
- "Content": item.get("otpContent", "N/A") # Nội dung thư từ API
180
  }
181
  for item in otp_data
182
  ])
183
  return df
184
 
185
- # Hàm xóa tất cả log
186
  def clear_all_logs():
187
- return pd.DataFrame([["Chưa có dữ liệu"]], columns=["Message"]), pd.DataFrame([["Chưa có dữ liệu"]], columns=["Message"]), ""
188
 
189
- # Hàm giao diện Gradio
190
  def gradio_interface(access_key, action, service, order_id, rent_otp_log, get_otp_log):
191
  message = ""
192
- new_order_id = order_id # Giữ nguyên order_id nếu không có thay đổi
193
-
194
- # Khởi tạo log nếu chưa có
195
  if rent_otp_log is None:
196
- rent_otp_log = pd.DataFrame([["Chưa có dữ liệu"]], columns=["Message"])
197
  if get_otp_log is None:
198
- get_otp_log = pd.DataFrame([["Chưa có dữ liệu"]], columns=["Message"])
199
 
200
- # Chỉ yêu cầu key cho hành động "Thuê OTP"
201
- if action == "Thuê OTP":
202
  if not access_key:
203
- rent_otp_log = pd.DataFrame([["Vui lòng nhập key để thực hiện Thuê OTP!"]], columns=["Message"])
204
  return rent_otp_log, get_otp_log, message, order_id
205
  if not service:
206
- rent_otp_log = pd.DataFrame([["Vui lòng chọn dịch vụ!"]], columns=["Message"])
207
  return rent_otp_log, get_otp_log, message, order_id
208
  result = execute_with_loading(client.rent_otp, service)
209
  is_valid, message = validate_and_remove_key(access_key, result)
@@ -212,80 +181,50 @@ def gradio_interface(access_key, action, service, order_id, rent_otp_log, get_ot
212
  return rent_otp_log, get_otp_log, message, order_id
213
  if result.get("code") == 200:
214
  rent_otp_log = format_rent_otp_result(result)
215
- # Lấy Order ID mới để tự động điền
216
  new_order_id = result["data"].get("orderId", order_id)
217
  else:
218
  rent_otp_log = pd.DataFrame([[json.dumps(result, indent=2, ensure_ascii=False)]], columns=["Message"])
219
  return rent_otp_log, get_otp_log, message, new_order_id
220
- elif action == "Lấy OTP":
221
  if not order_id:
222
- get_otp_log = pd.DataFrame([["Vui lòng nhập Order ID!"]], columns=["Message"])
223
  return rent_otp_log, get_otp_log, "", order_id
224
  result = execute_with_loading(client.get_otp, order_id)
225
  if result.get("code") == 200 and "data" in result:
226
- get_otp_log = format_get_otp_result(result, service) # Truyền service đã chọn
227
  else:
228
  get_otp_log = pd.DataFrame([[json.dumps(result, indent=2, ensure_ascii=False)]], columns=["Message"])
229
  return rent_otp_log, get_otp_log, "", order_id
230
  else:
231
- return rent_otp_log, get_otp_log, "Hành động không hợp lệ!", order_id
232
 
233
- # Danh sách dịch vụ cố định
234
- SERVICES = [
235
- "ICLOUD", "ZSK", "FACEBOOK", "TELEGRAM", "OTHERS",
236
- "GGPLAY", "INSTAGRAM", "FMCPAY", "AMAZON"
237
- ]
238
 
239
- # Tạo giao diện Gradio
240
  with gr.Blocks() as demo:
241
- gr.Markdown("## ZGM API Client - Nhập Key để Thuê OTP (Key chỉ cần thiết cho Thuê OTP, mỗi key dùng 1 lần)")
242
-
243
  with gr.Row():
244
- access_key = gr.Textbox(label="Nhập Key Truy Cập (Chỉ cần cho Thuê OTP)", placeholder="Nhập key 32 ký tự...")
245
- action = gr.Dropdown(
246
- label="Chọn Hành Động",
247
- choices=["Thuê OTP", "Lấy OTP"],
248
- value="Thuê OTP"
249
- )
250
-
251
  with gr.Row():
252
- service = gr.Dropdown(label="Dịch Vụ (Cho Thuê OTP)", choices=SERVICES)
253
- order_id = gr.Textbox(label="Order ID (Cho Lấy OTP)", placeholder="Nhập Order ID")
254
-
255
- rent_otp_log = gr.State(value=pd.DataFrame([["Chưa có dữ liệu"]], columns=["Message"]))
256
- get_otp_log = gr.State(value=pd.DataFrame([["Chưa có dữ liệu"]], columns=["Message"]))
257
-
258
  with gr.Row():
259
- rent_otp_output = gr.Dataframe(
260
- label="Log Thuê OTP",
261
- headers=["Order ID", "Email"],
262
- datatype=["str", "str"],
263
- interactive=False
264
- )
265
- get_otp_output = gr.Dataframe(
266
- label="Log Lấy OTP",
267
- headers=["Service", "Email", "OTP Code", "Content"],
268
- datatype=["str", "str", "str", "str"],
269
- interactive=False
270
- )
271
-
272
- message_output = gr.Textbox(label="Thông Báo", interactive=False)
273
-
274
  with gr.Row():
275
- submit_btn = gr.Button("Thực Thi", variant="primary")
276
- clear_btn = gr.Button("Xóa Log", variant="secondary")
277
-
278
- submit_btn.click(
279
- fn=gradio_interface,
280
- inputs=[access_key, action, service, order_id, rent_otp_log, get_otp_log],
281
- outputs=[rent_otp_output, get_otp_output, message_output, order_id]
282
- )
283
-
284
- clear_btn.click(
285
- fn=clear_all_logs,
286
- inputs=None,
287
- outputs=[rent_otp_output, get_otp_output, message_output]
288
- )
289
-
290
- # Khởi chạy giao diện
291
- demo.launch()
 
8
  import time
9
  import pandas as pd
10
 
 
11
  ZGM_API_TOKEN = os.getenv("ZGM_API_TOKEN")
12
  if not ZGM_API_TOKEN:
13
+ raise ValueError("ZGM_API_TOKEN not found in environment variables!")
14
 
 
15
  VPS_IP = os.getenv("VPS_IP")
16
  if not VPS_IP:
17
+ raise ValueError("VPS_IP not found in environment variables!")
18
 
 
19
  KEY_API_URL = f"http://{VPS_IP}:3000"
20
 
21
  class ZGMApiClient:
 
 
22
  def __init__(self, base_url: str, api_token: str):
23
  self.base_url = base_url.rstrip('/')
24
  self.api_token = api_token
 
42
  response.raise_for_status()
43
  return response.json()
44
  except requests.exceptions.ConnectTimeout:
45
+ return {"error": f"Cannot connect to {self.base_url}. Check URL or network.", "status_code": 0}
46
  except requests.exceptions.HTTPError as e:
47
  if response.status_code == 401:
48
+ return {"error": "Unauthorized. Check API Token.", "status_code": 401}
49
  elif response.status_code == 500:
50
+ return {"error": "Server error from ZGM API.", "status_code": 500}
51
+ return {"error": f"HTTP Error: {str(e)}", "status_code": response.status_code}
52
  except requests.exceptions.RequestException as e:
53
+ return {"error": f"Connection error: {str(e)}", "status_code": 0}
54
 
55
  def rent_otp(self, service: str) -> Dict:
56
  data = {"service": service}
 
61
  UUID(order_id)
62
  return self._make_request('GET', '/api/mail/otp-get', params={"orderId": order_id})
63
  except ValueError:
64
+ return {"error": "order_id must be a valid UUID", "status_code": 400}
65
 
 
66
  client = ZGMApiClient("https://gm.haivl.wtf", ZGM_API_TOKEN)
67
 
 
68
  def validate_key_from_api(access_key: str) -> tuple[bool, str]:
69
  try:
70
  response = requests.get(f"{KEY_API_URL}/api/keys/validate", params={"key": access_key}, timeout=5)
 
71
  response.raise_for_status()
72
  data = response.json()
73
  if data["valid"]:
74
+ return True, f"{data['remaining']} key(s) remaining."
75
  else:
76
+ return False, "Invalid key. Please enter a valid key."
77
  except requests.exceptions.RequestException as e:
78
+ return False, f"Error while checking key from API: {str(e)}"
 
79
 
 
80
  def remove_key_from_api(access_key: str) -> tuple[bool, str]:
81
  try:
82
  response = requests.delete(f"{KEY_API_URL}/api/keys/remove", params={"key": access_key}, timeout=5)
 
83
  response.raise_for_status()
84
  data = response.json()
85
  if data["success"]:
86
+ return True, f"{data['remaining']} key(s) remaining."
87
  else:
88
+ return False, "Could not remove key."
89
  except requests.exceptions.RequestException as e:
90
+ return False, f"Error while removing key from API: {str(e)}"
 
91
 
 
92
  def validate_and_remove_key(access_key: str, result: Dict) -> tuple[bool, str]:
 
93
  is_valid, message = validate_key_from_api(access_key)
 
94
  if not is_valid:
95
  return False, message
96
+
 
97
  if result.get("code") == 200 and result.get("data") and "orderId" in result["data"] and "email" in result["data"]:
98
  success, remove_message = remove_key_from_api(access_key)
99
  if not success:
100
+ return True, f"OTP rental succeeded but {remove_message}"
101
+ remaining_keys = int(remove_message.split(" key")[0].split()[-1])
102
+ remaining_message = f"{remaining_keys} key(s) remaining."
103
  if remaining_keys < 100:
104
+ remaining_message += " Low key count! Please generate more."
105
  return True, remaining_message
106
  else:
107
+ return True, f"Error: {result.get('message', 'Could not rent Gmail.')}\nKey not removed."
108
 
 
109
  def execute_with_loading(func, *args, **kwargs):
110
  result = [None]
111
  is_loading = [True]
 
120
  chars = "|/-\\"
121
  i = 0
122
  while is_loading[0]:
123
+ print(f"\rLoading {chars[i % len(chars)]}", end="")
124
  i += 1
125
  time.sleep(0.1)
126
  print("\r", end="")
 
128
  api_thread.join()
129
  return result[0]
130
 
 
131
  def format_rent_otp_result(data: Dict) -> pd.DataFrame:
132
  if not data or "data" not in data:
133
+ return pd.DataFrame([["No data to display."]], columns=["Message"])
134
  order_info = data["data"]
135
+ df = pd.DataFrame([{ "Order ID": order_info.get("orderId", "N/A"), "Email": order_info.get("email", "N/A") }])
 
 
 
136
  return df
137
 
 
138
  def format_get_otp_result(data: Dict, selected_service: str) -> pd.DataFrame:
139
  if not data or "data" not in data:
140
+ return pd.DataFrame([["No data to display."]], columns=["Message"])
 
141
  otp_data = data["data"]
 
 
142
  if isinstance(otp_data, dict):
143
+ otp_data = [otp_data]
 
 
144
  if not isinstance(otp_data, list):
145
+ return pd.DataFrame([["Invalid data."]], columns=["Message"])
146
+
147
  df = pd.DataFrame([
148
  {
149
+ "Service": selected_service,
150
+ "Email": item.get("email", "N/A"),
151
  "OTP Code": item.get("otpCode", "N/A"),
152
+ "Content": item.get("otpContent", "N/A")
153
  }
154
  for item in otp_data
155
  ])
156
  return df
157
 
 
158
  def clear_all_logs():
159
+ return pd.DataFrame([["No data yet"]], columns=["Message"]), pd.DataFrame([["No data yet"]], columns=["Message"]), ""
160
 
 
161
  def gradio_interface(access_key, action, service, order_id, rent_otp_log, get_otp_log):
162
  message = ""
163
+ new_order_id = order_id
164
+
 
165
  if rent_otp_log is None:
166
+ rent_otp_log = pd.DataFrame([["No data yet"]], columns=["Message"])
167
  if get_otp_log is None:
168
+ get_otp_log = pd.DataFrame([["No data yet"]], columns=["Message"])
169
 
170
+ if action == "Rent OTP":
 
171
  if not access_key:
172
+ rent_otp_log = pd.DataFrame([["Please enter key to proceed!"]], columns=["Message"])
173
  return rent_otp_log, get_otp_log, message, order_id
174
  if not service:
175
+ rent_otp_log = pd.DataFrame([["Please select a service!"]], columns=["Message"])
176
  return rent_otp_log, get_otp_log, message, order_id
177
  result = execute_with_loading(client.rent_otp, service)
178
  is_valid, message = validate_and_remove_key(access_key, result)
 
181
  return rent_otp_log, get_otp_log, message, order_id
182
  if result.get("code") == 200:
183
  rent_otp_log = format_rent_otp_result(result)
 
184
  new_order_id = result["data"].get("orderId", order_id)
185
  else:
186
  rent_otp_log = pd.DataFrame([[json.dumps(result, indent=2, ensure_ascii=False)]], columns=["Message"])
187
  return rent_otp_log, get_otp_log, message, new_order_id
188
+ elif action == "Get OTP":
189
  if not order_id:
190
+ get_otp_log = pd.DataFrame([["Please enter Order ID!"]], columns=["Message"])
191
  return rent_otp_log, get_otp_log, "", order_id
192
  result = execute_with_loading(client.get_otp, order_id)
193
  if result.get("code") == 200 and "data" in result:
194
+ get_otp_log = format_get_otp_result(result, service)
195
  else:
196
  get_otp_log = pd.DataFrame([[json.dumps(result, indent=2, ensure_ascii=False)]], columns=["Message"])
197
  return rent_otp_log, get_otp_log, "", order_id
198
  else:
199
+ return rent_otp_log, get_otp_log, "Invalid action!", order_id
200
 
201
+ SERVICES = ["ICLOUD", "ZSK", "FACEBOOK", "TELEGRAM", "OTHERS", "GGPLAY", "INSTAGRAM", "FMCPAY", "AMAZON"]
 
 
 
 
202
 
 
203
  with gr.Blocks() as demo:
204
+ gr.Markdown("## ZGM API Client - Enter Access Key to Rent OTP (Key is required only for Rent OTP, one-time use only)")
205
+
206
  with gr.Row():
207
+ access_key = gr.Textbox(label="Enter Access Key (Only for Rent OTP)", placeholder="Enter 32-character key...")
208
+ action = gr.Dropdown(label="Select Action", choices=["Rent OTP", "Get OTP"], value="Rent OTP")
209
+
 
 
 
 
210
  with gr.Row():
211
+ service = gr.Dropdown(label="Service (for Rent OTP)", choices=SERVICES)
212
+ order_id = gr.Textbox(label="Order ID (for Get OTP)", placeholder="Enter Order ID")
213
+
214
+ rent_otp_log = gr.State(value=pd.DataFrame([["No data yet"]], columns=["Message"]))
215
+ get_otp_log = gr.State(value=pd.DataFrame([["No data yet"]], columns=["Message"]))
216
+
217
  with gr.Row():
218
+ rent_otp_output = gr.Dataframe(label="Rent OTP Log", headers=["Order ID", "Email"], datatype=["str", "str"], interactive=False)
219
+ get_otp_output = gr.Dataframe(label="Get OTP Log", headers=["Service", "Email", "OTP Code", "Content"], datatype=["str", "str", "str", "str"], interactive=False)
220
+
221
+ message_output = gr.Textbox(label="Message", interactive=False)
222
+
 
 
 
 
 
 
 
 
 
 
223
  with gr.Row():
224
+ submit_btn = gr.Button("Execute", variant="primary")
225
+ clear_btn = gr.Button("Clear Logs", variant="secondary")
226
+
227
+ submit_btn.click(fn=gradio_interface, inputs=[access_key, action, service, order_id, rent_otp_log, get_otp_log], outputs=[rent_otp_output, get_otp_output, message_output, order_id])
228
+ clear_btn.click(fn=clear_all_logs, inputs=None, outputs=[rent_otp_output, get_otp_output, message_output])
229
+
230
+ demo.launch()