GmailTrust commited on
Commit
a36092f
·
verified ·
1 Parent(s): 0a62fff

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +125 -102
app.py CHANGED
@@ -1,28 +1,28 @@
1
  import requests
2
  import json
3
  from uuid import UUID
 
4
  import gradio as gr
5
  import os
6
  import threading
7
  import time
8
  import pandas as pd
9
- from typing import Dict, Tuple
10
 
11
- # Get ZGM API Token from environment variables
12
  ZGM_API_TOKEN = os.getenv("ZGM_API_TOKEN")
13
  if not ZGM_API_TOKEN:
14
- raise ValueError("ZGM_API_TOKEN not found in environment variables!")
15
 
16
- # Get VPS IP from environment variables
17
  VPS_IP = os.getenv("VPS_IP")
18
  if not VPS_IP:
19
- raise ValueError("VPS_IP not found in environment variables!")
20
 
21
- # VPS API URL
22
  KEY_API_URL = f"http://{VPS_IP}:3000"
23
 
24
  class ZGMApiClient:
25
- """Client class to interact with ZGM API"""
26
 
27
  def __init__(self, base_url: str, api_token: str):
28
  self.base_url = base_url.rstrip('/')
@@ -47,75 +47,82 @@ class ZGMApiClient:
47
  response.raise_for_status()
48
  return response.json()
49
  except requests.exceptions.ConnectTimeout:
50
- return {"error": f"Could not connect to {self.base_url}. Please check URL or network.", "status_code": 0}
51
  except requests.exceptions.HTTPError as e:
52
  if response.status_code == 401:
53
- return {"error": "Not logged in. Please check API Token.", "status_code": 401}
54
  elif response.status_code == 500:
55
- return {"error": "Server error from ZGM API.", "status_code": 500}
56
- return {"error": f"HTTP Error: {str(e)}", "status_code": response.status_code}
57
  except requests.exceptions.RequestException as e:
58
- return {"error": f"Connection Error: {str(e)}", "status_code": 0}
59
 
60
- def rent_mail(self, service: str) -> Dict:
61
  data = {"service": service}
62
- return self._make_request('POST', '/api/mail/rent', data=data)
63
 
64
  def get_otp(self, order_id: str) -> Dict:
65
  try:
66
  UUID(order_id)
67
- return self._make_request('GET', '/api/mail/otp', params={"orderId": order_id})
68
  except ValueError:
69
- return {"error": "order_id must be a valid UUID", "status_code": 400}
70
 
71
- # Initialize client
72
  client = ZGMApiClient("https://gm.haivl.wtf", ZGM_API_TOKEN)
73
 
74
- # Validate key from VPS API
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
  response.raise_for_status()
79
  data = response.json()
80
  if data["valid"]:
81
- return True, f"Remaining keys: {data['remaining']}."
82
  else:
83
- return False, "Invalid key! Please enter a valid key."
84
  except requests.exceptions.RequestException as e:
85
- return False, f"Error checking key from API: {str(e)}"
 
86
 
87
- # Remove key from VPS API
88
  def remove_key_from_api(access_key: str) -> tuple[bool, str]:
89
  try:
90
  response = requests.delete(f"{KEY_API_URL}/api/keys/remove", params={"key": access_key}, timeout=5)
 
91
  response.raise_for_status()
92
  data = response.json()
93
  if data["success"]:
94
- return True, f"Remaining keys: {data['remaining']}."
95
  else:
96
- return False, "Failed to remove key."
97
  except requests.exceptions.RequestException as e:
98
- return False, f"Error removing key from API: {str(e)}"
 
99
 
100
- # Validate and remove key
101
  def validate_and_remove_key(access_key: str, result: Dict) -> tuple[bool, str]:
 
102
  is_valid, message = validate_key_from_api(access_key)
 
103
  if not is_valid:
104
  return False, message
105
 
 
106
  if result.get("code") == 200 and result.get("data") and "orderId" in result["data"] and "email" in result["data"]:
107
  success, remove_message = remove_key_from_api(access_key)
108
  if not success:
109
- return True, f"Mail rented successfully but {remove_message}"
110
- remaining_keys = int(remove_message.split("Remaining keys: ")[1].split(".")[0])
111
- remaining_message = f"Remaining keys: {remaining_keys}."
112
  if remaining_keys < 100:
113
- remaining_message += " Low key count! Please add more keys."
114
  return True, remaining_message
115
  else:
116
- return True, f"Error: {result.get('message', 'Failed to rent mail.')}\nKey not removed."
117
 
118
- # Async execution with loading indicator
119
  def execute_with_loading(func, *args, **kwargs):
120
  result = [None]
121
  is_loading = [True]
@@ -130,7 +137,7 @@ def execute_with_loading(func, *args, **kwargs):
130
  chars = "|/-\\"
131
  i = 0
132
  while is_loading[0]:
133
- print(f"\rLoading {chars[i % len(chars)]}", end="")
134
  i += 1
135
  time.sleep(0.1)
136
  print("\r", end="")
@@ -138,10 +145,10 @@ def execute_with_loading(func, *args, **kwargs):
138
  api_thread.join()
139
  return result[0]
140
 
141
- # Format rent mail result
142
- def format_rent_result(data: Dict) -> pd.DataFrame:
143
  if not data or "data" not in data:
144
- return pd.DataFrame([["No data to display."]], columns=["Message"])
145
  order_info = data["data"]
146
  df = pd.DataFrame([{
147
  "Order ID": order_info.get("orderId", "N/A"),
@@ -149,120 +156,136 @@ def format_rent_result(data: Dict) -> pd.DataFrame:
149
  }])
150
  return df
151
 
152
- # Format OTP result
153
- def format_otp_result(data: Dict, selected_service: str) -> pd.DataFrame:
154
  if not data or "data" not in data:
155
- return pd.DataFrame([["No data to display."]], columns=["Message"])
156
 
157
  otp_data = data["data"]
158
 
 
159
  if isinstance(otp_data, dict):
160
- otp_data = [otp_data]
161
 
 
162
  if not isinstance(otp_data, list):
163
- return pd.DataFrame([["Invalid data format."]], columns=["Message"])
164
 
165
  df = pd.DataFrame([
166
  {
167
- "Service": selected_service,
168
- "Email": item.get("email", "N/A"),
169
  "OTP Code": item.get("otpCode", "N/A"),
170
- "Content": item.get("otpContent", "N/A")
171
  }
172
  for item in otp_data
173
  ])
174
  return df
175
 
176
- # Clear all logs
177
  def clear_all_logs():
178
- return pd.DataFrame([["No data yet"]], columns=["Message"]), pd.DataFrame([["No data yet"]], columns=["Message"]), ""
179
 
180
- # Services list
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  SERVICES = [
182
  "ICLOUD", "ZSK", "FACEBOOK", "TELEGRAM", "OTHERS",
183
  "GGPLAY", "INSTAGRAM", "FMCPAY", "AMAZON"
184
  ]
185
 
186
- # Gradio interface
187
  with gr.Blocks() as demo:
188
- gr.Markdown("## Gmail Trust 247 API Client - Rent Gmails for OTP Services")
189
 
190
  with gr.Row():
191
- access_key = gr.Textbox(label="Access Key (Required for renting)", placeholder="Enter your 32-character key...")
192
- service = gr.Dropdown(label="Service", choices=SERVICES)
 
 
 
 
193
 
194
  with gr.Row():
195
- order_id = gr.Textbox(label="Order ID", placeholder="Enter Order ID from rented mail")
 
196
 
197
- rent_result = gr.State(value=pd.DataFrame([["No data yet"]], columns=["Message"]))
198
- otp_result = gr.State(value=pd.DataFrame([["No data yet"]], columns=["Message"]))
199
 
200
  with gr.Row():
201
- rent_output = gr.Dataframe(
202
- label="Rented Mail",
203
  headers=["Order ID", "Email"],
204
  datatype=["str", "str"],
205
  interactive=False
206
  )
207
- otp_output = gr.Dataframe(
208
- label="OTP Results",
209
  headers=["Service", "Email", "OTP Code", "Content"],
210
  datatype=["str", "str", "str", "str"],
211
  interactive=False
212
  )
213
 
214
- message_output = gr.Textbox(label="Status Message", interactive=False)
215
 
216
  with gr.Row():
217
- rent_btn = gr.Button("Rent Mail", variant="primary")
218
- get_otp_btn = gr.Button("Get OTP", variant="primary")
219
- clear_btn = gr.Button("Clear Logs", variant="secondary")
220
-
221
- def rent_mail_action(access_key, service, rent_result, otp_result):
222
- if not access_key:
223
- return pd.DataFrame([["Please enter access key!"]], columns=["Message"]), otp_result, "Access key required", rent_result
224
- if not service:
225
- return pd.DataFrame([["Please select service!"]], columns=["Message"]), otp_result, "Service required", rent_result
226
-
227
- result = execute_with_loading(client.rent_mail, service)
228
- is_valid, message = validate_and_remove_key(access_key, result)
229
- if not is_valid:
230
- return pd.DataFrame([[message]], columns=["Message"]), otp_result, message, rent_result
231
-
232
- if result.get("code") == 200:
233
- df = format_rent_result(result)
234
- new_order_id = result["data"].get("orderId", "")
235
- return df, otp_result, message, new_order_id
236
- else:
237
- return pd.DataFrame([[json.dumps(result, indent=2, ensure_ascii=False)]], columns=["Message"]), otp_result, message, rent_result
238
-
239
- def get_otp_action(order_id, service, rent_result, otp_result):
240
- if not order_id:
241
- return rent_result, pd.DataFrame([["Please enter Order ID!"]], columns=["Message"]), "", rent_result
242
-
243
- result = execute_with_loading(client.get_otp, order_id)
244
- if result.get("code") == 200 and "data" in result:
245
- df = format_otp_result(result, service)
246
- return rent_result, df, "", rent_result
247
- else:
248
- return rent_result, pd.DataFrame([[json.dumps(result, indent=2, ensure_ascii=False)]], columns=["Message"]), "", rent_result
249
-
250
- rent_btn.click(
251
- fn=rent_mail_action,
252
- inputs=[access_key, service, rent_result, otp_result],
253
- outputs=[rent_output, otp_output, message_output, order_id]
254
- )
255
 
256
- get_otp_btn.click(
257
- fn=get_otp_action,
258
- inputs=[order_id, service, rent_result, otp_result],
259
- outputs=[rent_output, otp_output, message_output, order_id]
260
  )
261
 
262
  clear_btn.click(
263
  fn=clear_all_logs,
264
  inputs=None,
265
- outputs=[rent_output, otp_output, message_output]
266
  )
267
 
 
268
  demo.launch()
 
1
  import requests
2
  import json
3
  from uuid import UUID
4
+ from typing import Dict, Any, Optional
5
  import gradio as gr
6
  import os
7
  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('/')
 
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}
62
+ return self._make_request('POST', '/api/mail/otp-rent', data=data)
63
 
64
  def get_otp(self, order_id: str) -> Dict:
65
  try:
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
  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
  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"),
 
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)
210
+ if not is_valid:
211
+ rent_otp_log = pd.DataFrame([[message]], columns=["Message"])
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()