Files
com.wisp.app/app/build.gradle.kts
T
Barry Deen 977da039df fix(auth): restore encrypted Drive backup; drop deterministic sub derivation
#530 derived the Nostr private key as SHA-256(sub || index). The Google
sub claim is not a secret — any app the user signs into with Google
gets the same sub value for that account/OAuth-client pair, and even
across clients it leaks via id_token introspection. That meant any
third party with the sub could regenerate the user's nsec offline. A
non-starter.

Reverts to the #528 design:

  - GoogleSignInManager re-acquires the drive.appdata OAuth scope via
    AuthorizationClient
  - DriveBackupService reads/writes wisp_nsec_<npub>.bin blobs in the
    per-app appDataFolder (other apps cannot see this folder)
  - BackupCrypto already provided HMAC-SHA256(sub)-derived key + NIP-44
    encryption; that file was not touched by #530 and is reused as-is
  - GoogleAuthViewModel lists backups, surfaces a chooser with avatar +
    display name fetched from kind-0 events, and decrypts only on
    explicit Restore
  - "Create new account" generates a fresh keypair, encrypts, and
    uploads a new blob

The encryption key is still derived from sub, but the attack surface
is fundamentally different: an attacker now needs both the sub AND
read access to Wisp's appDataFolder in the user's Drive. The folder
is sandboxed per-app, so the only paths in are the user's own Google
account or a Wisp app compromise. That's the same trust boundary as
"can sign in to the user's Google account."

Splash button styling kept as-is (dark variant from #530 retained — a
cosmetic choice independent of the security model).

Reverts: 3d3c6e1, de88bdd
2026-05-15 15:02:45 -04:00

122 lines
3.9 KiB
Kotlin

import java.util.Properties
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.objectbox)
}
android {
val baseApplicationId = rootProject.extra["baseApplicationId"] as String
val debugApplicationIdSuffix = rootProject.extra["debugApplicationIdSuffix"] as String
namespace = "com.wisp.app"
compileSdk = 35
defaultConfig {
applicationId = baseApplicationId
minSdk = 26
targetSdk = 35
versionCode = 79
versionName = "1.0.5"
resValue("string", "app_name", "Wisp")
ndk {
abiFilters += "arm64-v8a"
}
val localProps = rootProject.file("local.properties")
val breezApiKey = if (localProps.exists()) {
val props = Properties()
localProps.inputStream().use { props.load(it) }
props.getProperty("breez.api.key", "")
} else ""
buildConfigField("String", "BREEZ_API_KEY", "\"$breezApiKey\"")
buildConfigField("String", "BREEZ_SDK_VERSION", "\"${libs.versions.breez.sdk.spark.get()}\"")
}
buildTypes {
debug {
applicationIdSuffix = debugApplicationIdSuffix
resValue("string", "app_name", "Wisp Debug")
}
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
packaging {
jniLibs.useLegacyPackaging = false
}
buildFeatures {
compose = true
buildConfig = true
}
}
dependencies {
testImplementation(libs.kotlinx.serialization.json)
testImplementation("junit:junit:4.13.2")
implementation(platform(libs.compose.bom))
implementation(libs.compose.ui)
implementation(libs.compose.ui.graphics)
implementation(libs.compose.material3)
implementation(libs.compose.icons.extended)
implementation(libs.activity.compose)
implementation(libs.navigation.compose)
implementation(libs.lifecycle.viewmodel.compose)
implementation(libs.lifecycle.runtime.compose)
implementation(libs.okhttp)
implementation(libs.kotlinx.serialization.json)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.secp256k1.kmp)
implementation(libs.secp256k1.kmp.jni.android)
implementation(libs.coil.compose)
implementation(libs.coil.gif)
implementation(libs.coil.network.okhttp)
implementation(libs.coil.video)
implementation(libs.security.crypto)
implementation(libs.bouncycastle)
implementation(libs.media3.exoplayer)
implementation(libs.media3.exoplayer.hls)
implementation(libs.media3.datasource.okhttp)
implementation(libs.media3.ui)
implementation(libs.media3.session)
implementation(libs.biometric)
implementation(libs.splashscreen)
implementation(libs.profileinstaller)
implementation(libs.zxing.core)
implementation(libs.mlkit.translate)
implementation(libs.mlkit.language.id)
implementation(libs.kotlinx.coroutines.play.services)
implementation(libs.objectbox.android)
implementation(libs.objectbox.kotlin)
implementation(libs.breez.sdk.spark)
implementation(libs.mlkit.barcode)
implementation(libs.camerax.core)
implementation(libs.camerax.camera2)
implementation(libs.camerax.lifecycle)
implementation(libs.camerax.view)
implementation(libs.camerax.mlkit)
implementation(libs.androidx.credentials)
implementation(libs.androidx.credentials.play.services.auth)
implementation(libs.googleid)
implementation(libs.play.services.auth)
}