import requests import json from uuid import UUID from typing import Dict, Any, Optional import gradio as gr import os import threading import time import pandas as pd ZGM_API_TOKEN = os.getenv("ZGM_API_TOKEN") if not ZGM_API_TOKEN: raise ValueError("ZGM_API_TOKEN not found in environment variables!") VPS_IP = os.getenv("VPS_IP") if not VPS_IP: raise ValueError("VPS_IP not found in environment variables!") KEY_API_URL = f"http://{VPS_IP}:3000" class ZGMApiClient: def __init__(self, base_url: str, api_token: str): self.base_url = base_url.rstrip('/') self.api_token = api_token self.headers = { 'ZGM-API-TOKEN': api_token, 'Content-Type': 'application/json', 'Accept': 'text/plain' } def _make_request(self, method: str, endpoint: str, params: Dict = None, data: Dict = None) -> Dict: url = f"{self.base_url}{endpoint}" try: response = requests.request( method=method, url=url, headers=self.headers, params=params, json=data, timeout=15 ) response.raise_for_status() return response.json() except requests.exceptions.ConnectTimeout: return {"error": f"Cannot connect to {self.base_url}. Please check URL or network.", "status_code": 0} except requests.exceptions.HTTPError as e: if response.status_code == 401: return {"error": "Unauthorized. Please check API Token.", "status_code": 401} elif response.status_code == 500: return {"error": "Server error from ZGM API.", "status_code": 500} return {"error": f"HTTP Error: {str(e)}", "status_code": response.status_code} except requests.exceptions.RequestException as e: return {"error": f"Connection error: {str(e)}", "status_code": 0} def rent_otp(self, service: str) -> Dict: data = {"service": service} return self._make_request('POST', '/api/mail/otp-rent', data=data) def get_otp(self, order_id: str) -> Dict: try: UUID(order_id) return self._make_request('GET', '/api/mail/otp-get', params={"orderId": order_id}) except ValueError: return {"error": "order_id must be a valid UUID", "status_code": 400} client = ZGMApiClient("https://gm.haivl.wtf", ZGM_API_TOKEN) def validate_key_from_api(access_key: str) -> tuple[bool, str]: try: response = requests.get(f"{KEY_API_URL}/api/keys/validate", params={"key": access_key}, timeout=5) response.raise_for_status() data = response.json() if data["valid"]: return True, f"Remaining {data['remaining']} keys." else: return False, "Invalid key!" except requests.exceptions.RequestException as e: return False, f"Error checking key from API: {str(e)}" def remove_key_from_api(access_key: str) -> tuple[bool, str]: try: response = requests.delete(f"{KEY_API_URL}/api/keys/remove", params={"key": access_key}, timeout=5) response.raise_for_status() data = response.json() if data["success"]: return True, f"Remaining {data['remaining']} keys." else: return False, "Cannot remove key." except requests.exceptions.RequestException as e: return False, f"Error removing key from API: {str(e)}" def validate_and_remove_key(access_key: str, result: Dict) -> tuple[bool, str]: is_valid, message = validate_key_from_api(access_key) if not is_valid: return False, message if result.get("code") == 200 and result.get("data") and "orderId" in result["data"] and "email" in result["data"]: success, remove_message = remove_key_from_api(access_key) if not success: return True, f"OTP rented successfully but {remove_message}" remaining_keys = int(remove_message.split("Remaining ")[1].split(" key")[0]) remaining_message = f"Remaining {remaining_keys} keys." if remaining_keys < 100: remaining_message += " Low key count! Please create more keys." return True, remaining_message else: return True, f"Error: {result.get('message', 'Unable to rent Gmail.')}\nKey not deleted." def execute_with_loading(func, *args, **kwargs): result = [None] is_loading = [True] def target(): result[0] = func(*args, **kwargs) is_loading[0] = False api_thread = threading.Thread(target=target) api_thread.start() while is_loading[0]: time.sleep(0.1) api_thread.join() return result[0] def format_rent_otp_result(data: Dict) -> pd.DataFrame: if not data or "data" not in data: return pd.DataFrame([["No data to display."]], columns=["Message"]) order_info = data["data"] df = pd.DataFrame([{ "Order ID": order_info.get("orderId", "N/A"), "Email": order_info.get("email", "N/A") }]) return df def format_get_otp_result(data: Dict) -> pd.DataFrame: if not data or "data" not in data: return pd.DataFrame([["No data to display."]], columns=["Message"]) otp_data = data["data"] if isinstance(otp_data, dict): otp_data = [otp_data] if not isinstance(otp_data, list): return pd.DataFrame([["Invalid data."]], columns=["Message"]) df = pd.DataFrame([ { "Email": item.get("email", "N/A"), "OTP Code": item.get("otpCode", "N/A"), "Content": item.get("otpContent", "N/A") } for item in otp_data ]) return df def clear_all_logs(): return pd.DataFrame([["No data yet"]], columns=["Message"]), pd.DataFrame([["No data yet"]], columns=["Message"]), "" def gradio_interface(access_key, action, service, order_id, rent_otp_log, get_otp_log): message = "" new_order_id = order_id if rent_otp_log is None: rent_otp_log = pd.DataFrame([["No data yet"]], columns=["Message"]) if get_otp_log is None: get_otp_log = pd.DataFrame([["No data yet"]], columns=["Message"]) if action == "Rent OTP": if not access_key: rent_otp_log = pd.DataFrame([["Please enter a key to rent OTP!"]], columns=["Message"]) return rent_otp_log, get_otp_log, message, order_id if not service: rent_otp_log = pd.DataFrame([["Please select a service!"]], columns=["Message"]) return rent_otp_log, get_otp_log, message, order_id result = execute_with_loading(client.rent_otp, service) is_valid, message = validate_and_remove_key(access_key, result) if not is_valid: rent_otp_log = pd.DataFrame([[message]], columns=["Message"]) return rent_otp_log, get_otp_log, message, order_id if result.get("code") == 200: rent_otp_log = format_rent_otp_result(result) new_order_id = result["data"].get("orderId", order_id) else: rent_otp_log = pd.DataFrame([[json.dumps(result, indent=2, ensure_ascii=False)]], columns=["Message"]) return rent_otp_log, get_otp_log, message, new_order_id elif action == "Get OTP": if not order_id: get_otp_log = pd.DataFrame([["Please enter Order ID!"]], columns=["Message"]) return rent_otp_log, get_otp_log, "", order_id result = execute_with_loading(client.get_otp, order_id) if result.get("code") == 200 and "data" in result: get_otp_log = format_get_otp_result(result) else: get_otp_log = pd.DataFrame([[json.dumps(result, indent=2, ensure_ascii=False)]], columns=["Message"]) return rent_otp_log, get_otp_log, "", order_id else: return rent_otp_log, get_otp_log, "Invalid action!", order_id SERVICES = [ "ICLOUD", "ZSK", "FACEBOOK", "TELEGRAM", "GGPLAY", "INSTAGRAM", "FMCPAY", "AMAZON" ] NOTIFICATION_FILE = "notification.txt" def read_notification() -> str: if os.path.exists(NOTIFICATION_FILE): with open(NOTIFICATION_FILE, "r", encoding="utf-8") as f: return f.read() return "" def update_notification(msg_input, password): if password == "2312": with open(NOTIFICATION_FILE, "w", encoding="utf-8") as f: f.write(msg_input) return msg_input return read_notification() with gr.Blocks() as demo: gr.Markdown("## Gmail Trust 247 - Enter Key to Rent OTP") with gr.Row(): access_key = gr.Textbox(label="Access Key (Required for Rent OTP)", placeholder="Enter 32-char key...") action = gr.Dropdown(label="Select Action", choices=["Rent OTP", "Get OTP"], value="Rent OTP") with gr.Row(): service = gr.Dropdown(label="Service (For Rent OTP)", choices=SERVICES) order_id = gr.Textbox(label="Order ID (For Get OTP)", placeholder="Enter Order ID") rent_otp_log = gr.State(value=pd.DataFrame([["No data yet"]], columns=["Message"])) get_otp_log = gr.State(value=pd.DataFrame([["No data yet"]], columns=["Message"])) rent_otp_output = gr.Dataframe( label="Rent OTP Log", headers=["Order ID", "Email"], datatype=["str", "str"], interactive=False ) get_otp_output = gr.Dataframe( label="Get OTP Log", headers=["Email", "OTP Code", "Content"], datatype=["str", "str", "str"], interactive=False ) message_output = gr.Textbox(label="Message", interactive=False) with gr.Row(): submit_btn = gr.Button("Submit", variant="primary") clear_btn = gr.Button("Clear Log", variant="secondary") 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] ) clear_btn.click( fn=clear_all_logs, inputs=None, outputs=[rent_otp_output, get_otp_output, message_output] ) gr.Markdown("## System Notification") with gr.Row(): notification_input = gr.Textbox(label="View the number of gmail in stock", lines=3) password_input = gr.Textbox(label="Password", type="password") with gr.Row(): update_btn = gr.Button("View the number of gmail in stock") current_notification = gr.Textbox(label="gmail in stock", value=read_notification(), interactive=False) update_btn.click(update_notification, inputs=[notification_input, password_input], outputs=current_notification) gr.Markdown("## Get OTP Log") demo.launch()