MBO-Tech-IT-Webseite/modules/02-admin-auth/files/lib/token-blacklist.ts

116 lines
3.0 KiB
TypeScript

/**
* Token-Revocation & Blacklist Management
* Verhindert Wiederverwendung von:
* 1. Session-Tokens nach Logout
* 2. Action-Tokens nach einmaliger Verwendung
*/
import { createServiceClient } from "./supabase";
/**
* Revoke a session token by adding its signature to the blacklist
*/
export async function revokeSessionToken(
tokenSignature: string,
adminId: string,
reason: "logout" | "password_changed" | "suspicious_activity" = "logout",
notes?: string
): Promise<boolean> {
try {
const db = createServiceClient();
const { error } = await db.from("admin_session_blacklist").insert({
admin_id: adminId,
token_signature: tokenSignature,
reason,
notes,
});
if (error) {
console.error("Failed to revoke session token:", error);
return false;
}
return true;
} catch (error) {
console.error("Error revoking session token:", error);
return false;
}
}
/**
* Check if a session token signature is revoked
*/
export async function isSessionTokenRevoked(tokenSignature: string): Promise<boolean> {
try {
const db = createServiceClient();
const { data, error } = await db
.from("admin_session_blacklist")
.select("id", { count: "exact" })
.eq("token_signature", tokenSignature)
.single();
if (error && error.code !== "PGRST116") {
// PGRST116 = no rows found, which is expected
console.error("Error checking token revocation:", error);
return false;
}
return data?.id !== undefined && data?.id !== null;
} catch (error) {
console.error("Error checking token revocation:", error);
return false;
}
}
/**
* Mark an action token as used (one-time use)
*/
export async function markActionTokenUsed(
tokenSignature: string,
anfrageId: string,
actionType: string,
ipAddr?: string
): Promise<boolean> {
try {
const db = createServiceClient();
const { error } = await db.from("action_token_blacklist").insert({
token_signature: tokenSignature,
anfrage_id: anfrageId,
action_type: actionType,
used_by_ip: ipAddr,
});
if (error) {
console.error("Failed to mark action token as used:", error);
return false;
}
return true;
} catch (error) {
console.error("Error marking action token as used:", error);
return false;
}
}
/**
* Check if an action token has already been used
*/
export async function isActionTokenUsed(tokenSignature: string): Promise<boolean> {
try {
const db = createServiceClient();
const { data, error } = await db
.from("action_token_blacklist")
.select("id", { count: "exact" })
.eq("token_signature", tokenSignature)
.single();
if (error && error.code !== "PGRST116") {
console.error("Error checking action token usage:", error);
return false;
}
return data?.id !== undefined && data?.id !== null;
} catch (error) {
console.error("Error checking action token usage:", error);
return false;
}
}