更新 core/LoginServices.py

This commit is contained in:
2025-09-11 12:46:52 +00:00
parent a44c2fce0f
commit 521fefe3f8

View File

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