mirror of
https://github.com/nihilvux/bancho.py.git
synced 2025-09-26 07:06:35 -07:00
134 lines
4.1 KiB
Python
134 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import TypedDict
|
|
from typing import cast
|
|
|
|
from sqlalchemy import CHAR
|
|
from sqlalchemy import Column
|
|
from sqlalchemy import DateTime
|
|
from sqlalchemy import Integer
|
|
from sqlalchemy import func
|
|
from sqlalchemy import or_
|
|
from sqlalchemy import select
|
|
from sqlalchemy.dialects.mysql import Insert as MysqlInsert
|
|
from sqlalchemy.dialects.mysql import insert as mysql_insert
|
|
from sqlalchemy.sql import ColumnElement
|
|
from sqlalchemy.types import Boolean
|
|
|
|
import app.state.services
|
|
from app.repositories import Base
|
|
from app.repositories.users import UsersTable
|
|
|
|
|
|
class ClientHashesTable(Base):
|
|
__tablename__ = "client_hashes"
|
|
|
|
userid = Column("userid", Integer, nullable=False, primary_key=True)
|
|
osupath = Column("osupath", CHAR(32), nullable=False, primary_key=True)
|
|
adapters = Column("adapters", CHAR(32), nullable=False, primary_key=True)
|
|
uninstall_id = Column("uninstall_id", CHAR(32), nullable=False, primary_key=True)
|
|
disk_serial = Column("disk_serial", CHAR(32), nullable=False, primary_key=True)
|
|
latest_time = Column("latest_time", DateTime, nullable=False)
|
|
occurrences = Column("occurrences", Integer, nullable=False, server_default="0")
|
|
|
|
|
|
READ_PARAMS = (
|
|
ClientHashesTable.userid,
|
|
ClientHashesTable.osupath,
|
|
ClientHashesTable.adapters,
|
|
ClientHashesTable.uninstall_id,
|
|
ClientHashesTable.disk_serial,
|
|
ClientHashesTable.latest_time,
|
|
ClientHashesTable.occurrences,
|
|
)
|
|
|
|
|
|
class ClientHash(TypedDict):
|
|
userid: int
|
|
osupath: str
|
|
adapters: str
|
|
uninstall_id: str
|
|
disk_serial: str
|
|
latest_time: datetime
|
|
occurrences: int
|
|
|
|
|
|
class ClientHashWithPlayer(ClientHash):
|
|
name: str
|
|
priv: int
|
|
|
|
|
|
async def create(
|
|
userid: int,
|
|
osupath: str,
|
|
adapters: str,
|
|
uninstall_id: str,
|
|
disk_serial: str,
|
|
) -> ClientHash:
|
|
"""Create a new client hash entry in the database."""
|
|
insert_stmt: MysqlInsert = (
|
|
mysql_insert(ClientHashesTable)
|
|
.values(
|
|
userid=userid,
|
|
osupath=osupath,
|
|
adapters=adapters,
|
|
uninstall_id=uninstall_id,
|
|
disk_serial=disk_serial,
|
|
latest_time=func.now(),
|
|
occurrences=1,
|
|
)
|
|
.on_duplicate_key_update(
|
|
latest_time=func.now(),
|
|
occurrences=ClientHashesTable.occurrences + 1,
|
|
)
|
|
)
|
|
|
|
await app.state.services.database.execute(insert_stmt)
|
|
|
|
select_stmt = (
|
|
select(*READ_PARAMS)
|
|
.where(ClientHashesTable.userid == userid)
|
|
.where(ClientHashesTable.osupath == osupath)
|
|
.where(ClientHashesTable.adapters == adapters)
|
|
.where(ClientHashesTable.uninstall_id == uninstall_id)
|
|
.where(ClientHashesTable.disk_serial == disk_serial)
|
|
)
|
|
client_hash = await app.state.services.database.fetch_one(select_stmt)
|
|
|
|
assert client_hash is not None
|
|
return cast(ClientHash, client_hash)
|
|
|
|
|
|
async def fetch_any_hardware_matches_for_user(
|
|
userid: int,
|
|
running_under_wine: bool,
|
|
adapters: str,
|
|
uninstall_id: str,
|
|
disk_serial: str | None = None,
|
|
) -> list[ClientHashWithPlayer]:
|
|
"""\
|
|
Fetch a list of matching hardware addresses where any of
|
|
`adapters`, `uninstall_id` or `disk_serial` match other users
|
|
from the database.
|
|
"""
|
|
select_stmt = (
|
|
select(*READ_PARAMS, UsersTable.name, UsersTable.priv)
|
|
.join(UsersTable, ClientHashesTable.userid == UsersTable.id)
|
|
.where(ClientHashesTable.userid != userid)
|
|
)
|
|
|
|
if running_under_wine:
|
|
select_stmt = select_stmt.where(ClientHashesTable.uninstall_id == uninstall_id)
|
|
else:
|
|
# make disk serial optional in the OR
|
|
oneof_filters: list[ColumnElement[Boolean]] = []
|
|
oneof_filters.append(ClientHashesTable.adapters == adapters)
|
|
oneof_filters.append(ClientHashesTable.uninstall_id == uninstall_id)
|
|
if disk_serial is not None:
|
|
oneof_filters.append(ClientHashesTable.disk_serial == disk_serial)
|
|
select_stmt = select_stmt.where(or_(*oneof_filters))
|
|
|
|
client_hashes = await app.state.services.database.fetch_all(select_stmt)
|
|
return cast(list[ClientHashWithPlayer], client_hashes)
|