fix: configuration Firebase acceptée avec guillemets typographiques ou google-services.json

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 11:16:07 +01:00
1 parent 1d707f8785
commit 11d7ed1fa6
2 files changed
+31 -4

No files matched your search

@@ -7,7 +7,7 @@ data class FirebaseConfig(val apiKey: String, val appId: String, val projectId:
companion object { companion object {
/** /**
* Lit ce que l'utilisateur colle : le bloc `firebaseConfig` de la console (JavaScript), un JSON, * 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. * le fichier google-services.json, ou une chaîne « fc1:… » partagée par FamilyControl. Renvoie null si apiKey, appId ou projectId manque.
*/ */
fun parse(input: String): FirebaseConfig? { fun parse(input: String): FirebaseConfig? {
val text = input.trim() val text = input.trim()
@@ -17,9 +17,17 @@ data class FirebaseConfig(val apiKey: String, val appId: String, val projectId:
build(json.optString("apiKey"), json.optString("appId"), json.optString("projectId")) build(json.optString("apiKey"), json.optString("appId"), json.optString("projectId"))
}.getOrNull() }.getOrNull()
} }
fun pick(name: String) = // Guillemets typographiques (souvent insérés par un copier-coller sur téléphone) → droits.
Regex("""["']?$name["']?\s*[:=]\s*["']([^"']+)["']""").find(text)?.groupValues?.get(1) val plain = text.replace(Regex("[“”„«»]"), "\"").replace(Regex("[‘’]"), "'")
return build(pick("apiKey"), pick("appId"), pick("projectId")) // Noms du bloc Web (apiKey…) ou du fichier google-services.json de l'application Android.
fun pick(vararg names: String) = names.firstNotNullOfOrNull { name ->
Regex("""["']?\b$name["']?\s*[:=]\s*["']\s*([^"'\s]+)\s*["']""").find(plain)?.groupValues?.get(1)
}
return build(
pick("apiKey", "current_key"),
pick("appId", "mobilesdk_app_id"),
pick("projectId", "project_id")
)
} }
private fun build(apiKey: String?, appId: String?, projectId: String?): FirebaseConfig? = private fun build(apiKey: String?, appId: String?, projectId: String?): FirebaseConfig? =
@@ -35,6 +35,25 @@ class FirebaseConfigTest {
assertEquals(expected, FirebaseConfig.parse(" fc1:${b64.chunked(20).joinToString("\n")} ")) assertEquals(expected, FirebaseConfig.parse(" fc1:${b64.chunked(20).joinToString("\n")} "))
} }
@Test fun `guillemets typographiques`() {
val js = "apiKey: “AIzaTest”, projectId: «mon-projet», appId: ‘1:123:android:abc’"
assertEquals(expected, FirebaseConfig.parse(js))
}
@Test fun `fichier google-services json`() {
val gs = """
{
"project_info": { "project_number": "123", "project_id": "mon-projet", "storage_bucket": "mon-projet.appspot.com" },
"client": [ {
"client_info": { "mobilesdk_app_id": "1:123:android:abc",
"android_client_info": { "package_name": "com.jttools.datacontrol" } },
"api_key": [ { "current_key": "AIzaTest" } ]
} ]
}
""".trimIndent()
assertEquals(expected, FirebaseConfig.parse(gs))
}
@Test fun `champ manquant ou illisible`() { @Test fun `champ manquant ou illisible`() {
assertNull(FirebaseConfig.parse("""{"apiKey":"AIzaTest","projectId":"mon-projet"}""")) assertNull(FirebaseConfig.parse("""{"apiKey":"AIzaTest","projectId":"mon-projet"}"""))
assertNull(FirebaseConfig.parse("fc1:!!!")) assertNull(FirebaseConfig.parse("fc1:!!!"))