diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d211c93..1922962 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,6 +8,12 @@ plugins { id("org.jetbrains.kotlin.plugin.compose") } +// App Check (Play Integrity) needs the Google Services plugin, which requires google-services.json. +// Apply it only when that file is present so the build still works before Firebase is configured. +if (project.file("google-services.json").exists()) { + apply(plugin = "com.google.gms.google-services") +} + fun String.asBuildConfigStringLiteral(): String = "\"" + replace("\\", "\\\\").replace("\"", "\\\"") + "\"" @@ -409,6 +415,11 @@ dependencies { implementation("org.json:json:20240303") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0") + // Firebase App Check (Play Integrity) — attests requests come from the genuine app. + implementation(platform("com.google.firebase:firebase-bom:33.7.0")) + implementation("com.google.firebase:firebase-appcheck") + implementation("com.google.firebase:firebase-appcheck-playintegrity") + testImplementation("junit:junit:4.13.2") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4b02a24..27d35ab 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ android:required="false" /> val call = client.newCall(request) diff --git a/app/src/main/java/com/b2/ultraprocessed/network/llm/ProxyResultChatWorkflow.kt b/app/src/main/java/com/b2/ultraprocessed/network/llm/ProxyResultChatWorkflow.kt index e9a1657..3a1890f 100644 --- a/app/src/main/java/com/b2/ultraprocessed/network/llm/ProxyResultChatWorkflow.kt +++ b/app/src/main/java/com/b2/ultraprocessed/network/llm/ProxyResultChatWorkflow.kt @@ -33,11 +33,14 @@ class ProxyResultChatWorkflow( .put("history", JSONArray(trimHistory(history).map { it.toJson() })) val url = "${baseUrl.trimEnd('/')}/chat" AnalysisTelemetry.event("proxy_chat_request_start url=$url") - val request = Request.Builder() + val requestBuilder = Request.Builder() .url(url) .header("Content-Type", "application/json") .post(payload.toString().toRequestBody(JSON_MEDIA_TYPE)) - .build() + AppCheckTokenProvider.currentToken()?.let { + requestBuilder.header(AppCheckTokenProvider.X_FIREBASE_APPCHECK_HEADER, it) + } + val request = requestBuilder.build() client.newCall(request).execute().use { response -> val raw = response.body?.string().orEmpty() AnalysisTelemetry.event("proxy_chat_response http=${response.code}") diff --git a/build.gradle.kts b/build.gradle.kts index f360e1d..419af41 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,4 +2,5 @@ plugins { id("com.android.application") version "9.1.1" apply false id("org.jetbrains.kotlin.android") version "2.2.10" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.2.10" apply false + id("com.google.gms.google-services") version "4.4.2" apply false }