cleaned up auth (only use supabase)

This commit is contained in:
Pascal P. 2026-08-06 08:40:31 +02:00
parent b396602dee
commit c02f08a767
5 changed files with 138 additions and 56 deletions

View File

@ -0,0 +1,7 @@
TODO:
- [ ] Schedule opening
- [ ] Notification
- [ ] Complete API (for selling)
- [ ] Add a scoring for cards pulled
- [ ] Multiusers

View File

@ -5,6 +5,7 @@ description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"apscheduler>=3.11.3",
"dotenv>=0.9.9",
"httpx>=0.28.1",
"loguru>=0.7.3",

View File

@ -4,9 +4,10 @@ from loguru import logger
from pathlib import Path
# from sqlalchemy import create_engine
from .lib.utils import EveryRunRotator
from .lib.utils import EveryRunRotator, HumanReadable as hr
from .services.wiki_masters import WikiMastersClient
from dotenv import load_dotenv
from datetime import datetime, timedelta, timezone
class App:
@ -42,8 +43,38 @@ class App:
load_dotenv()
truc = WikiMastersClient()
truc.login(environ.get("ACCOUNT_EMAIL"), environ.get("ACCOUNT_PASSWORD"))
wm_client = WikiMastersClient()
user = wm_client.login(
environ.get("ACCOUNT_EMAIL"), environ.get("ACCOUNT_PASSWORD")
)
d = user.sync()
logger.debug("sync user {}", d.username)
packs_remaining = d.packs_remaining
packs_last_regen_at = d.packs_last_regen_at
if packs_remaining == 10:
packs_remaining, packs_last_regen_at = wm_client.open_pack(
user.auth_cookies
)
# Does this math still works when we are opening the 9th pack ?
next_pack_in = WikiMastersClient.ONE_PACK_TIME - (
datetime.now(tz=timezone.utc) - packs_last_regen_at
)
next_run_in = (
next_pack_in
+ WikiMastersClient.ONE_PACK_TIME * (9 - packs_remaining)
- timedelta(seconds=10)
)
logger.info(
"Next pack is in {}",
hr.seconds_to_human(next_pack_in.total_seconds()),
)
logger.debug(
"We should schedule in {}", hr.seconds_to_human(next_run_in.total_seconds())
)
async def main():

View File

@ -1,9 +1,11 @@
import httpx
from dataclasses import dataclass
from supabase import create_client, Client
from supabase_auth import Session
from loguru import logger
from datetime import datetime, timedelta, timezone
from datetime import datetime, timedelta
from ..lib.supabase_cookie import get_auth_cookies
from ..lib.utils import HumanReadable as hr
from typing import Self
# supabase ?
# https://cyrxjeppjqsxxjayfrur.supabase.co/auth/v1/token?grant_type=password
# https://cyrxjeppjqsxxjayfrur.supabase.co/auth/v1/user
@ -11,6 +13,44 @@ from ..lib.utils import HumanReadable as hr
# https://cyrxjeppjqsxxjayfrur.supabase.co/rest/v1/rpc/sync_profile_packs
@dataclass
class SyncDataSubset:
_id: str
username: str
packs_remaining: int
packs_last_regen_at: datetime
@staticmethod
def from_json(d: dict) -> Self:
return SyncDataSubset(
d["id"],
d["username"],
d["packs_remaining"],
datetime.fromisoformat(d["packs_last_regen_at"]),
)
@dataclass
class UserSession:
username: str
sb_client: Client
@property
def auth_cookies(self):
return get_auth_cookies(self.session.model_dump_json().encode("utf-8"))
@property
def session(self):
return self.sb_client.auth.get_session()
def sync(self) -> SyncDataSubset:
response = self.sb_client.postgrest.rpc(
"sync_profile_packs", {"user_id": self.session.user.id}
).execute()
return SyncDataSubset.from_json(response.data[0])
class WikiMastersClient:
BASE_URL = "https://www.wiki-masters.com"
@ -22,12 +62,9 @@ class WikiMastersClient:
def __init__(self) -> None:
self.logger = logger.bind(service=self.__class__.__name__)
self.users: dict[str, UserSession] = {}
self.logger.info("creating client for supabase")
self.sb_client: Client = create_client(self.SUPABASE_URL, self.SUPABASE_KEY)
self.logger.info("done creating client for supabase: {}", self.sb_client)
def open_pack(self, cookies):
def open_pack(self, cookies) -> tuple[int, str]:
url = f"{self.BASE_URL}/api/packs/open"
logger.debug("trying to request a pull (cookies:{})", cookies)
@ -37,57 +74,28 @@ class WikiMastersClient:
cookies=cookies,
)
if response.status_code == 200:
logger.debug("trying to pull: {}", response.json())
else:
if response.status_code != 200:
logger.error(
"error while opening [{}] {}", response.status_code, response.content
)
raise Exception("Could not pull :'(")
def login(self, email, password):
url = f"{self.SUPABASE_URL}/auth/v1/token?grant_type=password"
response = httpx.post(
url,
json={"email": email, "password": password, "gotrue_meta_security": {}},
headers={
"ApiKey": self.SUPABASE_KEY,
"Authorization": f"Bearer {self.SUPABASE_KEY}",
},
pull_data = response.json()
logger.debug("trying to pull: {}", pull_data)
return (pull_data["packs_remaining"], datetime.fromisoformat(pull_data["packs_last_regen_at"]))
def login(self, email, password) -> UserSession:
sb_client = create_client(self.SUPABASE_URL, self.SUPABASE_KEY)
response = sb_client.auth.sign_in_with_password(
{"email": email, "password": password}
)
logger.debug("trying to login {}", response)
if response.status_code == 200:
cookies_compute = get_auth_cookies(response.content)
# TODO: save cookies for the current user
if not response.session:
raise Exception(f"Login failed for {email}")
content = response.json()
session = self.sb_client.auth.set_session(
content["access_token"], content["refresh_token"]
)
session = response.session
username = session.user.user_metadata["username"]
self.logger.debug("connected with supabase as {}", username)
logger.debug("logged user {}", username)
response = self.sb_client.postgrest.rpc(
"sync_profile_packs", {"user_id": session.user.id}
).execute()
self.logger.info("info sync: {}", response)
d = response.data[0]
_id = d["id"]
_username = d["username"]
_packs_remaining = d["packs_remaining"]
_packs_last_regen_at = datetime.fromisoformat(
d["packs_last_regen_at"]
)
# Does this math still works when we are opening the 9th pack ?
next_pack_in = WikiMastersClient.ONE_PACK_TIME - (
datetime.now(tz=timezone.utc) - _packs_last_regen_at
)
next_run_in = next_pack_in + WikiMastersClient.ONE_PACK_TIME * (9 - _packs_remaining) - timedelta(seconds=10)
self.logger.info(
"Next pack is in {}",
hr.seconds_to_human(next_pack_in.total_seconds()),
)
self.logger.debug("We should schedule in {}", hr.seconds_to_human(next_run_in.total_seconds()))
return UserSession(username, sb_client)

35
uv.lock
View File

@ -23,6 +23,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
]
[[package]]
name = "apscheduler"
version = "3.11.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "tzlocal" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8c/6b/eeff360196bb20b312c9e762a820fd1b2c6d809466c755ef57863478e454/apscheduler-3.11.3.tar.gz", hash = "sha256:cd2fcc9330039a81a5893472ad49facf23a6d5604cbe1d918c835c6de7834d5a", size = 110312, upload-time = "2026-06-28T19:39:22.493Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl", hash = "sha256:bbeb2ec02d23d3c06a6c07ed7f0f3939ada6680eb121fae809a69bb42c537a30", size = 66024, upload-time = "2026-06-28T19:39:20.982Z" },
]
[[package]]
name = "certifi"
version = "2026.7.22"
@ -753,6 +765,27 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
]
[[package]]
name = "tzdata"
version = "2026.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/92/ff/5a28bdfd8c3ebec42564ac7d0e54ca3db65044a9314a97f9564fa7a1e926/tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415", size = 198674, upload-time = "2026-07-10T08:50:37.887Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" },
]
[[package]]
name = "tzlocal"
version = "5.4.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/81/5b/879b2f932adfa7a053c360d50bc896c977fa6426109185f7c12ebdd0cb9d/tzlocal-5.4.4.tar.gz", hash = "sha256:8dbb8660838688a7b6ba4fed31d18dedf842afb4d47ca050d6d891c2c15f3be4", size = 31170, upload-time = "2026-06-29T08:03:40.026Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl", hash = "sha256:aae09f0126a8a86fa736be266eb4a471380d26a0de3bc14844e7821fee3e2a15", size = 18115, upload-time = "2026-06-29T08:03:38.666Z" },
]
[[package]]
name = "websockets"
version = "15.0.1"
@ -778,6 +811,7 @@ name = "wiki-bot"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "apscheduler" },
{ name = "dotenv" },
{ name = "httpx" },
{ name = "loguru" },
@ -787,6 +821,7 @@ dependencies = [
[package.metadata]
requires-dist = [
{ name = "apscheduler", specifier = ">=3.11.3" },
{ name = "dotenv", specifier = ">=0.9.9" },
{ name = "httpx", specifier = ">=0.28.1" },
{ name = "loguru", specifier = ">=0.7.3" },