SPB Git forge

spb/spinza

Public
8commits 1branches 0releases
1.6 MBsize
maindefault branch
16 days agolast push
TypeScript 97.6% SQL 1.4% JavaScript 0.5%
1.5 KB · 50 lines typescript
Raw Blame History
1import { db, securityEvents } from "@spinza/database";2import type { FastifyRequest } from "fastify";34export type SecurityEventType =5  | "login.success"6  | "login.failed"7  | "register"8  | "logout"9  | "password.changed"10  | "recovery.used"11  | "recovery.failed"12  | "rate_limit"13  | "spin.suspicious"14  | "admin.login.success"15  | "admin.login.failed"16  | "admin.wallet.adjust"17  | "admin.user.status"18  | "admin.game.lifecycle"19  | "admin.game.flags"20  | "admin.flag"21  | "admin.setting"22  | "admin.maintenance"23  | "csrf.rejected";2425export function clientIp(req: FastifyRequest): string {26  const xff = req.headers["x-forwarded-for"];27  if (typeof xff === "string" && xff.length) return xff.split(",").pop()!.trim();28  return req.ip;29}3031export async function logSecurity(32  req: FastifyRequest | null,33  type: SecurityEventType,34  opts: { userId?: string | null; adminId?: string | null; severity?: "info" | "warn" | "high"; meta?: Record<string, unknown> } = {},35): Promise<void> {36  try {37    await db.insert(securityEvents).values({38      userId: opts.userId ?? null,39      adminId: opts.adminId ?? null,40      type,41      severity: opts.severity ?? (type.includes("failed") || type === "rate_limit" || type === "csrf.rejected" ? "warn" : "info"),42      ip: req ? clientIp(req) : null,43      userAgent: req ? (req.headers["user-agent"] ?? "").slice(0, 300) : null,44      meta: opts.meta ?? null,45    });46  } catch (e) {47    req?.log.error({ err: e }, "security event write failed");48  }49}50