fix: corrections de l'audit de sécurité et de robustesse

- VPN retiré : le contrôle reste activé (alerte parent, tunnel remonté après 30 s, autorisation redemandée à l'ouverture)
- Horloge de référence : changer date/heure/fuseau ne contourne plus les plages horaires ni le temps d'écran (signalé au parent)
- Mot de passe : PBKDF2 + attente croissante après 3 échecs ; conversion automatique des anciens hachages
- Écrans protégés : aucun affichage avant chargement des réglages ; effacement du journal protégé
- Signature release via keystore.properties (même clé que les versions publiées)
- Sauvegarde Google : réglages, appairage et journal exclus
- Alerte admin fiable (goAsync), relance refusée signalée, liste d'applis renvoyée à chaque installation, code d'appairage consommé
- Journal thread-safe et sans recopie à chaque ligne ; correctifs lint
- Tests unitaires (mot de passe, règles, versions, config Firebase) ; README aligné sur le comportement réel

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R9CBCVP5oDu2sfoYPisNCQ
This commit is contained in:
tuxgyverandClaude Opus 5.5 committed 2026-10-25 10:49:43 +01:00
1 parent f33776bbb5
commit e269e9932a
37 files changed
+809 -147

No files matched your search

@@ -4,16 +4,25 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.lifecycle.lifecycleScope
import com.jttools.datacontrol.data.SettingsRepository
import com.jttools.datacontrol.log.AppLog
import com.jttools.datacontrol.service.DataMonitorService
import com.jttools.datacontrol.ui.SystemActions
import com.jttools.datacontrol.ui.navigation.DataControlNavHost
import com.jttools.datacontrol.ui.theme.DataControlTheme
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject lateinit var settingsRepository: SettingsRepository
private lateinit var systemActions: SystemActions
private var vpnAskedThisSession = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -29,4 +38,21 @@ class MainActivity : ComponentActivity() {
}
}
}
override fun onResume() {
super.onResume()
// Contrôle actif mais autorisation VPN perdue (retirée, ou prise par un autre VPN) :
// on la redemande à l'ouverture, une seule fois par session pour ne pas boucler.
if (vpnAskedThisSession) return
lifecycleScope.launch {
if (settingsRepository.settingsFlow.first().controlEnabled && !systemActions.isVpnPrepared()) {
vpnAskedThisSession = true
AppLog.w("Pare-feu", "Contrôle actif sans autorisation VPN : nouvelle demande")
systemActions.requestVpnPermission { granted ->
AppLog.i("Pare-feu", "Autorisation VPN ${if (granted) "rétablie" else "REFUSÉE"}")
if (granted) DataMonitorService.start(this@MainActivity)
}
}
}
}
}