🍻 实验性加入fpdeviceid支持

This commit is contained in:
Wuyi无疑 2023-05-23 00:57:14 +08:00
parent ed846b5851
commit 23c499c82b
7 changed files with 126 additions and 18 deletions

View File

@ -134,4 +134,6 @@ CALENDAR_URL = f'{DRAW_BASE_URL}/calendar'
RECEIVE_URL = f'{DRAW_BASE_URL}/post_my_draw'
BS_INDEX_URL = f'{DRAW_BASE_URL}/index'
GET_FP_URL = 'https://public-data-api.mihoyo.com/device-fp/api/getFp'
_API = locals()

View File

@ -14,6 +14,7 @@ from typing import Any, Dict, List, Tuple, Union, Literal, Optional, cast
from aiohttp import TCPConnector, ClientSession, ContentTypeError
from gsuid_core.logger import logger
from gsuid_core.utils.database.api import DBSqla
from gsuid_core.utils.plugins_config.gs_config import core_plugins_config
from .api import _API
@ -88,6 +89,7 @@ class BaseMysApi:
is_sr = False
RECOGNIZE_SERVER = RECOGNIZE_SERVER
chs = {}
dbsqla: DBSqla = DBSqla()
@abstractmethod
async def _upass(self, header: Dict) -> str:
@ -109,6 +111,59 @@ class BaseMysApi:
async def get_stoken(self, uid: str) -> Optional[str]:
...
@abstractmethod
async def get_user_fp(self, uid: str) -> Optional[str]:
...
@abstractmethod
async def get_user_device_id(self, uid: str) -> Optional[str]:
...
def get_device_id(self) -> str:
device_id = uuid.uuid4().hex
return device_id
def generate_seed(self, length: int):
characters = '0123456789abcdef'
result = ''.join(random.choices(characters, k=length))
return result
async def generate_fp_by_uid(self, uid: str) -> str:
seed_id = self.generate_seed(16)
seed_time = str(int(time.time() * 1000))
ext_fields = f'{{"userAgent":"{self._HEADER["User-Agent"]}",\
"browserScreenSize":281520,"maxTouchPoints":5,\
"isTouchSupported":true,"browserLanguage":"zh-CN","browserPlat":"iPhone",\
"browserTimeZone":"Asia/Shanghai","webGlRender":"Apple GPU",\
"webGlVendor":"Apple Inc.",\
"numOfPlugins":0,"listOfPlugins":"unknown","screenRatio":3,"deviceMemory":"unknown",\
"hardwareConcurrency":"4","cpuClass":"unknown","ifNotTrack":"unknown","ifAdBlock":0,\
"hasLiedResolution":1,"hasLiedOs":0,"hasLiedBrowser":0}}'
body = {
'seed_id': seed_id,
'device_id': await self.get_user_device_id(uid),
'platform': '5',
'seed_time': seed_time,
'ext_fields': ext_fields,
'app_name': 'account_cn',
'device_fp': '38d7ee834d1e9',
}
HEADER = copy.deepcopy(self._HEADER)
res = await self._mys_request(
url=self.MAPI['GET_FP_URL'],
method='POST',
header=HEADER,
data=body,
)
if not isinstance(res, Dict):
logger.error(f"获取fp连接失败{res}")
return random_hex(13).lower()
elif res["data"]["code"] != 200:
logger.error(f"获取fp参数不正确{res['data']['msg']}")
return random_hex(13).lower()
else:
return res["data"]["device_fp"]
async def simple_mys_req(
self,
URL: str,
@ -200,8 +255,15 @@ class BaseMysApi:
connector=TCPConnector(verify_ssl=ssl_verify)
) as client:
raw_data = {}
uid = None
if params and 'role_id' in params:
uid = params['role_id']
header['x-rpc-device_id'] = await self.get_user_device_id(uid)
header['x-rpc-device_fp'] = await self.get_user_fp(uid)
for _ in range(2):
if 'Cookie' in header and header['Cookie'] in self.chs:
# header['x-rpc-challenge']=self.chs.pop(header['Cookie'])
if self.is_sr:
header['x-rpc-challenge'] = self.chs.pop(
header['Cookie']
@ -216,6 +278,7 @@ class BaseMysApi:
header['x-rpc-page'] = (
'3.1.3_#/rpg' if self.is_sr else '3.1.3_#/ys'
)
async with client.request(
method,
url=url,
@ -244,6 +307,11 @@ class BaseMysApi:
if retcode == 1034:
ch = await self._upass(header)
self.chs[header['Cookie']] = ch
elif retcode == -10001 and uid:
sqla = self.dbsqla.get_sqla('TEMP')
new_fp = await self.generate_fp_by_uid(uid)
await sqla.update_user_data(uid, {'fp': new_fp})
header['x-rpc-device_fp'] = new_fp
elif retcode != 0:
return retcode
else:

View File

@ -1,15 +1,12 @@
from typing import Literal, Optional
from gsuid_core.utils.api.mys import MysApi
from gsuid_core.utils.database.api import DBSqla
from gsuid_core.utils.plugins_config.gs_config import core_plugins_config
gsconfig = core_plugins_config
class _MysApi(MysApi):
dbsqla: DBSqla = DBSqla()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@ -24,5 +21,23 @@ class _MysApi(MysApi):
async def get_stoken(self, uid: str) -> Optional[str]:
return await self.dbsqla.get_sqla('TEMP').get_user_stoken(uid)
async def get_user_fp(self, uid: str) -> Optional[str]:
data = await self.dbsqla.get_sqla('TEMP').get_user_fp(uid)
if data is None:
data = await self.generate_fp_by_uid(uid)
await self.dbsqla.get_sqla('TEMP').update_user_data(
uid, {'fp': data}
)
return data
async def get_user_device_id(self, uid: str) -> Optional[str]:
data = await self.dbsqla.get_sqla('TEMP').get_user_device_id(uid)
if data is None:
data = self.get_device_id()
await self.dbsqla.get_sqla('TEMP').update_user_data(
uid, {'device_id': data}
)
return data
mys_api = _MysApi()

View File

@ -236,8 +236,16 @@ async def _deal_ck(bot_id: str, mes: str, user_id: str) -> str:
if uid is None:
uid = '0'
device_id = mys_api.get_device_id()
fp = await mys_api.generate_fp_by_uid(uid)
await sqla.insert_user_data(
user_id, uid_bind, sr_uid_bind, account_cookie, app_cookie
user_id,
uid_bind,
sr_uid_bind,
account_cookie,
app_cookie,
fp,
device_id,
)
im_list.append(

View File

@ -1,6 +1,5 @@
import re
import asyncio
import contextlib
from typing import Dict, List, Literal, Optional
from sqlmodel import SQLModel
@ -43,13 +42,17 @@ class SQLA:
'ALTER TABLE GsBind ADD COLUMN sr_uid TEXT',
'ALTER TABLE GsUser ADD COLUMN sr_uid TEXT',
'ALTER TABLE GsUser ADD COLUMN sr_region TEXT',
'ALTER TABLE GsUser ADD COLUMN fp TEXT',
'ALTER TABLE GsUser ADD COLUMN device_id TEXT',
'ALTER TABLE GsCache ADD COLUMN sr_uid TEXT',
]
with contextlib.suppress(Exception):
async with self.async_session() as session:
for _t in exec_list:
async with self.async_session() as session:
for _t in exec_list:
try:
await session.execute(text(_t))
await session.commit()
await session.commit()
except: # noqa: E722
pass
#####################
# GsBind 部分 #
@ -244,6 +247,14 @@ class SQLA:
await session.execute(sql)
return True
async def get_user_fp(self, uid: str) -> Optional[str]:
data = await self.select_user_data(uid)
return data.fp if data else None
async def get_user_device_id(self, uid: str) -> Optional[str]:
data = await self.select_user_data(uid)
return data.device_id if data else None
async def insert_cache_data(
self,
cookie: str,
@ -267,6 +278,8 @@ class SQLA:
sr_uid: Optional[str] = None,
cookie: Optional[str] = None,
stoken: Optional[str] = None,
fp: Optional[str] = None,
device_id: Optional[str] = None,
) -> bool:
async with self.async_session() as session:
async with session.begin():
@ -281,6 +294,7 @@ class SQLA:
bot_id=self.bot_id,
user_id=user_id,
sr_uid=sr_uid,
fp=fp,
)
)
await session.execute(sql)
@ -295,6 +309,7 @@ class SQLA:
bot_id=self.bot_id,
user_id=user_id,
uid=uid,
fp=fp,
)
)
await session.execute(sql)
@ -321,6 +336,8 @@ class SQLA:
sr_region=SR_SERVER.get(sr_uid[0], None)
if sr_uid
else None,
fp=fp,
device_id=device_id,
)
session.add(user_data)
await session.commit()
@ -330,13 +347,9 @@ class SQLA:
async with self.async_session() as session:
async with session.begin():
sql = (
update(GsUser).where(
GsUser.sr_uid == uid, GsUser.bot_id == self.bot_id
)
update(GsUser).where(GsUser.sr_uid == uid)
if self.is_sr
else update(GsUser).where(
GsUser.uid == uid, GsUser.bot_id == self.bot_id
)
else update(GsUser).where(GsUser.uid == uid)
)
if data is not None:
query = sql.values(**data)

View File

@ -29,6 +29,8 @@ class GsUser(SQLModel, table=True):
sign_switch: str = Field(title='自动签到')
bbs_switch: str = Field(title='自动米游币')
status: Optional[str] = Field(default=None, title='状态')
fp: Optional[str] = Field(default=None, title='Fingerprint')
device_id: Optional[str] = Field(default=None, title='设备ID')
class GsCache(SQLModel, table=True):

6
poetry.lock generated
View File

@ -1486,14 +1486,14 @@ reference = "mirrors"
[[package]]
name = "nodeenv"
version = "1.7.0"
version = "1.8.0"
description = "Node.js virtual environment builder"
category = "dev"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
files = [
{file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"},
{file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"},
{file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"},
{file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"},
]
[package.dependencies]