admin 发表于 2025-5-15 21:59:40

号商用来挣钱的1脚本

Gmi.py


import datetime
import json
import random
import string
import time

import httpx

from graph import EmailFetcher


def generate_random_string(length: int = 8) -> str:
    """Generate a random string of specified length using lowercase letters and numbers.

    Args:
      length: Length of the string to generate. Defaults to 8.

    Returns:
      str: Random string of specified length
    """
    characters = string.ascii_lowercase + string.digits
    return "".join(random.choice(characters) for _ in range(length))


def load_proxies():
    """Load and parse proxies from the proxies.txt file.

    Returns:
      list: List of proxy strings in format host:port:username:password
    """
    proxies = []
    try:
      with open("proxies.txt", "r") as f:
            for line in f:
                line = line.strip()
                if line:# Skip empty lines
                  proxies.append(line)
      return proxies
    except Exception as e:
      print(f"Error loading proxies: {e}")
      return []


def get_random_proxy(proxies):
    """Get a random proxy from the list.

    Args:
      proxies: List of proxy strings

    Returns:
      str: A random proxy string or None if list is empty
    """
    if not proxies:
      return None
    return random.choice(proxies)


class RequestyClient:
    """Class for managing Requesty.ai account operations."""

    BASE_API_URL = "https://inference-engine.gmicloud.ai/api/v1"

    def __init__(
      self, email: str, password: str, client_id: str, refresh_token: str, proxy=None
    ):
      self.email = email
      self.password = password
      self.email_fetcher = EmailFetcher(client_id, refresh_token)
      self.client_id = client_id
      self.refresh_token = refresh_token
      self.proxy = proxy
      self.request_client_id = generate_random_string()# 生成唯一的客户端ID

      # Setup client with or without proxy
      if proxy:
            # Format: host:port:username:password
            proxy_host, proxy_port, proxy_user, proxy_pass = proxy.split(":")
            # Construct the proxy URL in the correct format for httpx
            proxy_url = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
            self.client = httpx.Client(proxy=proxy_url)
      else:
            self.client = httpx.Client()

      # 设置默认请求头
      self.client.headers.update({"ce-clientid": self.request_client_id})

      self.code = None
      self.emailVerificationToken = None
      self.authToken = None
      self.accessToken = None
      self.refreshToken = None
      self.organization_id = None

      self.balance = None
      self.apikey = None

    def __enter__(self):
      return self

    def __exit__(self, exc_type, exc_val, exc_tb):
      self.client.close()

    def register_account(self) -> bool:
      try:
            print(f"\nUsing client ID: {self.request_client_id}")
            response = self.client.post(
                f"{self.BASE_API_URL}/users",
                json={
                  "email": self.email,
                  "password": self.password,
                  "firstName": self.email.split("@"),
                  "organization": {"name": self.email.split("@")},
                },
            )

            if response.status_code != 201:
                print(f"Failed to get emailVerificationToken: {response.status_code}")
                print(response.text)
                return False

            response_json = response.json()
            self.emailVerificationToken = response_json["emailVerificationToken"]
            print(json.dumps(response_json, indent=4))
            return True
      except Exception as e:
            print(f"\nError during account registration: {e}")
            return False

    def retrieve_verification_code(
      self, subject="Confirm your email address", max_attempts=10
    ) -> bool:
      verification_code_pattern = r"\b(\d{6})\b"
      self.code = None

      for i in range(max_attempts):
            print(f"\nWaiting for email code... ({i + 1}/{max_attempts})")
            try:
                emails = self.email_fetcher.fetch_emails(
                  top=5, sender_filter="cluster-engine@gmicloud.ai"
                )
                if emails:
                  latest_email = emails
                  print(
                        f"Body Preview: {latest_email.get('bodyPreview', '').strip()}..."
                  )
                  if latest_email.get("subject") == subject:
                        self.code = self.email_fetcher.extract_verification_code(
                            latest_email, verification_code_pattern
                        )
                        if self.code:
                            print(f"\nVerification code: {self.code}")
                            return True
                time.sleep(3)# Wait before checking again
            except Exception as e:
                print(f"\nError during email retrieval: {e}")
                continue

      print("Failed to retrieve verification code.")
      return False

    def verify_email(self) -> bool:
      """Verify email with the retrieved code.

      Returns:
            bool: True if verification successful, False otherwise
      """
      try:
            response = self.client.post(
                f"{self.BASE_API_URL}/users/email-verification",
                json={
                  "otpCode": self.code,
                },
                headers={
                  "Authorization": f"Bearer {self.emailVerificationToken}",
                },
            ).json()
            print(json.dumps(response, indent=4))

            # Get session ID
            if "id" in response:
                self.session_id = response["id"]
                print(f"\nSession ID: {self.session_id}")
                return True
            else:
                print(f"\nError during email verification: {response}")
                return False
      except Exception as e:
            print(f"\nError during email verification: {e}")
            return False

    def login(self) -> bool:
      self.authToken = None
      try:
            response = self.client.post(
                f"{self.BASE_API_URL}/me/auth-tokens",
                json={
                  "email": self.email,
                  "password": self.password,
                },
            ).json()
            print(json.dumps(response, indent=4))

            # Get organization ID
            self.authToken = response["authToken"]
            print(f"\nAuth Token: {self.authToken}")
            return True
      except Exception as e:
            print(f"\nError during organization creation: {e}")
            return False

    def get_access_token(self) -> bool:
      try:
            response = self.client.post(
                f"{self.BASE_API_URL}/me/sessions",
                json={
                  "authToken": self.authToken,
                  "otpCode": self.code,
                  "type": "native",
                },
            ).json()
            print(json.dumps(response, indent=4))

            self.accessToken = response["accessToken"]
            self.refreshToken = response["refreshToken"]
            print(f"\nAccess Token: {self.accessToken}")
            print(f"\nRefresh Token: {self.refreshToken}")
            return True

      except Exception as e:
            print(f"\nError during email verification: {e}")
            return False

    def get_organization(self) -> bool:
      try:
            response = self.client.get(
                f"{self.BASE_API_URL}/me/profile",
                headers={
                  "Authorization": f"Bearer {self.accessToken}",
                },
            ).json()
            print(json.dumps(response, indent=4))

            self.organization_id = response["organization"]["id"]
            print(f"\nOrganization ID: {self.organization_id}")
            return True

      except Exception as e:
            print(f"\nError during email verification: {e}")
            return False

    def redeem_promotion(self) -> bool:
      try:
            response = self.client.post(
                f"{self.BASE_API_URL}/billing/credit_coupons/INFERENCE/use",
                headers={
                  "Authorization": f"Bearer {self.accessToken}",
                },
            ).json()
            print(json.dumps(response, indent=4))
            valid = response["valid"]

            if valid:
                print(f"\nPromotion redeemed successfully: {valid}")
                return True
            else:
                print(f"\nError during promotion redemption: {response}")
                return False
      except Exception as e:
            print(f"\nError during promotion redemption: {e}")
            return False

    def get_balance(self) -> bool:
      try:
            response = self.client.get(
                f"{self.BASE_API_URL}/billing/balance",
                headers={
                  "Authorization": f"Bearer {self.accessToken}",
                },
            ).json()
            print(json.dumps(response, indent=4))

            self.balance = response["balanceAmount"]
            print(f"\nBalance: {self.balance}")
            return True

      except Exception as e:
            print(f"\nError during balance retrieval: {e}")
            return False

    def create_api_key(self) -> bool:
      try:
            response = self.client.post(
                f"{self.BASE_API_URL}/organizations/{self.organization_id}/api-keys",
                headers={
                  "Authorization": f"Bearer {self.accessToken}",
                },
                json={"name": self.email.split("@"), "type": "ie_model"},
            ).json()
            print(json.dumps(response, indent=4))

            self.apikey = response["key"]
            print(f"\nAPI Key: {self.apikey}")
            return True

      except Exception as e:
            print(f"\nError during API key creation: {e}")
            return False


def save_account_data(account_data: dict) -> None:
    """Save account data to a JSONL file.

    Args:
      account_data: Dictionary containing account information
    """
    try:
      # Add timestamp
      account_data["created_at"] = datetime.datetime.now().isoformat()

      # Append to JSONL file
      with open("gmi_accounts.jsonl", "a", encoding="utf-8") as f:
            f.write(json.dumps(account_data, ensure_ascii=False) + "\n")

    except Exception as e:
      print(f"\nError saving account data: {e}")


def process_account(
    email: str,
    password: str,
    client_id: str,
    refresh_token: str,
    proxy=None,
) -> bool:
    print(f"\nProcessing {email}...")
    if proxy:
      print(f"Using proxy: {proxy}")

    with RequestyClient(email, password, client_id, refresh_token, proxy) as client:
      # Step 2: Register account
      if not client.register_account():
            return False

      # Step 4: Retrieve verification code
      if not client.retrieve_verification_code():
            return False

      # Step 5: Verify email
      if not client.verify_email():
            return False

      # Step 6: Create organization
      if not client.login():
            return False

      # Step 4: Retrieve verification code
      if not client.retrieve_verification_code(
            subject="Two-Factor Authentication verification code"
      ):
            return False

      # Step 7: Get JWT token
      if not client.get_access_token():
            return False

      if not client.get_organization():
            return False

      if not client.redeem_promotion():
            return False

      # Step 8: Get account balance
      if not client.get_balance():
            return False

      # Step 9: Create API key
      if not client.create_api_key():
            return False

      # Save account data
      account_data = {
            "email": email,
            "password": password,
            "client_id": client_id,
            "refresh_token": refresh_token,
            "proxy": proxy,
            "api_key": client.apikey,
            "balance": client.balance,
            "organization_id": client.organization_id,
            "gmi_access_token": client.accessToken,
            "gmi_refresh_token": client.refreshToken,
      }
      save_account_data(account_data)

    return True


def main():
    # Load proxies
    proxies = load_proxies()

    # Process accounts from file
    with open("accounts.txt", "r") as f:
      for line in f:
            try:
                email, password, client_id, refresh_token = line.strip().split("----")
                proxy = get_random_proxy(proxies)
                process_account(email, password, client_id, refresh_token, proxy)
            except Exception as e:
                print(f"\nError processing account: {e}")


if __name__ == "__main__":
    main()


Graph.py

import httpx
import re
import time
import random


# --- Custom Exceptions ---
class EmailFetcherError(Exception):
    """Base exception for EmailFetcher errors."""

    pass


class TokenError(EmailFetcherError):
    """Raised when there's an error obtaining the access token."""

    pass


class GraphApiError(EmailFetcherError):
    """Raised when there's an error during a Microsoft Graph API call."""

    pass


class InvalidRegexError(EmailFetcherError):
    """Raised when the provided regex pattern is invalid."""

    pass


# --- End Custom Exceptions ---


class EmailFetcher:
    BASE_URL = "https://graph.microsoft.com/v1.0"
    TOKEN_URL = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
    MAX_RETRIES = 3# Maximum number of retry attempts
    BASE_RETRY_DELAY = 2# Base delay in seconds

    def __init__(self, client_id, refresh_token):
      self.client_id = client_id
      self.refresh_token = refresh_token
      self.access_token = None

    def _get_access_token(self):
      """Retrieves or refreshes the access token. Raises TokenError on failure."""
      data = {
            "client_id": self.client_id,
            "grant_type": "refresh_token",
            "refresh_token": self.refresh_token,
            "scope": "https://graph.microsoft.com/.default",
      }
      
      retries = 0
      while retries <= self.MAX_RETRIES:
            try:
                response = httpx.post(self.TOKEN_URL, data=data)
               
                # Handle 429 Too Many Requests specifically
                if response.status_code == 429:
                  if retries == self.MAX_RETRIES:
                        error_msg = f"Token request failed after {self.MAX_RETRIES} retries due to rate limiting (429)"
                        print(error_msg)
                        raise TokenError(error_msg)
                  
                  # Get retry-after header if available, otherwise use exponential backoff
                  retry_after = response.headers.get('Retry-After')
                  if retry_after and retry_after.isdigit():
                        delay = int(retry_after)
                  else:
                        # Exponential backoff with jitter
                        delay = self.BASE_RETRY_DELAY * (2 ** retries) + random.uniform(0, 1)
                  
                  print(f"Rate limited (429). Retrying in {delay:.2f} seconds... (Attempt {retries+1}/{self.MAX_RETRIES})")
                  time.sleep(delay)
                  retries += 1
                  continue
               
                response.raise_for_status()# Raise an exception for other bad status codes
                result = response.json()

                if "error" in result:
                  error_msg = f"Access token error: {result.get('error')}, Description: {result.get('error_description')}"
                  print(error_msg)# Also print for immediate feedback
                  raise TokenError(error_msg)

                self.access_token = result.get("access_token")
                if not self.access_token:
                  raise TokenError("No access token found in the response.")
                return self.access_token
               
            except httpx.HTTPStatusError as e:
                # For other HTTP errors that aren't 429
                if e.response.status_code != 429:
                  error_msg = f"Token request failed with status {e.response.status_code}: {e.response.text}"
                  print(error_msg)
                  raise TokenError(error_msg) from e
                # 429 errors are handled in the code above
               
            except httpx.RequestError as e:
                error_msg = f"Token request network error: {e}"
                print(error_msg)
                raise TokenError(error_msg) from e
               
            except Exception as e:
                if isinstance(e, TokenError):
                  raise# Re-raise TokenError without wrapping
                error_msg = f"An unexpected error occurred during token request: {e}"
                print(error_msg)
                raise TokenError(error_msg) from e

    def fetch_emails(self, top=50, sender_filter=None):
      """
      Fetches emails and performs client-side filtering.
      Raises TokenError or GraphApiError on failure.

      Args:
            top: Maximum number of emails to fetch
            sender_filter: Optional email address to filter by (client-side filtering)

      Returns:
            List of filtered email objects
      """
      try:
            if not self.access_token:
                # Attempt to get token, will raise TokenError if it fails
                self._get_access_token()
      except TokenError as e:
            # Re-raise token errors so the caller knows token fetch failed
            raise GraphApiError(
                "Failed to obtain access token before fetching emails."
            ) from e

      # Construct the base URL
      url = f"{self.BASE_URL}/me/messages"

      # Prepare query parameters - only use ordering and top, no server-side filtering
      params = {"$orderby": "receivedDateTime desc", "$top": top}

      headers = {"Authorization": f"Bearer {self.access_token}"}

      retries = 0
      while retries <= self.MAX_RETRIES:
            try:
                response = httpx.get(url, headers=headers, params=params)
               
                # Handle 429 Too Many Requests specifically
                if response.status_code == 429:
                  if retries == self.MAX_RETRIES:
                        error_msg = f"Graph API request failed after {self.MAX_RETRIES} retries due to rate limiting (429)"
                        print(error_msg)
                        raise GraphApiError(error_msg)
                  
                  # Get retry-after header if available, otherwise use exponential backoff
                  retry_after = response.headers.get('Retry-After')
                  if retry_after and retry_after.isdigit():
                        delay = int(retry_after)
                  else:
                        # Exponential backoff with jitter
                        delay = self.BASE_RETRY_DELAY * (2 ** retries) + random.uniform(0, 1)
                  
                  print(f"Rate limited (429). Retrying in {delay:.2f} seconds... (Attempt {retries+1}/{self.MAX_RETRIES})")
                  time.sleep(delay)
                  retries += 1
                  continue
               
                response.raise_for_status()# Check for other HTTP errors
                all_emails = response.json().get("value", [])

                # Perform client-side filtering if a sender filter is specified
                if sender_filter and all_emails:
                  filtered_emails = []
                  for email in all_emails:
                        sender_address = (
                            email.get("from", {}).get("emailAddress", {}).get("address", "")
                        )
                        if (
                            sender_address
                            and sender_filter.lower() in sender_address.lower()
                        ):
                            filtered_emails.append(email)
                  return filtered_emails

                # Return all emails if no filter is specified
                return all_emails

            except httpx.HTTPStatusError as e:
                # For other HTTP errors that aren't 429
                if e.response.status_code != 429:
                  error_msg = f"Graph API request failed with status {e.response.status_code}: {e.response.text}"
                  print(error_msg)
                  # Handle specific errors like token expiry if needed
                  if e.response.status_code == 401:# Unauthorized - token might have expired
                        print(
                            "Access token might be invalid or expired. Clearing token for retry."
                        )
                        self.access_token = None# Clear token
                  raise GraphApiError(error_msg) from e
                # 429 errors are handled in the code above
               
            except httpx.RequestError as e:
                error_msg = f"Graph API request network error: {e}"
                print(error_msg)
                raise GraphApiError(error_msg) from e
               
            except Exception as e:
                error_msg = f"An unexpected error occurred during Graph API request: {e}"
                print(error_msg)
                raise GraphApiError(error_msg) from e

    def extract_verification_code(self, email, pattern):
      """Extracts code using regex. Raises InvalidRegexError or returns None."""
      if not email or not isinstance(email, dict):
            return None

      subject = email.get("subject", "")
      body_preview = email.get("bodyPreview", "")
      body_content = email.get("body", {}).get("content", "")

      try:
            regex = re.compile(pattern)
      except re.error as e:
            error_msg = f"Invalid regex pattern '{pattern}': {e}"
            print(error_msg)
            raise InvalidRegexError(error_msg) from e

      # Search order: subject, body preview, full body
      for text_source in :
            if text_source:# Ensure source is not None or empty
                match = regex.search(text_source)
                if match:
                  # Assuming the code is in the first capture group
                  # If pattern has no groups, match.group(0) is the whole match
                  return match.group(1) if regex.groups >= 1 else match.group(0)

      return None# No code found




页: [1]
查看完整版本: 号商用来挣钱的1脚本