feat(protection): GET /api/protection/webcontent-domains — runtime-updatebare Layer-2-Domain-Liste

Neuer Nitro-Endpoint serviert die kuratierte Gambling-Domain-Liste pro Land
(DE/GB/FR) aus backend/data/gambling-domains.json. Auth wie alle
/api/protection/*-Routen (requireUser). 50-Domain-Cap pro Land serverseitig
erzwungen. Liste pflegen = JSON editieren + _meta.version hochzaehlen + deploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
chahinebrini 2026-05-21 20:21:54 +02:00
parent 50d3c6a8e1
commit 86ed603a45
3 changed files with 157 additions and 0 deletions

View File

@ -0,0 +1,95 @@
{
"_comment": "Kuratierte Gambling-Domain-Liste pro Land. APPLE-HARTLIMIT: max. 50 Domains pro Land-Key — NIE überschreiten. Schlüssel = ISO-3166-1-alpha-2 (Locale.current.region). Werte = registrierbare Domains ohne Schema/Subdomain (ManagedSettings WebDomain matched inkl. aller Subdomains). Pflege: Datei editieren, version hochzählen, updatedAt setzen, dann neu deployen.",
"_meta": {
"version": 1,
"updatedAt": "2026-05-21",
"maxDomainsPerCountry": 50,
"status": "starter"
},
"DE": [
"tipico.de",
"tipico.com",
"bwin.de",
"bwin.com",
"interwetten.de",
"interwetten.com",
"betano.de",
"bet-at-home.com",
"sportwetten.de",
"merkur-bets.de",
"merkurbets.de",
"happybet.de",
"neobet.de",
"winamax.de",
"betway.de",
"admiralbet.de",
"oddset.de",
"lottohelden.de",
"lotto.de",
"lotto24.de",
"jackpot.de",
"drueckglueck.de",
"loewen-play.de",
"merkur24.com",
"casino.de",
"casinos.de",
"betsson.de",
"leovegas.de",
"lapalingo.com",
"sunmaker.de"
],
"GB": [
"bet365.com",
"williamhill.com",
"skybet.com",
"skyvegas.com",
"ladbrokes.com",
"coral.co.uk",
"paddypower.com",
"betfair.com",
"betfred.com",
"unibet.co.uk",
"888.com",
"888sport.com",
"888casino.com",
"betway.com",
"virginbet.com",
"boylesports.com",
"betvictor.com",
"10bet.com",
"mrgreen.com",
"casumo.com",
"leovegas.com",
"grosvenorcasinos.com",
"mecca-bingo.com",
"gala-bingo.com",
"tombola.co.uk",
"lottoland.co.uk",
"national-lottery.co.uk",
"kwikfit-pools.co.uk",
"parimatch.co.uk",
"smarkets.com"
],
"FR": [
"winamax.fr",
"betclic.fr",
"betclic.com",
"pmu.fr",
"unibet.fr",
"parionssport.fdj.fr",
"fdj.fr",
"zebet.fr",
"vbet.fr",
"netbet.fr",
"bwin.fr",
"genybet.fr",
"zeturf.fr",
"feeling-bet.fr",
"barrierebet.fr",
"pokerstars.fr",
"partypoker.fr",
"lucien-barriere.com",
"casinobarriere.com",
"circus.be"
]
}

View File

@ -12,6 +12,13 @@ export default defineNitroConfig({
{ baseURL: "/", dir: "../public", maxAge: 60 * 60 },
],
// Server-Assets: werden ins Build-Artifact gebundelt und sind via
// useStorage('assets:server') abrufbar. Kein process.cwd()-Trick nötig.
// gambling-domains.json: runtime-updatebare iOS-Layer-2-Domain-Liste.
serverAssets: [
{ baseName: "data", dir: "../data" },
],
// Supabase als external dep — nicht bundlen
externals: {
inline: [/^(?!@supabase\/supabase-js)/],

View File

@ -0,0 +1,55 @@
import { requireUser } from "../../utils/auth";
const MAX_DOMAINS_PER_COUNTRY = 50;
/**
* GET /api/protection/webcontent-domains
*
* Liefert die runtime-updatebare iOS-Layer-2-Gambling-Domain-Liste.
* Datenquelle: backend/data/gambling-domains.json (file-based, v1).
* Im Build über Nitro serverAssets gebundelt kein process.cwd()-Trick.
*
* Pflege: backend/data/gambling-domains.json editieren,
* _meta.version hochzählen, _meta.updatedAt setzen, dann neu deployen.
*
* Apple-Hartlimit: max. 50 Domains pro Land-Key. Wird serverseitig
* enforced (slice), damit ein versehentlicher Überschuss in der JSON-Datei
* nie zur App durchdringt.
*
* Auth: identisch zu allen anderen /api/protection/*-Routen (requireUser).
*/
export default defineEventHandler(async (event) => {
await requireUser(event);
const storage = useStorage("assets:server");
const raw = await storage.getItem<{
_meta: { version: number; updatedAt: string; [k: string]: unknown };
_comment?: string;
[country: string]: unknown;
}>("data:gambling-domains.json");
if (!raw) {
throw createError({
statusCode: 500,
message: "GAMBLING_DOMAINS_UNAVAILABLE",
});
}
const { _meta, _comment: _c, ...countryEntries } = raw;
const countries: Record<string, string[]> = {};
for (const [key, value] of Object.entries(countryEntries)) {
if (Array.isArray(value)) {
// Apple-Hartlimit: niemals mehr als 50 Domains pro Land ausliefern
countries[key] = (value as string[]).slice(0, MAX_DOMAINS_PER_COUNTRY);
}
}
return {
_meta: {
version: _meta.version,
updatedAt: _meta.updatedAt,
},
...countries,
};
});