From 905e3248f2731ba28044c0e4e7250f56e4e99c69 Mon Sep 17 00:00:00 2001 From: Patrick Honkonen <1883101+SaintPatrck@users.noreply.github.com> Date: Wed, 6 Aug 2025 14:53:03 -0400 Subject: [PATCH] [PM-24411] Introduce BuildInfoManager for build-related information (#5654) --- .../manager/BitwardenBuildInfoManagerImpl.kt | 42 +++++++++++++++ .../manager/di/PlatformUiManagerModule.kt | 8 ++- authenticator/build.gradle.kts | 23 +++++++++ .../AuthenticatorBuildInfoManagerImpl.kt | 47 +++++++++++++++++ .../core/data/manager/BuildInfoManager.kt | 51 +++++++++++++++++++ .../util/BuildInfoManagerExtensions.kt | 38 ++++++++++++++ 6 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/manager/BitwardenBuildInfoManagerImpl.kt create mode 100644 authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/manager/AuthenticatorBuildInfoManagerImpl.kt create mode 100644 core/src/main/kotlin/com/bitwarden/core/data/manager/BuildInfoManager.kt create mode 100644 ui/src/main/kotlin/com/bitwarden/ui/platform/manager/util/BuildInfoManagerExtensions.kt diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/manager/BitwardenBuildInfoManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/manager/BitwardenBuildInfoManagerImpl.kt new file mode 100644 index 0000000000..d6b215ff09 --- /dev/null +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/manager/BitwardenBuildInfoManagerImpl.kt @@ -0,0 +1,42 @@ +package com.x8bit.bitwarden.ui.platform.manager + +import com.bitwarden.annotation.OmitFromCoverage +import com.bitwarden.core.data.manager.BuildInfoManager +import com.x8bit.bitwarden.BuildConfig + +/** + * Implementation of [BuildInfoManager] for Bitwarden Password Manager. + */ +@OmitFromCoverage +class BitwardenBuildInfoManagerImpl : BuildInfoManager { + override val applicationId: String + get() = BuildConfig.APPLICATION_ID + + override val isFdroid: Boolean + get() = BuildConfig.FLAVOR == "fdroid" + + override val isDevBuild: Boolean + get() = BuildConfig.BUILD_TYPE == "debug" + + override val versionData: String + get() = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" + + override val sdkData: String + get() = BuildConfig.SDK_VERSION + + override val ciBuildInfo: String? + get() = BuildConfig.CI_INFO.takeUnless { it.isBlank() } + + override val buildFlavorName: String + get() = when (BuildConfig.FLAVOR) { + "standard" -> "" + else -> "-${BuildConfig.FLAVOR}" + } + + override val buildTypeName: String + get() = when (BuildConfig.BUILD_TYPE) { + "debug" -> "dev" + "release" -> "prod" + else -> BuildConfig.BUILD_TYPE + } +} diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/manager/di/PlatformUiManagerModule.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/manager/di/PlatformUiManagerModule.kt index 9c3f6ae2ee..c371aa6451 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/manager/di/PlatformUiManagerModule.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/manager/di/PlatformUiManagerModule.kt @@ -1,7 +1,9 @@ package com.x8bit.bitwarden.ui.platform.manager.di import android.content.Context +import com.bitwarden.core.data.manager.BuildInfoManager import com.bitwarden.data.manager.DispatcherManager +import com.x8bit.bitwarden.ui.platform.manager.BitwardenBuildInfoManagerImpl import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManagerImpl import com.x8bit.bitwarden.ui.platform.manager.resource.ResourceManager @@ -21,7 +23,11 @@ import javax.inject.Singleton */ @Module @InstallIn(SingletonComponent::class) -class PlatformUiManagerModule { +object PlatformUiManagerModule { + + @Provides + @Singleton + fun provideBuildInfoManager(): BuildInfoManager = BitwardenBuildInfoManagerImpl() @Provides @Singleton diff --git a/authenticator/build.gradle.kts b/authenticator/build.gradle.kts index 74d75ca3b8..2694c98a49 100644 --- a/authenticator/build.gradle.kts +++ b/authenticator/build.gradle.kts @@ -2,6 +2,8 @@ import com.android.build.gradle.internal.api.BaseVariantOutputImpl import com.google.protobuf.gradle.proto import dagger.hilt.android.plugin.util.capitalize import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import java.io.FileInputStream +import java.util.Properties plugins { alias(libs.plugins.android.application) @@ -18,6 +20,16 @@ plugins { alias(libs.plugins.sonarqube) } +/** + * Loads CI-specific build properties that are not checked into source control. + */ +val ciProperties = Properties().apply { + val ciPropsFile = File(rootDir, "ci.properties") + if (ciPropsFile.exists()) { + FileInputStream(ciPropsFile).use { load(it) } + } +} + android { namespace = "com.bitwarden.authenticator" compileSdk = libs.versions.compileSdk.get().toInt() @@ -34,6 +46,17 @@ android { versionName = libs.versions.appVersionName.get() testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + buildConfigField( + type = "String", + name = "CI_INFO", + value = "${ciProperties.getOrDefault("ci.info", "\"\uD83D\uDCBB local\"")}", + ) + buildConfigField( + type = "String", + name = "SDK_VERSION", + value = "\"${libs.versions.bitwardenSdk.get()}\"", + ) } androidResources { diff --git a/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/manager/AuthenticatorBuildInfoManagerImpl.kt b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/manager/AuthenticatorBuildInfoManagerImpl.kt new file mode 100644 index 0000000000..8d61cdd4d7 --- /dev/null +++ b/authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/platform/manager/AuthenticatorBuildInfoManagerImpl.kt @@ -0,0 +1,47 @@ +package com.bitwarden.authenticator.ui.platform.manager + +import com.bitwarden.annotation.OmitFromCoverage +import com.bitwarden.authenticator.BuildConfig +import com.bitwarden.core.data.manager.BuildInfoManager + +/** + * Implementation of [BuildInfoManager] for Bitwarden Authenticator. + */ +@OmitFromCoverage +class AuthenticatorBuildInfoManagerImpl : BuildInfoManager { + override val applicationId: String + get() = BuildConfig.APPLICATION_ID + + /** + * Indicates whether the build is from the F-Droid flavor. + * This is always false for Authenticator as it does not have an F-Droid compatible flavor. + */ + override val isFdroid: Boolean + get() = false + + override val isDevBuild: Boolean + get() = BuildConfig.BUILD_TYPE == "debug" + + override val versionData: String + get() = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" + + override val sdkData: String + get() = BuildConfig.SDK_VERSION + + override val ciBuildInfo: String? + get() = BuildConfig.CI_INFO.takeUnless { it.isBlank() } + + /** + * Returns the build flavor name. + * For Authenticator, this is always an empty string as it does not have different flavors. + */ + override val buildFlavorName: String + get() = "" + + override val buildTypeName: String + get() = when (BuildConfig.BUILD_TYPE) { + "debug" -> "dev" + "release" -> "prod" + else -> BuildConfig.BUILD_TYPE + } +} diff --git a/core/src/main/kotlin/com/bitwarden/core/data/manager/BuildInfoManager.kt b/core/src/main/kotlin/com/bitwarden/core/data/manager/BuildInfoManager.kt new file mode 100644 index 0000000000..29f746e5a1 --- /dev/null +++ b/core/src/main/kotlin/com/bitwarden/core/data/manager/BuildInfoManager.kt @@ -0,0 +1,51 @@ +package com.bitwarden.core.data.manager + +/** + * An manager interface for accessing build information for a Bitwarden client application. + * + * This interface provides properties to access various build-related information such as + * whether the build is an F-Droid flavor, if it's a dev build, and details about the app version, + * SDK version, device information, and CI build info. + */ +interface BuildInfoManager { + + /** + * The ID of the running application. + */ + val applicationId: String + + /** + * A boolean property that indicates whether the current build flavor is "fdroid". + */ + val isFdroid: Boolean + + /** + * A boolean property that indicates whether the current build is a dev build. + */ + val isDevBuild: Boolean + + /** + * A string that represents a displayable app version. + */ + val versionData: String + + /** + * A string that represents a displayable SDK version. + */ + val sdkData: String + + /** + * A string representing the CI information if available. + */ + val ciBuildInfo: String? + + /** + * A string representing the build flavor or blank if it is the standard configuration. + */ + val buildFlavorName: String + + /** + * A string representing the build type. + */ + val buildTypeName: String +} diff --git a/ui/src/main/kotlin/com/bitwarden/ui/platform/manager/util/BuildInfoManagerExtensions.kt b/ui/src/main/kotlin/com/bitwarden/ui/platform/manager/util/BuildInfoManagerExtensions.kt new file mode 100644 index 0000000000..995ad42c41 --- /dev/null +++ b/ui/src/main/kotlin/com/bitwarden/ui/platform/manager/util/BuildInfoManagerExtensions.kt @@ -0,0 +1,38 @@ +@file:OmitFromCoverage + +package com.bitwarden.ui.platform.manager.util + +import android.os.Build +import com.bitwarden.annotation.OmitFromCoverage +import com.bitwarden.core.data.manager.BuildInfoManager + +/** + * A string representing the device brand and model. + */ +val BuildInfoManager.deviceBrandModel: String + get() = "\uD83D\uDCF1 ${Build.BRAND} ${Build.MODEL}" + +/** + * A string representing the operating system information. + */ +val BuildInfoManager.osInfo: String + get() = "\uD83E\uDD16 ${Build.VERSION.RELEASE}@${Build.VERSION.SDK_INT}" + +/** + * A string representing the build information. + */ +val BuildInfoManager.buildInfo: String + get() = "\uD83D\uDCE6 $buildTypeName" + + buildFlavorName.takeUnless { it.isBlank() }?.let { " $it" }.orEmpty() + +/** + * A string that represents device data. + */ +val BuildInfoManager.deviceData: String + get() = "$deviceBrandModel $osInfo $buildInfo" + +/** + * The authority for the FileProvider used in the application. + */ +val BuildInfoManager.fileProviderAuthority: String + get() = "$applicationId.fileprovider"