import { randomUUID } from "crypto"; /** XML-Escape für User-Input in plist-Strings. */ function xmlEscape(str: string): string { return str .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /** Slugify label für Content-Disposition filename. */ export function labelToSlug(label: string): string { return label .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, "") .slice(0, 40); } /** * Generiert ein macOS DNS-Over-HTTPS Konfigurationsprofil (plist XML). * * Jeder Aufruf erzeugt neue random PayloadUUIDs — damit der Mac mehrere Profile * unterscheiden kann falls ein User das Profil neu lädt. * * Phase 2: DoH-Server routet per dnsToken auf user-spezifische Blocklist. */ export function generateMacOSDnsProfile(opts: { deviceId: string; dnsToken: string; label: string; }): string { const { deviceId, dnsToken, label } = opts; // Unique UUIDs pro Generierung (nicht deviceId verwenden — Mac dedupliciert sonst) const outerUUID = randomUUID().toUpperCase(); const innerUUID = randomUUID().toUpperCase(); // PayloadIdentifier: stabil pro Device (kein UUID hier — bleibt gleich bei Re-Download) const tokenPrefix = dnsToken.slice(0, 8); const payloadId = `org.rebreak.protection.dns.${tokenPrefix}`; const displayName = xmlEscape(`ReBreak Schutz — ${label}`); const innerDisplayName = xmlEscape("ReBreak DNS-Filter"); const description = xmlEscape( "Leitet DNS-Anfragen über dns.rebreak.org. Glücksspiel-Domains werden blockiert.", ); const outerDescription = xmlEscape( "Aktiviert den ReBreak-DNS-Filter auf diesem Mac. Glücksspiel-Domains werden auf System-Ebene blockiert — gilt für alle Browser und alle Apps. Entfernen erfordert Admin-Passwort.", ); const serverURL = `https://dns.rebreak.org/api/dns/${dnsToken}/dns-query`; return ` PayloadContent PayloadDisplayName ${innerDisplayName} PayloadDescription ${description} PayloadIdentifier ${payloadId}.dns PayloadType com.apple.dnsSettings.managed PayloadUUID ${innerUUID} PayloadVersion 1 DNSSettings DNSProtocol HTTPS ServerURL ${serverURL} PayloadDisplayName ${displayName} PayloadDescription ${outerDescription} PayloadIdentifier ${payloadId} PayloadOrganization ReBreak PayloadType Configuration PayloadUUID ${outerUUID} PayloadVersion 1 PayloadScope System PayloadRemovalDisallowed `; }