116 lines
3.0 KiB
TypeScript
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;
|
|
}
|
|
}
|