diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b3414460..ff09a750 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -101,6 +101,7 @@ dependencies { debugImplementation(libs.thirdparty.leakcanary) add("nonFreeImplementation", libs.thirdparty.nonfree.googlePlayAuthApiPhone) add("nonFreeImplementation", libs.thirdparty.nonfree.sentry) + add("freeImplementation", projects.sentryStub) androidTestImplementation(libs.bundles.testDependencies) androidTestImplementation(libs.bundles.androidTestDependencies) diff --git a/app/src/main/java/dev/msfjarvis/aps/Application.kt b/app/src/main/java/dev/msfjarvis/aps/Application.kt index 1a72655b..0c7def1c 100644 --- a/app/src/main/java/dev/msfjarvis/aps/Application.kt +++ b/app/src/main/java/dev/msfjarvis/aps/Application.kt @@ -15,11 +15,15 @@ import dagger.hilt.android.HiltAndroidApp import dev.msfjarvis.aps.injection.context.FilesDirPath import dev.msfjarvis.aps.injection.prefs.SettingsPreferences import dev.msfjarvis.aps.util.extensions.getString +import dev.msfjarvis.aps.util.features.Feature +import dev.msfjarvis.aps.util.features.Features import dev.msfjarvis.aps.util.git.sshj.setUpBouncyCastleForSshj import dev.msfjarvis.aps.util.proxy.ProxyUtils import dev.msfjarvis.aps.util.settings.GitSettings import dev.msfjarvis.aps.util.settings.PreferenceKeys import dev.msfjarvis.aps.util.settings.runMigrations +import io.sentry.Sentry +import io.sentry.protocol.User import javax.inject.Inject import logcat.AndroidLogcatLogger import logcat.LogPriority.DEBUG @@ -33,6 +37,7 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere @Inject @FilesDirPath lateinit var filesDirPath: String @Inject lateinit var proxyUtils: ProxyUtils @Inject lateinit var gitSettings: GitSettings + @Inject lateinit var features: Features override fun onCreate() { super.onCreate() @@ -48,6 +53,14 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere runMigrations(filesDirPath, prefs, gitSettings) proxyUtils.setDefaultProxy() DynamicColors.applyToActivitiesIfAvailable(this) + Sentry.configureScope { scope -> + val user = User() + user.others = + Feature.VALUES.associate { feature -> + "features.${feature.configKey}" to features.isEnabled(feature).toString() + } + scope.user = user + } } override fun onTerminate() { diff --git a/app/src/main/java/dev/msfjarvis/aps/util/features/Feature.kt b/app/src/main/java/dev/msfjarvis/aps/util/features/Feature.kt index 7ae2e642..4eef003d 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/features/Feature.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/features/Feature.kt @@ -15,4 +15,9 @@ enum class Feature( /** Opt into the new PGP backend powered by the PGPainless library. */ EnablePGPainlessBackend(false, "enable_pgp_v2_backend"), + ; + + companion object { + @JvmField val VALUES = values() + } } diff --git a/app/src/nonFree/AndroidManifest.xml b/app/src/nonFree/AndroidManifest.xml index 2f8d2746..83103b18 100644 --- a/app/src/nonFree/AndroidManifest.xml +++ b/app/src/nonFree/AndroidManifest.xml @@ -6,6 +6,6 @@ - + diff --git a/build-logic/android-plugins/build.gradle.kts b/build-logic/android-plugins/build.gradle.kts index cdc7c315..dfe77e89 100644 --- a/build-logic/android-plugins/build.gradle.kts +++ b/build-logic/android-plugins/build.gradle.kts @@ -35,4 +35,5 @@ dependencies { implementation(libs.build.dokka) implementation(libs.build.mavenpublish) implementation(libs.build.semver) + implementation(libs.build.sentry) } diff --git a/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.sentry.gradle.kts b/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.sentry.gradle.kts index 4c22e8c8..0407d808 100644 --- a/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.sentry.gradle.kts +++ b/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.sentry.gradle.kts @@ -2,11 +2,14 @@ import flavors.FlavorDimensions import flavors.ProductFlavors +import io.sentry.android.gradle.InstrumentationFeature -plugins { id("com.android.application") } +plugins { + id("com.android.application") + id("io.sentry.android.gradle") +} val SENTRY_DSN_PROPERTY = "SENTRY_DSN" -val INVOKED_FROM_IDE_PROPERTY = "android.injected.invoked.from.ide" android { androidComponents { @@ -14,12 +17,17 @@ android { val sentryDsn = project.providers.environmentVariable(SENTRY_DSN_PROPERTY) if (sentryDsn.isPresent) { variant.manifestPlaceholders.put("sentryDsn", sentryDsn.get()) - } else if (project.providers.gradleProperty(INVOKED_FROM_IDE_PROPERTY).orNull != "true") { - // Checking for 'INVOKED_FROM_IDE_PROPERTY' prevents failures during Gradle sync by the IDE - throw GradleException( - "The '${SENTRY_DSN_PROPERTY}' environment variable must be set when building the ${ProductFlavors.NON_FREE} flavor" - ) } } } } + +sentry { + autoUploadProguardMapping.set(true) + ignoredBuildTypes.set(setOf("debug")) + ignoredFlavors.set(setOf(ProductFlavors.FREE)) + tracingInstrumentation { + enabled.set(true) + features.set(setOf(InstrumentationFeature.FILE_IO)) + } +} diff --git a/build-logic/kotlin-plugins/src/main/kotlin/com.github.android-password-store.binary-compatibility.gradle.kts b/build-logic/kotlin-plugins/src/main/kotlin/com.github.android-password-store.binary-compatibility.gradle.kts index ad6080e0..2723c8dc 100644 --- a/build-logic/kotlin-plugins/src/main/kotlin/com.github.android-password-store.binary-compatibility.gradle.kts +++ b/build-logic/kotlin-plugins/src/main/kotlin/com.github.android-password-store.binary-compatibility.gradle.kts @@ -16,6 +16,7 @@ apiValidation { "format-common", "diceware", "random", + "sentry-stub", "ui-compose", ) } diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts index dc8e13b2..144cd7f7 100644 --- a/build-logic/settings.gradle.kts +++ b/build-logic/settings.gradle.kts @@ -2,6 +2,7 @@ * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. * SPDX-License-Identifier: GPL-3.0-only */ +@file:Suppress("UnstableApiUsage") rootProject.name = "build-logic" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 256b2797..b2c1a09c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,6 +50,7 @@ build-mavenpublish = "com.vanniktech:gradle-maven-publish-plugin:0.19.0" build-okhttp = "com.squareup.okhttp3:okhttp:4.9.3" build-r8 = "com.android.tools:r8:3.3.15-dev" build-semver = "com.vdurmont:semver4j:3.1.0" +build-sentry = "io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin:3.0.0-rc.3" build-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.3.0" dagger-hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } diff --git a/sentry-stub/build.gradle.kts b/sentry-stub/build.gradle.kts new file mode 100644 index 00000000..f91458dd --- /dev/null +++ b/sentry-stub/build.gradle.kts @@ -0,0 +1,4 @@ +plugins { + kotlin("jvm") + id("com.github.android-password-store.kotlin-library") +} diff --git a/sentry-stub/src/main/kotlin/io/sentry/Scope.kt b/sentry-stub/src/main/kotlin/io/sentry/Scope.kt new file mode 100644 index 00000000..34557a84 --- /dev/null +++ b/sentry-stub/src/main/kotlin/io/sentry/Scope.kt @@ -0,0 +1,10 @@ +@file:Suppress("Unused", "UNUSED_PARAMETER") + +package io.sentry + +import io.sentry.protocol.User + +public class Scope { + public var user: User? = null + public fun setTag(tag: String, value: String) {} +} diff --git a/sentry-stub/src/main/kotlin/io/sentry/Sentry.kt b/sentry-stub/src/main/kotlin/io/sentry/Sentry.kt new file mode 100644 index 00000000..e64f176e --- /dev/null +++ b/sentry-stub/src/main/kotlin/io/sentry/Sentry.kt @@ -0,0 +1,8 @@ +@file:Suppress("Unused", "UNUSED_PARAMETER") + +package io.sentry + +/** Stubs for the Sentry SDK */ +public object Sentry { + public fun configureScope(callback: (Scope) -> Unit) {} +} diff --git a/sentry-stub/src/main/kotlin/io/sentry/protocol/User.kt b/sentry-stub/src/main/kotlin/io/sentry/protocol/User.kt new file mode 100644 index 00000000..5b60ba72 --- /dev/null +++ b/sentry-stub/src/main/kotlin/io/sentry/protocol/User.kt @@ -0,0 +1,12 @@ +@file:Suppress("Unused", "UNUSED_PARAMETER") + +package io.sentry.protocol + +public data class User( + public var email: String? = null, + public var id: String? = null, + public var username: String? = null, + public var ipAddress: String? = null, + public var others: Map? = null, + public var unknown: Map? = null, +) diff --git a/settings.gradle.kts b/settings.gradle.kts index e0ab512d..1840ee1c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,6 +2,7 @@ * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved. * SPDX-License-Identifier: GPL-3.0-only */ +@file:Suppress("UnstableApiUsage") rootProject.name = "APS" @@ -54,4 +55,6 @@ include("passgen:diceware") include("passgen:random") +include("sentry-stub") + include("ui-compose")