fix: enforce unique provider+subject constraint and harden sync route
- Change providerSubjectIdx from index to uniqueIndex in schema.ts to prevent multiple users sharing the same (provider, subject) pair, which caused non-deterministic sign-in resolution via findFirst. - Add migration 0008_unique_provider_subject.sql: DROP the existing non-unique index and CREATE UNIQUE INDEX in its place. - Validate INSTANCE_SYNC_MAX_BYTES env var in sync route: fall back to 10 MB default when the value is non-numeric (e.g. 'off') or non-positive, preventing NaN comparisons that silently disabled the size limit. - Return a generic error message to callers on applySyncPayload / applyCaddyConfig failure instead of leaking the raw error string; the original message is still stored internally via setSlaveLastSync. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,11 @@ import { timingSafeEqual } from "crypto";
|
||||
import { applyCaddyConfig } from "@/src/lib/caddy";
|
||||
import { applySyncPayload, getInstanceMode, getSlaveMasterToken, setSlaveLastSync, SyncPayload } from "@/src/lib/instance-sync";
|
||||
|
||||
const MAX_SYNC_BODY_BYTES = Number(process.env.INSTANCE_SYNC_MAX_BYTES ?? 10 * 1024 * 1024);
|
||||
const DEFAULT_MAX_SYNC_BODY_BYTES = 10 * 1024 * 1024; // 10 MB
|
||||
const _parsedMaxBytes = Number(process.env.INSTANCE_SYNC_MAX_BYTES);
|
||||
const MAX_SYNC_BODY_BYTES = Number.isFinite(_parsedMaxBytes) && _parsedMaxBytes > 0
|
||||
? _parsedMaxBytes
|
||||
: DEFAULT_MAX_SYNC_BODY_BYTES;
|
||||
const SYNC_RATE_MAX = Number(process.env.INSTANCE_SYNC_RATE_MAX ?? 60);
|
||||
const SYNC_RATE_WINDOW_MS = Number(process.env.INSTANCE_SYNC_RATE_WINDOW_MS ?? 60_000);
|
||||
const SYNC_RATE_LIMITS = new Map<string, { count: number; windowStart: number }>();
|
||||
@@ -235,7 +239,7 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ ok: true });
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Failed to apply sync payload";
|
||||
await setSlaveLastSync({ ok: false, error: message });
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
await setSlaveLastSync({ ok: false, error: message }); // still store internally
|
||||
return NextResponse.json({ error: "Failed to apply sync payload" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user