Skip to content

Commit 5052dbb

Browse files
committed
chore(security): corrections audit mobile OWASP + code audit + pentest v1.13.3
- Deplace android/key.properties et android/app/keystore.jks hors depot (J:/applications/_backups/pdf_tech_keystore/) ; signature release uniquement via variables d'environnement PDFTECH_*. - build.gradle.kts: interdit le fallback signing debug en release, le build echoue explicitement si les credentials release sont absents. - build.gradle.kts: desactive enableV1Signing (attaque Janus) ; minSdk pinner explicitement a 24. - AndroidManifest.xml: justifie MANAGE_EXTERNAL_STORAGE comme optionnelle avec fallback SAF. - storage_permission_service.dart: dialogue explicatif complet, permission optionnelle, proposition systematique du fallback SAF. - pdf_picker_screen.dart + saf_picker.dart: protegent les debugPrint sous if (kDebugMode) avec blocs conformes au lint. - google_drive_screen.dart: messages d'erreur generiques sans fuite de l'exception brute ; logs restreints au mode debug. - Inclut la refonte de l'explorateur de fichiers (3 modes + miniatures).
1 parent d2ac7ba commit 5052dbb

7 files changed

Lines changed: 498 additions & 249 deletions

File tree

‎android/app/build.gradle.kts‎

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
import java.util.Properties
2-
import java.io.FileInputStream
3-
41
plugins {
52
id("com.android.application")
63
id("kotlin-android")
74
id("dev.flutter.flutter-gradle-plugin")
85
}
96

10-
// Credentials keystore : variables d'environnement (CI / poste sécurisé)
11-
// avec fallback sur android/key.properties (gitignoré).
12-
val keyPropertiesFile = rootProject.file("key.properties")
13-
val keyProperties = Properties()
14-
if (keyPropertiesFile.exists()) {
15-
keyProperties.load(FileInputStream(keyPropertiesFile))
16-
}
17-
fun keyProp(envName: String, propName: String): String? =
18-
System.getenv(envName) ?: keyProperties[propName] as String?
7+
// Credentials keystore : UNIQUEMENT via variables d'environnement (CI / poste
8+
// sécurisé). Le fichier key.properties et le keystore ne doivent JAMAIS être
9+
// versionnés. Ils sont stockés hors dépôt, par exemple dans
10+
// J:/applications/_backups/pdf_tech_keystore/.
11+
fun env(name: String): String? = System.getenv(name)
1912

2013
android {
2114
// v1.12.5 (S1) — `com.pdftech.pdf_tech` est le package HISTORIQUE pré-
@@ -40,25 +33,33 @@ android {
4033

4134
signingConfigs {
4235
create("release") {
43-
val alias = keyProp("PDFTECH_KEY_ALIAS", "keyAlias")
44-
val kPass = keyProp("PDFTECH_KEY_PASSWORD", "keyPassword")
45-
val sFile = keyProp("PDFTECH_STORE_FILE", "storeFile")
46-
val sPass = keyProp("PDFTECH_STORE_PASSWORD","storePassword")
47-
if (alias != null && kPass != null && sFile != null && sPass != null) {
48-
keyAlias = alias
49-
keyPassword = kPass
50-
storeFile = file(sFile)
51-
storePassword = sPass
52-
enableV1Signing = true
53-
enableV2Signing = true
54-
enableV3Signing = true
36+
val alias = env("PDFTECH_KEY_ALIAS")
37+
val kPass = env("PDFTECH_KEY_PASSWORD")
38+
val sFile = env("PDFTECH_STORE_FILE")
39+
val sPass = env("PDFTECH_STORE_PASSWORD")
40+
if (alias == null || kPass == null || sFile == null || sPass == null) {
41+
throw GradleException(
42+
"Release signing credentials missing. " +
43+
"Set PDFTECH_KEY_ALIAS, PDFTECH_KEY_PASSWORD, " +
44+
"PDFTECH_STORE_FILE and PDFTECH_STORE_PASSWORD " +
45+
"environment variables (or use a secure CI secret store)."
46+
)
5547
}
48+
keyAlias = alias
49+
keyPassword = kPass
50+
storeFile = file(sFile)
51+
storePassword = sPass
52+
// v1 désactivée (audit OWASP M5/M8 — attaque Janus).
53+
enableV1Signing = false
54+
enableV2Signing = true
55+
enableV3Signing = true
5656
}
5757
}
5858

5959
defaultConfig {
6060
applicationId = "com.pdftech.pdf_tech"
61-
minSdk = flutter.minSdkVersion
61+
// Pinné explicitement (coherence cross-app, reproductibilité CI).
62+
minSdk = 24
6263
// Pinné explicitement à 35 (cohérence avec compileSdk = 36) au lieu
6364
// de suivre `flutter.targetSdkVersion` qui peut diverger selon le SDK.
6465
targetSdk = 35
@@ -99,13 +100,10 @@ android {
99100

100101
buildTypes {
101102
release {
102-
// Fallback debug si pas de credentials release dispo (CI sans secrets)
103-
signingConfig = if (keyPropertiesFile.exists() ||
104-
System.getenv("PDFTECH_STORE_PASSWORD") != null) {
105-
signingConfigs.getByName("release")
106-
} else {
107-
signingConfigs.getByName("debug")
108-
}
103+
// Pas de fallback debug : un build release sans credentials valides
104+
// doit échouer explicitement (audit — empêche une signature debug
105+
// de fuiter en production).
106+
signingConfig = signingConfigs.getByName("release")
109107
isMinifyEnabled = true
110108
isShrinkResources = true
111109
proguardFiles(

‎android/app/src/main/AndroidManifest.xml‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33

44
<!-- Permissions -->
55
<uses-permission android:name="android.permission.INTERNET"/>
6-
<!-- P0 v1.13.4 — MANAGE_EXTERNAL_STORAGE réactivé. L'app est un
7-
gestionnaire/lecteur de PDFs : l'utilisateur a besoin d'ouvrir des
8-
documents répartis sur tout le stockage externe (Download, Documents,
9-
WhatsApp Documents, etc.) sans avoir à naviguer dans un picker SAF
10-
système par fichier. La permission n'est pas destinée au Play Store. -->
6+
<!-- P0 v1.13.4+ — MANAGE_EXTERNAL_STORAGE : PDF Tech est un gestionnaire
7+
de documents PDF. La permission est requise pour permettre à
8+
l'utilisateur de parcourir de manière fluide l'ensemble de son
9+
stockage externe (Download, Documents, dossiers de messageries…)
10+
et d'ouvrir des PDFs sans avoir à lancer un picker système par
11+
fichier. Cette fonctionnalité est optionnelle : l'application reste
12+
utilisable via le Storage Access Framework (SAF) si la permission est
13+
refusée. La permission n'est pas destinée au Play Store. -->
1114
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
1215
tools:ignore="ScopedStorage" />
1316

‎lib/screens/cloud/google_drive_screen.dart‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ class _GoogleDriveScreenState extends State<GoogleDriveScreen> {
8484
});
8585
await _loadFiles();
8686
} catch (e) {
87+
if (kDebugMode) debugPrint('[GoogleDriveScreen._signIn] $e');
8788
if (!mounted) return;
8889
setState(() => _checkingAuth = false);
89-
showErrorSnack(context, 'connexion : $e');
90+
showErrorSnack(context, 'Erreur de connexion a Google Drive');
9091
}
9192
}
9293

@@ -109,8 +110,9 @@ class _GoogleDriveScreenState extends State<GoogleDriveScreen> {
109110
final files = await _service.listPdfFiles();
110111
if (mounted) setState(() => _files = files);
111112
} catch (e) {
113+
if (kDebugMode) debugPrint('[GoogleDriveScreen._loadFiles] $e');
112114
if (!mounted) return;
113-
showErrorSnack(context, 'chargement : $e');
115+
showErrorSnack(context, 'Erreur de chargement des fichiers Drive');
114116
} finally {
115117
if (mounted) setState(() => _loadingFiles = false);
116118
}
@@ -131,8 +133,9 @@ class _GoogleDriveScreenState extends State<GoogleDriveScreen> {
131133
showInfoSnack(context, 'Fichier envoyé sur Google Drive');
132134
await _loadFiles();
133135
} catch (e) {
136+
if (kDebugMode) debugPrint('[GoogleDriveScreen._upload] $e');
134137
if (!mounted) return;
135-
showErrorSnack(context, 'upload : $e');
138+
showErrorSnack(context, 'Erreur d\'envoi sur Google Drive');
136139
} finally {
137140
if (mounted) setState(() => _uploading = false);
138141
}
@@ -160,8 +163,9 @@ class _GoogleDriveScreenState extends State<GoogleDriveScreen> {
160163
),
161164
);
162165
} catch (e) {
166+
if (kDebugMode) debugPrint('[GoogleDriveScreen._download] $e');
163167
if (!mounted) return;
164-
showErrorSnack(context, 'téléchargement : $e');
168+
showErrorSnack(context, 'Erreur de telechargement depuis Google Drive');
165169
} finally {
166170
if (mounted) setState(() => _downloadingId = null);
167171
}

0 commit comments

Comments
 (0)