mirror of
https://github.com/UiO-Gaming/name-100-uio-gamers.git
synced 2026-11-05 13:56:53 +01:00
Re-verify the paying member role every hour during a session
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
925d1a4593
commit
ecfa50799e
2 files changed
+44
-19
No files matched your search
+34
-4
@@ -2,6 +2,16 @@ import { verifyUserRole } from "@/lib/discord";
|
||||
import type { NextAuthOptions } from "next-auth";
|
||||
import DiscordProvider, { type DiscordProfile } from "next-auth/providers/discord";
|
||||
|
||||
const ROLE_RECHECK_INTERVAL = 60 * 60 * 1000;
|
||||
|
||||
const roleChecks = new Map<string, { hasRole: boolean; checkedAt: number }>();
|
||||
|
||||
async function checkRole(userId: string): Promise<boolean> {
|
||||
const hasRole = await verifyUserRole(userId);
|
||||
roleChecks.set(userId, { hasRole, checkedAt: Date.now() });
|
||||
return hasRole;
|
||||
}
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
providers: [
|
||||
DiscordProvider({
|
||||
@@ -26,13 +36,33 @@ export const authOptions: NextAuthOptions = {
|
||||
],
|
||||
callbacks: {
|
||||
async signIn({ user }) {
|
||||
const hasRequiredRole = await verifyUserRole(user.id);
|
||||
|
||||
if (!hasRequiredRole) {
|
||||
try {
|
||||
return await checkRole(user.id);
|
||||
} catch (error) {
|
||||
console.error("Error verifying user role:", error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
async jwt({ token }) {
|
||||
if (!token.sub) {
|
||||
return token;
|
||||
}
|
||||
|
||||
return true;
|
||||
const cached = roleChecks.get(token.sub);
|
||||
let hasRole = cached?.hasRole ?? true;
|
||||
|
||||
if (!cached || Date.now() - cached.checkedAt > ROLE_RECHECK_INTERVAL) {
|
||||
try {
|
||||
hasRole = await checkRole(token.sub);
|
||||
} catch (error) {
|
||||
console.error("Error re-verifying user role:", error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasRole) {
|
||||
throw new Error(`User ${token.sub} no longer has the required role`);
|
||||
}
|
||||
return token;
|
||||
},
|
||||
},
|
||||
pages: {
|
||||
|
||||
+10
-15
@@ -30,23 +30,18 @@ export async function discordFetch(path: string): Promise<Response> {
|
||||
}
|
||||
|
||||
export async function verifyUserRole(userId: string): Promise<boolean> {
|
||||
try {
|
||||
const guildId = requireEnv("DISCORD_GUILD_ID");
|
||||
const requiredRoleId = requireEnv("DISCORD_REQUIRED_ROLE_ID");
|
||||
const guildId = requireEnv("DISCORD_GUILD_ID");
|
||||
const requiredRoleId = requireEnv("DISCORD_REQUIRED_ROLE_ID");
|
||||
|
||||
const response = await discordFetch(`/guilds/${guildId}/members/${userId}`);
|
||||
const response = await discordFetch(`/guilds/${guildId}/members/${userId}`);
|
||||
|
||||
if (response.status === 404) {
|
||||
return false;
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch guild member ${userId}: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const member: DiscordGuildMember = await response.json();
|
||||
return member.roles.includes(requiredRoleId);
|
||||
} catch (error) {
|
||||
console.error("Error verifying user role:", error);
|
||||
if (response.status === 404) {
|
||||
return false;
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch guild member ${userId}: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const member: DiscordGuildMember = await response.json();
|
||||
return member.roles.includes(requiredRoleId);
|
||||
}
|
||||
Reference in new issue
Block a user