(twitch): Add user auth caching.

Fix issues with check_auth.
Implement fetch_client_for.
Add 'modauth' app command for basic mod scopes.
This commit is contained in:
2025-05-22 20:23:34 +10:00
parent d1c5c4a0af
commit 2d87783c3e
2 changed files with 34 additions and 4 deletions

View File

@@ -29,13 +29,26 @@ class TwitchAuthCog(LionCog):
self.bot = bot self.bot = bot
self.data = bot.db.load_registry(TwitchAuthData()) self.data = bot.db.load_registry(TwitchAuthData())
self.client_cache = {}
async def cog_load(self): async def cog_load(self):
await self.data.init() await self.data.init()
# ----- Auth API ----- # ----- Auth API -----
async def fetch_client_for(self, userid: int): async def fetch_client_for(self, userid: str):
... authrow = await self.data.UserAuthRow.fetch(userid)
if authrow is None:
# TODO: Some user authentication error
self.client_cache.pop(userid, None)
raise ValueError("Requested user is not authenticated.")
if (twitch := self.client_cache.get(userid)) is None:
twitch = await Twitch(self.bot.config.twitch['app_id'], self.bot.config.twitch['app_secret'])
scopes = await self.data.UserAuthRow.get_scopes_for(userid)
authscopes = [AuthScope(scope) for scope in scopes]
await twitch.set_user_authentication(authrow.access_token, authscopes, authrow.refresh_token)
self.client_cache[userid] = twitch
return twitch
async def check_auth(self, userid: str, scopes: list[AuthScope] = []) -> bool: async def check_auth(self, userid: str, scopes: list[AuthScope] = []) -> bool:
""" """
@@ -46,7 +59,9 @@ class TwitchAuthCog(LionCog):
if authrow: if authrow:
if scopes: if scopes:
has_scopes = await self.data.UserAuthRow.get_scopes_for(userid) has_scopes = await self.data.UserAuthRow.get_scopes_for(userid)
has_auth = set(map(str, scopes)).issubset(has_scopes) desired = {scope.value for scope in scopes}
has_auth = desired.issubset(has_scopes)
logger.info(f"Auth check for `{userid}`: Requested scopes {desired}, has scopes {has_scopes}. Passed: {has_auth}")
else: else:
has_auth = True has_auth = True
else: else:
@@ -58,6 +73,7 @@ class TwitchAuthCog(LionCog):
Start the user authentication flow for the given userid. Start the user authentication flow for the given userid.
Will request the given scopes along with the default ones and any existing scopes. Will request the given scopes along with the default ones and any existing scopes.
""" """
self.client_cache.pop(userid, None)
existing_strs = await self.data.UserAuthRow.get_scopes_for(userid) existing_strs = await self.data.UserAuthRow.get_scopes_for(userid)
existing = map(AuthScope, existing_strs) existing = map(AuthScope, existing_strs)
to_request = set(existing).union(scopes) to_request = set(existing).union(scopes)
@@ -82,3 +98,17 @@ class TwitchAuthCog(LionCog):
await ctx.reply(flow.auth.return_auth_url()) await ctx.reply(flow.auth.return_auth_url())
await flow.run() await flow.run()
await ctx.reply("Authentication Complete!") await ctx.reply("Authentication Complete!")
@cmds.hybrid_command(name='modauth')
async def cmd_modauth(self, ctx: LionContext):
if ctx.interaction:
await ctx.interaction.response.defer(ephemeral=True)
scopes = [
AuthScope.MODERATOR_READ_FOLLOWERS,
AuthScope.CHANNEL_READ_REDEMPTIONS,
AuthScope.MODERATOR_MANAGE_CHAT_MESSAGES,
]
flow = await self.start_auth(scopes=scopes)
await ctx.reply(flow.auth.return_auth_url())
await flow.run()
await ctx.reply("Authentication Complete!")

View File

@@ -64,7 +64,7 @@ class TwitchAuthData(Registry):
""" """
rows = await TwitchAuthData.user_scopes.select_where(userid=userid) rows = await TwitchAuthData.user_scopes.select_where(userid=userid)
return [row.scope for row in rows] if rows else [] return [row['scope'] for row in rows] if rows else []
""" """