diff --git a/core/AccountServices.py b/core/LoginServices.py similarity index 97% rename from core/AccountServices.py rename to core/LoginServices.py index 76324d9..82319f5 100644 --- a/core/AccountServices.py +++ b/core/LoginServices.py @@ -1,246 +1,246 @@ -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.device_id = '' - self.challenge = None - self.factors = [] - self.selected_factor_id = None - self.password = '' - self.user_store = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3' # 您可以自定义此User-Agent字符串 - - 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_name': "A Python login app.By NRFF & Deepseek"}, # 添加自定义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_name': "A Python login app.By NRFF & Deepseek"} # 添加自定义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_name': "A Python login app.By NRFF & Deepseek"}, # 添加自定义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_name': "A Python login app.By NRFF & Deepseek"}, # 添加自定义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_name': "A Python login app.By NRFF & Deepseek"}, # 添加自定义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 = ''#你的账号 - 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.") +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.device_id = '' + self.challenge = None + self.factors = [] + self.selected_factor_id = None + self.password = '' + self.user_store = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3' # 您可以自定义此User-Agent字符串 + + 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_name': "A Python login app.By NRFF & Deepseek"}, # 添加自定义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_name': "A Python login app.By NRFF & Deepseek"} # 添加自定义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_name': "A Python login app.By NRFF & Deepseek"}, # 添加自定义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_name': "A Python login app.By NRFF & Deepseek"}, # 添加自定义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_name': "A Python login app.By NRFF & Deepseek"}, # 添加自定义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 = ''#你的账号 + 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.")