feat: Audit remediation + Stripe webhook + test suites
- Apply 3 Prisma schema changes (Pending2FASession, hubApiKeyHash, SecurityVerificationCode attempts) - Add Stripe webhook handler (checkout.session.completed -> User + Subscription + Order) - Add stripe-service, api-key-service, rate-limit middleware - Add security headers (CSP, HSTS, X-Frame-Options) in next.config.ts - Harden auth routes, require ADMIN_API_KEY for orchestrator endpoints - Add Docker auto-migration via startup.sh - Add 7 unit test suites (api-key, dns, config-generator, automation-worker, permission, security-verification, auth-helpers) - Fix Prisma 7 compatibility with adapter-pg mock for vitest Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
-- AlterTable: Add brute-force attempt tracking to security verification codes
|
||||
ALTER TABLE "security_verification_codes" ADD COLUMN "attempts" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
-- AlterTable: Add hash-based API key lookup to server connections
|
||||
ALTER TABLE "server_connections" ADD COLUMN "hub_api_key_hash" TEXT;
|
||||
|
||||
-- CreateTable: DB-backed 2FA sessions (replacing in-memory Map)
|
||||
CREATE TABLE "pending_2fa_sessions" (
|
||||
"id" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"user_type" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"name" TEXT,
|
||||
"role" TEXT,
|
||||
"company" TEXT,
|
||||
"subscription" JSONB,
|
||||
"expires_at" TIMESTAMP(3) NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "pending_2fa_sessions_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "pending_2fa_sessions_token_key" ON "pending_2fa_sessions"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "pending_2fa_sessions_token_idx" ON "pending_2fa_sessions"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "pending_2fa_sessions_expires_at_idx" ON "pending_2fa_sessions"("expires_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "server_connections_hub_api_key_hash_key" ON "server_connections"("hub_api_key_hash");
|
||||
@@ -7,7 +7,7 @@ generator client {
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
// url configured in prisma.config.ts (Prisma 7+)
|
||||
// url configured in prisma.config.mjs (Prisma 7+)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -417,6 +417,7 @@ model ServerConnection {
|
||||
|
||||
// Hub API key (issued after successful registration, used for heartbeats/commands)
|
||||
hubApiKey String? @unique @map("hub_api_key")
|
||||
hubApiKeyHash String? @unique @map("hub_api_key_hash")
|
||||
|
||||
// Orchestrator connection info (provided during registration)
|
||||
orchestratorUrl String? @map("orchestrator_url")
|
||||
@@ -613,11 +614,12 @@ model DetectedError {
|
||||
model SecurityVerificationCode {
|
||||
id String @id @default(cuid())
|
||||
clientId String @map("client_id")
|
||||
code String // 6-digit code
|
||||
code String // 8-digit code
|
||||
action String // "WIPE" | "REINSTALL"
|
||||
targetServerId String @map("target_server_id") // Which server
|
||||
expiresAt DateTime @map("expires_at")
|
||||
usedAt DateTime? @map("used_at")
|
||||
attempts Int @default(0) // Failed verification attempts
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
// Relations
|
||||
@@ -705,6 +707,28 @@ model NotificationSetting {
|
||||
@@map("notification_settings")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PENDING 2FA SESSIONS
|
||||
// ============================================================================
|
||||
|
||||
model Pending2FASession {
|
||||
id String @id @default(cuid())
|
||||
token String @unique
|
||||
userId String @map("user_id")
|
||||
userType String @map("user_type") // 'customer' | 'staff'
|
||||
email String
|
||||
name String?
|
||||
role String? // StaffRole for staff users
|
||||
company String?
|
||||
subscription Json? // Subscription data for customer users
|
||||
expiresAt DateTime @map("expires_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@index([token])
|
||||
@@index([expiresAt])
|
||||
@@map("pending_2fa_sessions")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// SYSTEM-WIDE NOTIFICATION COOLDOWN
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user