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 type { NextAuthOptions } from "next-auth";
|
||||||
import DiscordProvider, { type DiscordProfile } from "next-auth/providers/discord";
|
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 = {
|
export const authOptions: NextAuthOptions = {
|
||||||
providers: [
|
providers: [
|
||||||
DiscordProvider({
|
DiscordProvider({
|
||||||
@@ -26,13 +36,33 @@ export const authOptions: NextAuthOptions = {
|
|||||||
],
|
],
|
||||||
callbacks: {
|
callbacks: {
|
||||||
async signIn({ user }) {
|
async signIn({ user }) {
|
||||||
const hasRequiredRole = await verifyUserRole(user.id);
|
try {
|
||||||
|
return await checkRole(user.id);
|
||||||
if (!hasRequiredRole) {
|
} catch (error) {
|
||||||
|
console.error("Error verifying user role:", error);
|
||||||
return false;
|
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: {
|
pages: {
|
||||||
|
|||||||
+10
-15
@@ -30,23 +30,18 @@ export async function discordFetch(path: string): Promise<Response> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function verifyUserRole(userId: string): Promise<boolean> {
|
export async function verifyUserRole(userId: string): Promise<boolean> {
|
||||||
try {
|
const guildId = requireEnv("DISCORD_GUILD_ID");
|
||||||
const guildId = requireEnv("DISCORD_GUILD_ID");
|
const requiredRoleId = requireEnv("DISCORD_REQUIRED_ROLE_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) {
|
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);
|
|
||||||
return false;
|
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