import requests import json import uuid import platform import hashlib class AuthClient: def __init__(self, base_url): self.base_url = base_url self.stage = 'find-account' self.error = None self.account_identifier = '' self.challenge = None self.factors = [] self.selected_factor_id = None self.password = '' self.user_store = f"SolianForPythonApp/0.000.001({platform.system()})" # 您可以自定义此User-Agent字符串 self.device_id = self.user_store def generate_device_id(self): """生成设备指纹 :return: 设备指纹ID(字符串) """ platform_info = platform.system() + platform.release() + platform.machine() # 修正了这里的拼接错误 unique_id = uuid.getnode() device_info = f"{platform_info}-{unique_id}" # 使用SHA-256哈希生成设备ID self.device_id = hashlib.sha256(device_info.encode()).hexdigest() return self.device_id def check_account_validity(self, account_identifier): """检查账户有效性 :param account_identifier: 用户的账户标识符(邮箱或用户名) :return: 挑战信息(字典) """ self.account_identifier = account_identifier self.error = None if not self.account_identifier: self.error = 'Please enter your email or username.' return None try: response = requests.post( f"{self.base_url}/auth/challenge", headers={'Content-Type': 'application/json', 'User-Agent': self.user_store,"device_id":self.device_id}, # 添加自定义User-Agent data=json.dumps({ 'platform': 1, 'account': self.account_identifier, 'device_id': self.generate_device_id(), }) ) if not response.ok: raise Exception(response.text or 'Account not found.') self.challenge = response.json() self.stage = 'select-factor' return self.challenge except Exception as e: self.error = str(e) return None def get_authentication_factors(self): """获取可用的认证因素 :return: 可用的认证因素列表(列表) """ self.error = None if not self.challenge: self.error = 'No challenge information available.' return None try: response = requests.get( f"{self.base_url}/auth/challenge/{self.challenge['id']}/factors", headers={'User-Agent': self.user_store,"device_id":self.device_id} # 添加自定义User-Agent ) if not response.ok: raise Exception('Could not fetch authentication factors.') available_factors = response.json() self.factors = [factor for factor in available_factors if factor['id'] not in self.challenge.get('blacklist_factors', [])] if len(self.factors) == 0: self.error = 'No available authentication factors.' return None else: self.stage = 'select-factor' return self.factors except Exception as e: self.error = str(e) return None def request_verification_code(self, selected_factor_id): """请求验证码 :param selected_factor_id: 用户选择的认证因素ID(字符串类型) :return: None """ self.selected_factor_id = selected_factor_id self.error = None if not self.selected_factor_id: self.error = 'No authentication factor selected.' return None selected_factor = self.get_selected_factor() if not selected_factor: self.error = 'Selected factor not found.' return None hint = {'contact': selected_factor['contact']} try: response = requests.post( f"{self.base_url}/auth/challenge/{self.challenge['id']}/factors/{self.selected_factor_id}", headers={'Content-Type': 'application/json', 'User-Agent': self.user_store,"device_id":self.device_id}, # 添加自定义User-Agent data=json.dumps(hint) ) if not response.ok: raise Exception(response.text or 'Failed to send code.') self.stage = 'enter-code' except Exception as e: self.error = str(e) self.stage = 'select-factor' return None def get_selected_factor(self): """获取选择的认证因素 :return: 选择的认证因素(字典)或 None """ if not self.selected_factor_id: return None return next((factor for factor in self.factors if factor['id'] == self.selected_factor_id), None) def verify_factor(self, selected_factor_id, password): """验证所选的认证因素 :param selected_factor_id: 用户选择的认证因素ID(字符串类型) :param password: 用户输入的密码或验证码(字符串类型) :return: None """ self.selected_factor_id = selected_factor_id self.password = password self.error = None if not self.selected_factor_id or not self.password: self.error = 'Please enter your password/code.' return None try: response = requests.patch( f"{self.base_url}/auth/challenge/{self.challenge['id']}", headers={'Content-Type': 'application/json', 'User-Agent': self.user_store,"device_id":self.device_id}, # 添加自定义User-Agent data=json.dumps({ 'factor_id': self.selected_factor_id, 'password': self.password, }) ) if not response.ok: raise Exception(response.text or 'Verification failed.') self.challenge = response.json() self.password = '' if self.challenge['step_remain'] == 0: self.stage = 'token-exchange' else: self.stage = 'select-factor' except Exception as e: self.error = str(e) self.stage = 'select-factor' def exchange_token(self): """交换令牌以完成登录 :return: None """ self.error = None if not self.challenge: self.error = 'No challenge information available.' return None try: response = requests.post( f"{self.base_url}/auth/token", headers={'Content-Type': 'application/json', 'User-Agent': self.user_store,"device_id":self.device_id}, # 添加自定义User-Agent data=json.dumps({ 'grant_type': 'authorization_code', 'code': self.challenge['id'], }) ) if not response.ok: raise Exception(response.text or 'Token exchange failed.') token_info = response.json() token = token_info['token'] #self.user_store.fetchUser() redirect_uri = 'redirect_uri_from_query' # 这里需要根据实际情况获取 if redirect_uri: print(f"Redirecting to: {redirect_uri}") else: print("Navigating to home page.") return token except Exception as e: self.error = str(e) self.stage = 'select-factor' def get_factor_name(self, factor_type): """根据认证因素类型返回相应的名称 :param factor_type: 认证因素类型(整数) :return: 认证因素名称(字符串) """ factor_names = { 0: 'Password', 1: 'Email', 2: 'Authenticator App', } return factor_names.get(factor_type, 'Unknown Factor') # 示例调用 if __name__ == "__main__": auth_client = AuthClient(base_url='https://api.solian.app/id') account_identifier = 'nanci'#你的账号 selected_factor_id = "enter-code" # 用户需要选择一个因素 password = ''#你的密码 # 第一步:检查账户有效性 challenge = auth_client.check_account_validity(account_identifier) if auth_client.error: print(f"Error in check account validity: {auth_client.error}") elif challenge: print(f"Challenge information: {challenge}") # 第二步:获取可用的认证因素 factors = auth_client.get_authentication_factors() if auth_client.error: print(f"Error in get authentication factors: {auth_client.error}") elif factors: print(f"Available factors: {factors}") # 假设用户选择第一个因素 selected_factor_id = factors[0]['id'] print(f"Selected factor ID: {selected_factor_id}") # 第三步:请求验证码(如果需要) if factors[0]['type'] == 1: auth_client.request_verification_code(selected_factor_id) if auth_client.error: print(f"Error in request verification code: {auth_client.error}") elif auth_client.stage == 'enter-code': print("Verification code requested. Please enter the code.") # 第四步:验证所选的认证因素 auth_client.verify_factor(selected_factor_id, password) if auth_client.error: print(f"Error in verify factor: {auth_client.error}") elif auth_client.stage == 'token-exchange': print("Factor verified. Ready to exchange token.") # 第五步:交换令牌以完成登录 if auth_client.stage == 'token-exchange': token = auth_client.exchange_token() if auth_client.error: print(f"Error in exchange token: {auth_client.error}") else: print("Login successful!") print(f"Token: {token}") else: print("Login failed.") else: print("No available authentication factors.")