After an APK reinstall (or an OS low-memory kill that START_STICKY didn't recover promptly), the VpnService dies but `filter_enabled` stays true. isVpnEffectivelyOn then reports vpn:true (from the flag) → tamperLock:true → lockedIn:true → the green "protection active" card with no toggles, while in reality nothing is filtering. New native reconcileVpn(): if `filter_enabled` && !RebreakVpnService.isRunning && VpnService.prepare()==null → startVpnService(). Wired into _layout.tsx enforceProtection() (runs on launch / foreground / 15s poll), called before reading combined state. No-op on iOS/web. If the VPN consent was revoked, isVpnEffectivelyOn already clears the flag, so that case self-resolves too. Net behavior: while `filter_enabled` is true (user hasn't exited via the cooldown), the app keeps the VPN alive. Exiting still goes through the cooldown → forceDisable → filter_enabled=false → reconcile leaves it off. DiGA-compliant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
1.7 KiB
TypeScript
73 lines
1.7 KiB
TypeScript
/**
|
|
* Web-Stub. Ergibt im Browser keinen funktionalen Schutz — der Filter ist
|
|
* inhärent device-bound. Verhindert nur dass Imports auf Web crashen.
|
|
*/
|
|
import { registerWebModule, NativeModule } from 'expo';
|
|
|
|
import type {
|
|
ActivateResult,
|
|
DeviceLayers,
|
|
DisableResult,
|
|
HealthProbeResult,
|
|
RebreakProtectionEvents,
|
|
SyncBlocklistResult,
|
|
} from './RebreakProtection.types';
|
|
|
|
class RebreakProtectionModuleWeb extends NativeModule<RebreakProtectionEvents> {
|
|
async activate(): Promise<ActivateResult> {
|
|
return { allLayersOn: false, missingLayers: [] };
|
|
}
|
|
|
|
async disable(): Promise<DisableResult> {
|
|
return { allLayersOff: true };
|
|
}
|
|
|
|
async getDeviceState(): Promise<DeviceLayers> {
|
|
return { blocklistCount: 0, blocklistLastSyncAt: null };
|
|
}
|
|
|
|
async syncBlocklist(): Promise<SyncBlocklistResult> {
|
|
return { updated: false, count: 0 };
|
|
}
|
|
|
|
async runHealthProbe(): Promise<HealthProbeResult> {
|
|
return {
|
|
outcome: 'offline',
|
|
reason: 'web_stub',
|
|
durationMs: 0,
|
|
target: '',
|
|
};
|
|
}
|
|
|
|
async openSystemSettings(): Promise<void> {
|
|
// no-op
|
|
}
|
|
|
|
// Android-only stubs (Web nutzt keinen davon, aber Type-Compat).
|
|
async isAccessibilityEnabled() {
|
|
return { enabled: false };
|
|
}
|
|
async openAccessibilitySettings() {
|
|
return { opened: false };
|
|
}
|
|
async armTamperLock() {
|
|
return { armed: false };
|
|
}
|
|
async disarmTamperLock() {
|
|
return { armed: false };
|
|
}
|
|
async getProtectionStatus() {
|
|
return {
|
|
vpnEnabled: false,
|
|
accessibilityEnabled: false,
|
|
blocklistCount: 0,
|
|
tamperArmed: false,
|
|
};
|
|
}
|
|
async reconcileVpn() {
|
|
return { restarted: false };
|
|
}
|
|
}
|
|
|
|
export default registerWebModule(RebreakProtectionModuleWeb, 'RebreakProtection');
|