Files
qinglong/脚本库/APP版/抓包/cloud_auth/2025-09-23_cloud_auth_eb2f681e.py
2026-05-24 05:33:05 +00:00

277 lines
15 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Source: https://github.com/3ixi/CodeScripts/blob/main/cloud_auth.py
# Raw: https://raw.githubusercontent.com/3ixi/CodeScripts/main/cloud_auth.py
# Repo: 3ixi/CodeScripts
# Path: cloud_auth.py
# UploadedAt: 2025-09-23T14:07:43+08:00
# SHA256: eb2f681e407a991c4a909c9f58a74cd58726b3204bbaa0f721a9fc015d53551c
# Category: APP版/抓包
# Evidence: cookie/token/authorization/header
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
3iXi云函数认证模块
用于与3iXi认证服务器进行安全通信云端加密敏感信息
创建日期2025-09-08
模块作者3iXi
项目主页https://github.com/3ixi/CloudScripts
获取授权码https://3ixi.top
安全说明:
- 本模块仅用于与云函数认证服务器进行安全通信
- 不会收集或上传用户的个人账号数据
- 所有敏感信息均在云端加密处理
- 仅传输必要的认证信息,保护用户隐私
"""
import os
import json
import time
import uuid
import base64
import sys
from datetime import datetime, timezone, timedelta
def check_required_packages():
missing_packages = []
try:
import requests
except ImportError:
missing_packages.append('requests')
try:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
except ImportError:
missing_packages.append('pycryptodome')
if missing_packages:
print("❌ 缺少必需的依赖库,请安装以下库:")
print()
for package in missing_packages:
print(f" pip install {package}")
print()
print("安装完成后请重新运行脚本。")
sys.exit(1)
check_required_packages()
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
PRIMARY_BASE_URL = "https://3ixi.top"
BACKUP_BASE_URL = "https://cloud.3ixi.top"
class CloudAuth:
def __init__(self):
self.base_urls = [PRIMARY_BASE_URL, BACKUP_BASE_URL]
self.current_url_index = 0
self.auth_code = None
self.session = requests.Session()
self._load_auth_code()
if self.auth_code:
self._verify_auth_code()
def _set_connection(self):
key_fragments = {
'prefix': 'QGp3','middle1': 'PFUk','middle2': 'MERJYmQp','suffix': 'ZW4pPw==',}
sequence = ['prefix', 'middle1', 'middle2', 'suffix']
encoded_key = ''.join([key_fragments[part] for part in sequence])
try:
decoded_key = base64.b64decode(encoded_key).decode('utf-8')
if len(decoded_key) == 16:
return decoded_key
except:
pass
backup_data = [64, 106, 119, 60, 85, 36, 48, 68, 73, 98, 100, 41, 101, 110, 41, 63]
return ''.join([chr(x) for x in backup_data])
def _switch_to_next_url(self):
self.current_url_index = (self.current_url_index + 1) % len(self.base_urls)
return self.base_urls[self.current_url_index]
def _get_current_url(self):
return self.base_urls[self.current_url_index].rstrip('/')
def _load_auth_code(self):
self.auth_code = os.getenv('CloudAuth')
if not self.auth_code:
raise ValueError("未找到环境变量'CloudAuth'请访问https://3ixi.top获取授权码")
try:
uuid.UUID(self.auth_code)
except ValueError:
raise ValueError("授权码格式无效请访问https://3ixi.top重新获取")
def _get_timestamp(self):
timestamp_ms = int(time.time() * 1000)
timestamp_bytes = timestamp_ms.to_bytes(8, byteorder='big') + b'\x00' * 8
return timestamp_bytes, timestamp_ms
def _aes_encrypt(self, data):
timestamp_data, timestamp_ms = self._get_timestamp()
cipher = AES.new(self._set_connection().encode('utf-8'), AES.MODE_CBC, timestamp_data)
padded_data = pad(data.encode('utf-8'), AES.block_size)
encrypted_data = cipher.encrypt(padded_data)
encrypted_b64 = base64.b64encode(encrypted_data).decode('utf-8')
random_hex = hex(timestamp_ms)[2:]
return encrypted_b64, random_hex
def _aes_decrypt(self, encrypted_data, random_hex):
timestamp_ms = int(random_hex, 16)
timestamp_bytes = timestamp_ms.to_bytes(8, byteorder='big') + b'\x00' * 8
cipher = AES.new(self._set_connection().encode('utf-8'), AES.MODE_CBC, timestamp_bytes)
encrypted_bytes = base64.b64decode(encrypted_data)
decrypted_padded = cipher.decrypt(encrypted_bytes)
decrypted_data = unpad(decrypted_padded, AES.block_size)
return decrypted_data.decode('utf-8')
def _make_request(self, endpoint, data=None, method='POST'):
if data is None:
data = {}
data['auth_code'] = self.auth_code
json_data = json.dumps(data, ensure_ascii=False)
encrypted_data, random_hex = self._aes_encrypt(json_data)
headers = {
'Content-Type': 'application/json',
'random': random_hex
}
for _ in range(len(self.base_urls)):
current_url = self._get_current_url()
url = f"{current_url}{endpoint}"
try:
if method.upper() == 'GET':
response = self.session.get(url, headers=headers, timeout=30)
else:
response = self.session.post(url, json={'data': encrypted_data}, headers=headers, timeout=30)
response.raise_for_status()
response_data = response.json()
if 'data' in response_data:
decrypted_response = self._aes_decrypt(response_data['data'], random_hex)
return json.loads(decrypted_response)
else:
return response_data
except requests.RequestException as e:
print(f"请求失败: {e}")
self._switch_to_next_url()
print(f"尝试切换到备用地址")
except json.JSONDecodeError as e:
print(f"响应解析失败: {e}")
self._switch_to_next_url()
print(f"尝试切换到备用地址")
except Exception as e:
print(f"解密失败: {e}")
self._switch_to_next_url()
print(f"尝试切换到备用地址")
raise Exception("所有服务器地址均请求失败,请检查网络连接或服务器状态")
def _verify_auth_code(self):
try:
response = self._make_request('/api/verify')
if response.get('success'):
expire_date = response.get('expire_date')
if expire_date:
china_tz = timezone(timedelta(hours=8))
expire_dt = datetime.fromisoformat(expire_date.replace('Z', '+00:00'))
china_time = expire_dt.astimezone(china_tz)
print(f"📅 授权码截止日期: {china_time.strftime('%Y-%m-%d %H:%M:%S')}")
else:
print("✅ 授权码验证成功,但未获取到截止日期")
notifications = response.get('notifications', [])
if notifications:
print("\n" + "="*30)
print("📢 系统通知:")
for i, notification in enumerate(notifications, 1):
title = notification.get('title', '无标题')
content = notification.get('content', '无内容')
print(f"\n{i}. {title}")
print(f" {content}")
print("="*30)
else:
error_msg = response.get('error', '未知错误')
if '禁用' in error_msg:
disable_reason = response.get('disable_reason', '未知原因')
disabled_at = response.get('disabled_at', '')
print(f"❌ 授权码已被禁用")
print(f"📝 禁用原因: {disable_reason}")
if disabled_at:
try:
china_tz = timezone(timedelta(hours=8))
disabled_dt = datetime.fromisoformat(disabled_at.replace('Z', '+00:00'))
china_time = disabled_dt.astimezone(china_tz)
print(f"⏰ 禁用时间: {china_time.strftime('%Y-%m-%d %H:%M:%S')}")
except:
print(f"⏰ 禁用时间: {disabled_at}")
else:
print(f"❌ 授权码验证失败: {error_msg}")
raise Exception(f"授权码验证失败: {error_msg}")
except Exception as e:
if "授权码验证失败:" not in str(e):
print(f"❌ 授权码验证失败: {e}")
raise
def call_service(self, service_name, **kwargs):
data = {
'mod': service_name,
**kwargs
}
try:
response = self._make_request('/api/service', data)
if response.get('success'):
return response
else:
error_msg = response.get('error', '未知错误')
raise Exception(f"{service_name}服务调用失败: {error_msg}")
except Exception as e:
print(f"{service_name}服务调用失败: {e}")
raise
def get_auth_client():
return CloudAuth()
def call_service(service_name, **kwargs):
client = get_auth_client()
return client.call_service(service_name, **kwargs)
if __name__ == "__main__":
print("3iXi认证模块")
print("=" * 30)
print("访问https://3ixi.top获取授权码")