diff --git a/features/login/impl/build.gradle.kts b/features/login/impl/build.gradle.kts index e6381c9162..f36cda49f6 100644 --- a/features/login/impl/build.gradle.kts +++ b/features/login/impl/build.gradle.kts @@ -1,3 +1,4 @@ +import extension.buildConfigFieldStr import extension.setupDependencyInjection import extension.testCommonDependencies @@ -23,6 +24,29 @@ android { isIncludeAndroidResources = true } } + + buildFeatures { + buildConfig = true + } + + buildTypes { + val elementClassicPackageKey = "elementClassicPackage" + val elementClassicPackage = "im.vector.app" + val elementClassicPackageDebug = "$elementClassicPackage.debug" + val elementClassicPackageNightly = "$elementClassicPackage.nightly" + getByName("release") { + manifestPlaceholders[elementClassicPackageKey] = elementClassicPackage + buildConfigFieldStr(elementClassicPackageKey, elementClassicPackage) + } + getByName("debug") { + manifestPlaceholders[elementClassicPackageKey] = elementClassicPackageDebug + buildConfigFieldStr(elementClassicPackageKey, elementClassicPackageDebug) + } + register("nightly") { + manifestPlaceholders[elementClassicPackageKey] = elementClassicPackageNightly + buildConfigFieldStr(elementClassicPackageKey, elementClassicPackageNightly) + } + } } setupDependencyInjection() diff --git a/features/login/impl/src/main/AndroidManifest.xml b/features/login/impl/src/main/AndroidManifest.xml index f2d84131a7..295658f6d4 100644 --- a/features/login/impl/src/main/AndroidManifest.xml +++ b/features/login/impl/src/main/AndroidManifest.xml @@ -13,8 +13,9 @@ + + + - - diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/classic/ElementClassicConnection.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/classic/ElementClassicConnection.kt index c983ea04ba..f895dd781e 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/classic/ElementClassicConnection.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/classic/ElementClassicConnection.kt @@ -20,9 +20,8 @@ import android.os.Messenger import android.os.RemoteException import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.login.impl.BuildConfig import io.element.android.libraries.core.log.logger.LoggerTag -import io.element.android.libraries.core.meta.BuildMeta -import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.di.annotations.ApplicationContext import io.element.android.libraries.matrix.api.core.UserId @@ -44,7 +43,11 @@ sealed interface ElementClassicConnectionState { object Idle : ElementClassicConnectionState object ElementClassicNotFound : ElementClassicConnectionState object ElementClassicReadyNoSession : ElementClassicConnectionState - data class ElementClassicReady(val userId: UserId) : ElementClassicConnectionState + data class ElementClassicReady( + val userId: UserId, + val secrets: String, + ) : ElementClassicConnectionState + data class Error(val error: String) : ElementClassicConnectionState } @@ -56,7 +59,6 @@ class DefaultElementClassicConnection( private val context: Context, @AppCoroutineScope private val coroutineScope: CoroutineScope, - private val buildMeta: BuildMeta, ) : ElementClassicConnection { // Messenger for communicating with the service. private var messenger: Messenger? = null @@ -101,7 +103,7 @@ class DefaultElementClassicConnection( // applications replace our component. try { val intentService = Intent() - intentService.setComponent(getElementClassicComponent(buildMeta)) + intentService.setComponent(getElementClassicComponent()) if (context.bindService(intentService, serviceConnection, BIND_AUTO_CREATE)) { Timber.tag(loggerTag.value).d("Binding returned true") } else { @@ -198,17 +200,8 @@ class DefaultElementClassicConnection( } } - private fun getElementClassicComponent(buildMeta: BuildMeta) = ComponentName( - buildString { - append(ELEMENT_CLASSIC_APP_ID) - append( - when (buildMeta.buildType) { - BuildType.DEBUG -> ELEMENT_CLASSIC_APP_ID_DEBUG_SUFFIX - BuildType.NIGHTLY -> ELEMENT_CLASSIC_APP_ID_NIGHTLY_SUFFIX - BuildType.RELEASE -> ELEMENT_CLASSIC_APP_ID_RELEASE_SUFFIX - } - ) - }, + private fun getElementClassicComponent() = ComponentName( + BuildConfig.elementClassicPackage, ELEMENT_CLASSIC_SERVICE_FULL_CLASS_NAME, ) @@ -220,9 +213,14 @@ class DefaultElementClassicConnection( if (error != null) { ElementClassicConnectionState.Error(error) } else { - val userId = getString(KEY_USER_ID_STR)?.let(::UserId) + val userId = getString(KEY_USER_ID_STR)?.takeIf { it.isNotEmpty() }?.let(::UserId) if (userId != null) { - ElementClassicConnectionState.ElementClassicReady(userId) + val secrets = getString(KEY_SECRETS_STR)?.takeIf { it.isNotEmpty() } + if (secrets == null) { + ElementClassicConnectionState.Error("No secrets received from Element Classic") + } else { + ElementClassicConnectionState.ElementClassicReady(userId, secrets) + } } else { ElementClassicConnectionState.ElementClassicReadyNoSession } @@ -232,18 +230,31 @@ class DefaultElementClassicConnection( // Everything in this companion object must match what is defined in Element Classic private companion object { + const val ELEMENT_CLASSIC_SERVICE_FULL_CLASS_NAME = "im.vector.app.features.importer.ImporterService" + // Command to the service to get the data. const val MSG_GET_DATA = 1 - const val ELEMENT_CLASSIC_APP_ID = "im.vector.app" - const val ELEMENT_CLASSIC_APP_ID_DEBUG_SUFFIX = ".debug" - const val ELEMENT_CLASSIC_APP_ID_NIGHTLY_SUFFIX = ".nightly" - const val ELEMENT_CLASSIC_APP_ID_RELEASE_SUFFIX = "" - - const val ELEMENT_CLASSIC_SERVICE_FULL_CLASS_NAME = "im.vector.app.features.importer.ImporterService" - // Keys for the bundle returned from the service const val KEY_ERROR_STR = "error" const val KEY_USER_ID_STR = "userId" + + /** + * Key to extract the secrets from the bundle, as a Json string. + * Json will have this format: + * { + * "cross_signing" : { + * "master_key" : "z8RUxnaAGu___REDACTED___k+BQL9o", + * "user_signing_key" : "baJHzA___REDACTED___xMLbSUAXw9QUzqms", + * "self_signing_key" : "DU0CvLtR2G/___REDACTED___dV/MONNq4nsQhM" + * }, + * "backup" : { + * "algorithm" : "m.megolm_backup.v1.curve25519-aes-sha2", + * "key" : "VzncmQ+UOV___REDACTED___patxDz7m0Nc", + * "backup_version" : "1" + * } + * } + */ + const val KEY_SECRETS_STR = "secrets" } }