addressing audit - #241
Open
goku-kamehameha wants to merge 8 commits into
Open
Conversation
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
There was a problem hiding this comment.
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
TelemetryConsentServiceto 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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change Description
Briefly describe what this PR does and why. Keep it short and clear.
Related Platforms
Verification Checklist
Optional (for bigger changes)
Related Links
Closes #ID.