import { NativeModule, requireNativeModule } from 'expo'; import type { ActivateResult, DeviceLayers, DisableResult, HealthProbeOpts, HealthProbeResult, RebreakProtectionEvents, SyncBlocklistOpts, SyncBlocklistResult, SyncWebContentDomainsOpts, SyncWebContentDomainsResult, SystemSettingsTarget, WebContentFilterResult, } from './RebreakProtection.types'; declare class RebreakProtectionModule extends NativeModule { /** * iOS: aktiviert Layer 1 = den Packet-Tunnel-DNS-Filter * (`NEPacketTunnelProvider`). Startet/konfiguriert den Tunnel via * `NETunnelProviderManager` — beim ersten Aufruf erscheint der iOS-VPN- * System-Permission-Dialog. MDM-frei, ab iOS 16. Das ist der neue * Default-Layer-1 (ersetzt NEURLFilter, der Apple-seitig blockiert ist). * * `opts` wird auf iOS NICHT mehr ausgewertet (der Packet-Tunnel braucht * keine PIR-Config) — bleibt für API-Kompatibilität in der Signatur. */ activateUrlFilter(opts: { pirServerURL: string; pirAuthToken: string; }): Promise<{ enabled: boolean; error?: string }>; /** * iOS: aktiviert den NEURLFilter (iOS 26) via `NEURLFilterManager` mit dem * PIR-Server. INAKTIV — NICHT der Default-Filter. Behalten als optionaler * iOS-26-Upgrade-Pfad, falls Apple den NEURLFilter-DTS-Bug fixt. Der * Default-Layer-1 ist der Packet-Tunnel (`activateUrlFilter`). * Braucht `pirServerURL` + `pirAuthToken`. iOS 26+. */ activateNeUrlFilter(opts: { pirServerURL: string; pirAuthToken: string; }): Promise<{ enabled: boolean; error?: string }>; /** * iOS: nach "Nicht erlauben" beim NEFilter-Permission-Dialog hat iOS den * Denied-State gecached und zeigt beim erneuten activateUrlFilter() den * Dialog nicht mehr (code 5 silent). resetUrlFilter() macht ein * removeFromPreferences vor dem saveToPreferences — iOS behandelt das als * brandneuen Permission-Request → frischer System-Dialog. * * Nicht aufrufen wenn der User schon einmal "Erlauben" getippt hat — dann * würde ein unnötiger Dialog kommen. Nur als Workaround bei code 5 nutzen. */ resetUrlFilter(): Promise<{ enabled: boolean; error?: string }>; /** * iOS: aktiviert NUR Family Controls (Auth + denyAppRemoval = der Lock). * Triggert iOS-Dialog "Bildschirmzeit verwalten". * Sobald aktiv, kann der User den Schutz nur über Cooldown deaktivieren. */ activateFamilyControls(): Promise<{ enabled: boolean; error?: string }>; /** * Aktiviert ALLE Schutz-Layer in einem Call (legacy, beide Dialoge nacheinander). * Bevorzugt activateUrlFilter() + activateFamilyControls() einzeln aufrufen. */ activate(): Promise; /** * Schaltet ALLE Schutz-Layer ab. NUR aufrufen wenn JS-Layer verifiziert * hat dass der 24h-Cooldown abgelaufen ist. Native-Modul prüft das nicht * — der Backend-Cooldown ist Single Source of Truth, das ist Aufgabe der * JS-Schicht. */ disable(): Promise; /** * iOS Layer 2 — webContent-Filter (ManagedSettings). Bestimmt das Land via * Locale.current.region, lädt die gebündelte Top-Gambling-Domain-Liste für * dieses Land (≤50 Domains, Apple-Hartlimit) und setzt * `ManagedSettingsStore().webContent.blockedByFilter = .auto(...)` — blockt * die Domains in WebKit (Safari u.a.) plus systemseitig Adult-Content. * * Setzt eine gültige Family-Controls-Authorization voraus (wie der App-Lock). * Auf Android/iOS<16 no-op. Stilles Sicherheitsnetz; KEINE Auto-Trigger-Logik * — muss explizit aufgerufen werden (siehe TODO(layer2-gating) im Swift-Modul). */ applyWebContentFilter(): Promise; /** * iOS Layer 2 — setzt den webContent-Filter zurück (blockedByFilter = .none). * Rührt denyAppRemoval (App-Lock) NICHT an. Auf Android/iOS<16 no-op. */ clearWebContentFilter(): Promise<{ cleared: boolean; error?: string }>; /** * iOS Layer 2 — synct die kuratierte Gambling-Domain-Liste vom Backend * (`GET /api/protection/webcontent-domains`) und cached sie als * `webcontent-domains.json` im App-Group-Container. `loadWebContentDomains` * liest danach cache-first; die gebündelte `gambling-domains.json` bleibt * nur noch Offline-Seed/Fallback. * * Gespiegelt von `syncBlocklist`: baseURL + authToken aus der Supabase- * Session, Bearer-Auth, ETag/If-None-Match, Retry mit Backoff. Nach * erfolgreichem Sync wird — wenn Family Controls authorisiert ist — * `applyWebContentLayer()` erneut ausgeführt, damit die neue Liste sofort * greift. Server respondet 304 wenn ETag matched → updated=false. */ syncWebContentDomains( opts: SyncWebContentDomainsOpts, ): Promise; /** Aktueller Device-State. Polling- und Health-Check-Pfad. */ getDeviceState(): Promise; /** * Lädt blocklist.bin vom Server, schreibt atomisch in App-Group/internal * storage, postet Reload-Notification an die Filter-Extension. Server * respondet 304 wenn ETag matched → updated=false. Plan-aware: * Free → nur personal-domains (≤5), Pro/Legend → 208k+ + personal. */ syncBlocklist(opts: SyncBlocklistOpts): Promise; /** * E2E-Verifikation: Hidden WebView lädt eine bekannte Gambling-Domain, * prüft ob WebKit/Browser den Load aborted (Filter funktioniert) oder die * Page lädt (Filter ist tot — Alarm). */ runHealthProbe(opts?: HealthProbeOpts): Promise; /** Öffnet System-Settings auf dem entsprechenden Tab. */ openSystemSettings(target?: SystemSettingsTarget): Promise; /** * iOS: liest die nativen Protection-Logs (SharedLogStore — NEFilter/ * FamilyControls Flow) aus dem App-Group-UserDefaults. Für Debug-Page, * damit TestFlight-Tester den nativen Flow ohne Mac/Console.app sehen. */ getProtectionLogs(): Promise; /** iOS: leert die nativen Protection-Logs. */ clearProtectionLogs(): Promise; // ─── Android-spezifische Methoden (auf iOS undefined zur Laufzeit) ─────── /** Android: Live-Check ob unser AccessibilityService aktuell als enabled * registriert ist (Settings.Secure + AccessibilityManager). */ isAccessibilityEnabled(): Promise<{ enabled: boolean }>; /** Android: Öffnet Settings → Bedienungshilfen, möglichst tief auf die * Rebreak-Detail-Page (deep-link). Fallback: generelle A11y-Liste. */ openAccessibilitySettings(): Promise<{ opened: boolean }>; /** Android: Aktiviert Tamper-Lock-Watchdog (Settings-Page-Blockade durch * AccessibilityService). Wirft `preconditions_not_met` wenn VPN oder A11y * nicht beide live. */ armTamperLock(): Promise<{ armed: boolean }>; /** Android: Disarm Tamper-Lock. Schutz-Layers laufen weiter, aber Settings- * Watchdog blockt nicht mehr. Im normalen Flow nur nach Cooldown-Ablauf. */ disarmTamperLock(): Promise<{ armed: boolean }>; /** Android: kombinierter Status aller 3 Layers + Blocklist-Count. */ getProtectionStatus(): Promise<{ vpnEnabled: boolean; accessibilityEnabled: boolean; blocklistCount: number; tamperArmed: boolean; }>; /** Android: Wenn der Schutz an sein soll (`filter_enabled`) der VpnService * aber nicht läuft (Reinstall / Low-Mem-Kill) → neu starten. Bei App-Start / * Foreground aufrufen, damit der State nicht „an aber tot" bleibt. */ reconcileVpn(): Promise<{ restarted: boolean; needsConsent?: boolean }>; } export default requireNativeModule('RebreakProtection');