feat(protection): VIP umfasst auch approved Custom-Domains
getWebCustomDomains schliesst nur noch 'rejected' aus — 'approved' Domains bleiben in der Layer-2-VIP (Zweitschutz, falls Layer 1 aus ist). Reihenfolge: pending zuerst (keine Layer-1-Deckung → duerfen nie aus dem 50er-Cap fallen), dann approved neueste-zuerst (Ueberlauf = aelteste approved, via Layer 1 gedeckt). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
ced749018b
commit
a713070d25
@ -22,24 +22,35 @@ export const CUSTOM_DOMAIN_TYPES: CustomDomainType[] = [
|
|||||||
// ─── Custom Domains ───────────────────────────────────────────────────────────
|
// ─── Custom Domains ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gibt die aktiven Web-Custom-Domains eines Users zurück (nur type='web').
|
* Web-Custom-Domains eines Users für die Layer-2-VIP-Komposition (type='web').
|
||||||
* Status 'approved' und 'rejected' werden ausgeschlossen:
|
* Nur 'rejected' wird ausgeschlossen — 'approved' Domains BLEIBEN in der VIP:
|
||||||
* - approved → Domain ist in der globalen Blocklist, kein Slot mehr nötig
|
* Layer 2 ist der Zweitschutz für den Fall, dass Layer 1 (VPN/URL-Filter) aus
|
||||||
* - rejected → Domain wurde abgelehnt und Slot wurde freigegeben
|
* ist. Eine approved Domain ist zwar in der globalen Layer-1-Blocklist, muss
|
||||||
* Wird von GET /api/protection/webcontent-domains für die VIP-Komposition genutzt.
|
* aber auch in Layer 2 gedeckt sein.
|
||||||
|
*
|
||||||
|
* Reihenfolge = Priorität für den 50er-Cap im Endpoint:
|
||||||
|
* 1. pending zuerst — KEINE Layer-1-Deckung, die VIP ist ihre einzige
|
||||||
|
* Absicherung → dürfen nie aus dem Cap fallen (≤ Slot-Limit, passen immer).
|
||||||
|
* 2. approved danach, neueste zuerst — bei Überlauf fallen die ältesten
|
||||||
|
* approved weg (via Layer 1 weiter gedeckt, daher vertretbar).
|
||||||
|
*
|
||||||
|
* Wird von GET /api/protection/webcontent-domains genutzt.
|
||||||
*/
|
*/
|
||||||
export async function getWebCustomDomains(userId: string): Promise<string[]> {
|
export async function getWebCustomDomains(userId: string): Promise<string[]> {
|
||||||
const db = usePrisma();
|
const db = usePrisma();
|
||||||
const rows = await db.userCustomDomain.findMany({
|
// pending = alles außer approved/rejected — älteste zuerst (passen alle rein)
|
||||||
where: {
|
const pending = await db.userCustomDomain.findMany({
|
||||||
userId,
|
where: { userId, type: "web", status: { notIn: ["approved", "rejected"] } },
|
||||||
type: "web",
|
|
||||||
status: { notIn: ["approved", "rejected"] },
|
|
||||||
},
|
|
||||||
orderBy: { addedAt: "asc" },
|
orderBy: { addedAt: "asc" },
|
||||||
select: { domain: true },
|
select: { domain: true },
|
||||||
});
|
});
|
||||||
return rows.map((r) => r.domain);
|
// approved — neueste zuerst, damit bei Cap-Überlauf die ältesten wegfallen
|
||||||
|
const approved = await db.userCustomDomain.findMany({
|
||||||
|
where: { userId, type: "web", status: "approved" },
|
||||||
|
orderBy: { addedAt: "desc" },
|
||||||
|
select: { domain: true },
|
||||||
|
});
|
||||||
|
return [...pending.map((r) => r.domain), ...approved.map((r) => r.domain)];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserCustomDomains(userId: string) {
|
export async function getUserCustomDomains(userId: string) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user