更新 core/LoginServices.py
This commit is contained in:
@@ -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.")
|
Reference in New Issue
Block a user