Skip to main content

Customer App (Android / iOS) — Security Implementation List

Date: January 31, 2026
Last Updated: January 31, 2026 — All critical and high items implemented
Scope: customer_app (Flutter — Android primary, iOS secondary)
Reference: project-docs/docs/development/security-audit.md §3 Customer App

This document compares the current customer app code with the security audit and lists what has been implemented and what remains.


1. Summary: Implementation Status

Audit itemStatusImplementation
Token storage✅ DoneFlutter Secure Storage; SharedPreferences fallback + migration
Logout✅ DoneCalls POST /logout before clearing local state
Error messages✅ DonegetSafeErrorMessage(); generic exceptions in api_service
API URL✅ DoneAppConfig.baseUrl from --dart-define=BASE_URL; fallback to prod
Certificate pinning✅ DoneIntermediate CA pinning (E7, R12, YE1, YE2, YR1, YR2); disabled in debug
HTTP timeout✅ Done30s for most; 120s for upload/calculate-cost
Google Maps key✅ Donelocal.properties (Android); MapsConfig.xcconfig (iOS)
Root/jailbreak detection✅ Doneflutter_jailbreak_detection; SecurityService; warning dialog
Session timeout✅ Done30 min idle logout via SessionService
Debug logging✅ DoneGated with kDebugMode; no response body or payment IDs in logs

2. Still Pending (Lower Priority)

ItemPriorityNotes
Location privacy toggleMediumAdd settings toggle to disable location for shop discovery
App integrity checksLowGoogle Play Integrity API (Android) / App Attest (iOS)
Biometric for sensitive actionsLowOptional fingerprint/face for payment on shared devices

3. Implemented Details

3.1 Token Storage

Implementation: api_service.dart uses FlutterSecureStorage as primary; SharedPreferences fallback with migration on first run. main.dart AuthWrapper reads token from secure storage first, then fallback.

Files: lib/services/api_service.dart, lib/main.dart


3.2 Logout

Implementation: api_service.logout() calls POST /logout with Bearer token before clearing local state. Clears both secure storage and SharedPreferences.

Files: lib/services/api_service.dart


3.3 Error Messages

Implementation: lib/utils/safe_error.dart provides getSafeErrorMessage(err, context). All auth, payment, upload, profile, and file screens use it. api_service throws generic exceptions only.

Files: lib/utils/safe_error.dart, lib/services/api_service.dart, all screen files


3.4 Debug Logging

Implementation: print statements removed or gated with kDebugMode and debugPrint. Razorpay success/error handlers do not log payment IDs in release.

Files: lib/services/api_service.dart, lib/services/razorpay_service.dart, screens


3.5 HTTP Timeout

Implementation: All API calls use 30s timeout (120s for multipart upload and calculate-cost).

Files: lib/services/api_service.dart


3.6 API URL Configuration

Implementation: lib/config/app_config.dart reads BASE_URL from --dart-define; falls back to production URL if empty.

Build: flutter run --dart-define=BASE_URL=https://...


3.7 Certificate Pinning

Implementation: lib/services/http_client_factory.dart creates HttpClient with SecurityContext using Let's Encrypt intermediate certificates. Default: intermediate CA pinning (E7, R12, YE1, YE2, YR1, YR2). Optional: leaf fingerprint pinning via --dart-define=CERT_PINS=.... Disabled in debug mode.

Files: lib/config/letsencrypt_certs.dart, lib/services/http_client_factory.dart
Update script: scripts/update_letsencrypt_certs.ps1 (run when Let's Encrypt rotates intermediates)


3.8 Google Maps API Key

Implementation:

  • Android: build.gradle.kts reads MAPS_API_KEY from local.properties; injects into manifest placeholder.
  • iOS: MapsConfig.xcconfig defines MAPS_API_KEY; AppDelegate.swift provides it to GMSServices.

Files: android/app/build.gradle.kts, android/local.properties, ios/Flutter/MapsConfig.xcconfig, ios/Runner/AppDelegate.swift
See: customer_app/GOOGLE_MAPS_SETUP.md


3.9 Root/Jailbreak Detection

Implementation: flutter_jailbreak_detection package. lib/services/security_service.dart provides SecurityService.hasElevatedRisk. dashboard_screen.dart shows warning dialog on elevated risk.

Note: Plugin requires a local patch for AGP compatibility (namespace + JVM target). See customer_app/SECURITY_SETUP.md.


3.10 Session Timeout

Implementation: lib/services/session_service.dart tracks activity. 30 min idle triggers callback; dashboard_screen.dart clears session and navigates to login. User interactions call SessionService.instance.touch().

Files: lib/services/session_service.dart, lib/screens/dashboard_screen.dart


4. What's Already OK

ItemStatus
HTTPSbaseUrl uses https://
Razorpay key✅ Comes from backend key_id, not hardcoded
Location permissions✅ Usage descriptions in Info.plist
Login timeout✅ 30s on login
Role check✅ Login screen checks role == 'customer'
File picker✅ Uses file_picker (user selects files)

5. References

  • Security audit: project-docs/docs/development/security-audit.md §3
  • Setup guide: customer_app/SECURITY_SETUP.md
  • Google Maps: customer_app/GOOGLE_MAPS_SETUP.md
  • Shopkeeper app (reference): shopkeeper_app/lib/services/api_service.dart

Last updated: January 31, 2026