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 item | Status | Implementation |
|---|---|---|
| Token storage | ✅ Done | Flutter Secure Storage; SharedPreferences fallback + migration |
| Logout | ✅ Done | Calls POST /logout before clearing local state |
| Error messages | ✅ Done | getSafeErrorMessage(); generic exceptions in api_service |
| API URL | ✅ Done | AppConfig.baseUrl from --dart-define=BASE_URL; fallback to prod |
| Certificate pinning | ✅ Done | Intermediate CA pinning (E7, R12, YE1, YE2, YR1, YR2); disabled in debug |
| HTTP timeout | ✅ Done | 30s for most; 120s for upload/calculate-cost |
| Google Maps key | ✅ Done | local.properties (Android); MapsConfig.xcconfig (iOS) |
| Root/jailbreak detection | ✅ Done | flutter_jailbreak_detection; SecurityService; warning dialog |
| Session timeout | ✅ Done | 30 min idle logout via SessionService |
| Debug logging | ✅ Done | Gated with kDebugMode; no response body or payment IDs in logs |
2. Still Pending (Lower Priority)
| Item | Priority | Notes |
|---|---|---|
| Location privacy toggle | Medium | Add settings toggle to disable location for shop discovery |
| App integrity checks | Low | Google Play Integrity API (Android) / App Attest (iOS) |
| Biometric for sensitive actions | Low | Optional 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.ktsreadsMAPS_API_KEYfromlocal.properties; injects into manifest placeholder. - iOS:
MapsConfig.xcconfigdefinesMAPS_API_KEY;AppDelegate.swiftprovides 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
| Item | Status |
|---|---|
| HTTPS | ✅ baseUrl 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