Skip to content

addressing audit - #241

Open
goku-kamehameha wants to merge 8 commits into
devfrom
crash-fix
Open

addressing audit#241
goku-kamehameha wants to merge 8 commits into
devfrom
crash-fix

Conversation

@goku-kamehameha

Copy link
Copy Markdown
Contributor

Change Description

Briefly describe what this PR does and why. Keep it short and clear.


Related Platforms

Which platforms are affected by your changes? Check only the ones you actually tested.

  • Android
  • iOS
  • iPad
  • Windows
  • Linux
  • Android TV
  • OpenWrt

Verification Checklist

Make sure the things you checked actually work. It's okay if you didn't test everything.

  • Project builds successfully
  • App runs without crashes on tested platforms
  • VPN connection works correctly
  • No obvious regressions observed
  • Documentation updated (if needed)

Optional (for bigger changes)

  • Added or updated unit / E2E tests
  • Checked security and edge cases

Related Links

Closes #ID.

@goku-kamehameha
goku-kamehameha requested review from JuliusCaesarCrypto and a lite review from Copilot and removed request for Copilot August 15, 2026 09:30
# Conflicts:
#	pubspec.lock
Copilot AI lite review requested due to automatic review settings August 15, 2026 22:35
@goku-kamehameha
goku-kamehameha removed the request for review from JuliusCaesarCrypto August 15, 2026 22:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an explicit telemetry consent flow (opt-in) and gates Firebase/Cloudflare telemetry behind it, while also hardening VPN connection/disconnection behavior across Flutter and Android native layers as part of addressing an audit.

Changes:

  • Add TelemetryConsentService to persist consent and delay Firebase initialization until granted; wire consent into UI (privacy notice + settings).
  • Gate analytics/crash reporting/speed-test logging behind consent checks and tighten event parameter allow-listing.
  • Improve VPN lifecycle robustness (dedupe connect operations in Dart; add mutex/timeouts/cleanup paths in Android service and method channel).

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test/widget_test.dart Adds widget/unit tests for telemetry opt-in default and consent persistence.
lib/shared/services/telemetry_consent_service.dart New consent + deferred Firebase init service (central piece of audit work).
lib/shared/services/firebase_analytics_service.dart Gates analytics calls behind telemetry consent.
lib/shared/services/crash_reporting_service.dart Gates Crashlytics calls behind telemetry consent.
lib/shared/services/animation_service.dart Prevents starting controllers with null/zero durations when animations are disabled.
lib/shared/providers/connection_state_provider.dart Updates Flutter-side connection state updates from native VPN status strings; avoids persisting transient states.
lib/modules/speed_test/application/services/cloudflare_logger_service.dart Prevents Cloudflare result uploads when telemetry is disabled.
lib/modules/settings/presentation/screens/settings_screen.dart Adds a settings toggle to grant/deny telemetry consent.
lib/modules/main/presentation/widgets/privacy_notice_dialog.dart Updates privacy notice to capture telemetry opt-in alongside VPN setup notice (or telemetry-only).
lib/modules/main/presentation/widgets/ads/strategy/internal_ad_strategy.dart Refactors delayed internal ad load and wraps async error handling.
lib/modules/main/presentation/widgets/ads/strategy/google_ad_strategy.dart Refactors “load + start countdown” flow into a helper to avoid duplicated logic.
lib/modules/main/presentation/screens/main_screen.dart Shows privacy/telemetry consent dialog when needed and persists chosen consent.
lib/modules/core/vpn.dart Deduplicates concurrent connect operations and improves tunnel start/stop error handling.
lib/main.dart Removes eager Firebase init and initializes telemetry consent service at startup.
android/app/src/main/kotlin/com/defyx/defyx/VpnService.kt Adds mutex + timeouts + cleanup hardening; adjusts foreground service promotion behavior.
android/app/src/main/kotlin/com/defyx/defyx/MainActivity.kt Improves VPN start/stop method channel flows and status listener lifecycle handling.
android/app/src/main/AndroidManifest.xml Switches VPN service to special-use foreground type and updates required permissions/metadata.
Suppressed comments (2)

android/app/src/main/kotlin/com/defyx/defyx/VpnService.kt:139

  • startForeground() is called with FOREGROUND_SERVICE_TYPE_SPECIAL_USE for all API 29+ devices. SPECIAL_USE is only valid on newer Android versions; on API 29–33 this can throw (or be rejected), preventing the VPN service from starting in the foreground.
    private fun startAsForeground(title: String, contentText: String) {
        val notification = buildNotification(title, contentText, isVpnConnected)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            try {
                startForeground(
                        NOTIFICATION_ID,
                        notification,
                        ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
                )
            } catch (e: Exception) {
                Log.e(TAG, "Failed to promote VPN service to foreground", e)
                throw ForegroundPromotionException(e)
            }
        } else {
            startForeground(NOTIFICATION_ID, notification)
        }
        isServiceRunning = true

android/app/src/main/AndroidManifest.xml:49

  • If startAsForeground() uses CONNECTED_DEVICE on API 29–33, the service also needs to declare connectedDevice in android:foregroundServiceType (the system validates runtime types against the manifest declaration). With only "specialUse" declared here, startForeground(...CONNECTED_DEVICE) can still fail.
        <service
            android:name="de.unboundtech.defyxvpn.DefyxVpnService"
            android:permission="android.permission.BIND_VPN_SERVICE"
            android:foregroundServiceType="specialUse"
            android:exported="false"

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +72 to +80
try {
await Firebase.initializeApp(
name: _firebaseAppName,
options: DefaultFirebaseOptions.currentPlatform,
);
await FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true);
await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
_installErrorHandlers();
_firebaseInitialized = true;
Comment on lines +87 to +97
void _installErrorHandlers() {
FlutterError.onError = (errorDetails) {
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
FlutterError.presentError(errorDetails);
};

PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
}
Comment on lines 6 to 10
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.BIND_VPN_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
Comment on lines +334 to 338
try {
stopForeground(STOP_FOREGROUND_REMOVE)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(NOTIFICATION_ID)
Comment on lines +213 to +219
suspendCancellableCoroutine<Unit> { continuation ->
fun complete(block: () -> Unit) {
if (completed.compareAndSet(false, true)) {
block()
continuation.resume(Unit)
}
}
Comment on lines 67 to +75
override fun onDestroy() {
super.onDestroy()
log("VPN Service Destroyed")
try {
runBlocking(Dispatchers.IO) { disconnectVpnAndWait() }
} catch (e: Throwable) {
log("Service destroy cleanup timed out: ${e.message}")
}
serviceScope.cancel()
super.onDestroy()
@goku-kamehameha
goku-kamehameha deleted the crash-fix branch August 15, 2026 22:52
@goku-kamehameha
goku-kamehameha restored the crash-fix branch August 15, 2026 22:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants