- 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
30 lines
1.4 KiB
Kotlin
30 lines
1.4 KiB
Kotlin
package com.jttools.datacontrol.remote
|
|
|
|
import org.json.JSONObject
|
|
|
|
/** Identifiants d'un projet Firebase (ceux du bloc `firebaseConfig` de la console). */
|
|
data class FirebaseConfig(val apiKey: String, val appId: String, val projectId: String) {
|
|
companion object {
|
|
/**
|
|
* Lit ce que l'utilisateur colle : le bloc `firebaseConfig` de la console (JavaScript), un JSON,
|
|
* ou une chaîne « fc1:… » partagée par FamilyControl. Renvoie null si apiKey, appId ou projectId manque.
|
|
*/
|
|
fun parse(input: String): FirebaseConfig? {
|
|
val text = input.trim()
|
|
if (text.startsWith("fc1:")) {
|
|
return runCatching {
|
|
val json = JSONObject(String(java.util.Base64.getMimeDecoder().decode(text.removePrefix("fc1:")), Charsets.UTF_8))
|
|
build(json.optString("apiKey"), json.optString("appId"), json.optString("projectId"))
|
|
}.getOrNull()
|
|
}
|
|
fun pick(name: String) =
|
|
Regex("""["']?$name["']?\s*[:=]\s*["']([^"']+)["']""").find(text)?.groupValues?.get(1)
|
|
return build(pick("apiKey"), pick("appId"), pick("projectId"))
|
|
}
|
|
|
|
private fun build(apiKey: String?, appId: String?, projectId: String?): FirebaseConfig? =
|
|
if (apiKey.isNullOrBlank() || appId.isNullOrBlank() || projectId.isNullOrBlank()) null
|
|
else FirebaseConfig(apiKey.trim(), appId.trim(), projectId.trim())
|
|
}
|
|
}
|