From 82bc6544b9e2d8e87c7efc176cb910ae1c7e94c6 Mon Sep 17 00:00:00 2001 From: Nishith Khanna Date: Fri, 2 Jan 2026 17:09:50 +0530 Subject: [PATCH] feat: add support for switching to staging server via adb --- .gitlab-ci.yml | 57 ++++--------------- app/build.gradle | 6 +- .../authorization/IdentityProvider.kt | 28 +++++++-- .../davdroid/syncadapter/AccountUtils.kt | 7 ++- .../ui/setup/MurenaOpenIdAuthFragment.kt | 6 +- .../setup/OpenIdAuthenticationBaseFragment.kt | 2 +- .../davdroid/util/MurenaServerConfig.kt | 47 +++++++++++++++ 7 files changed, 96 insertions(+), 57 deletions(-) create mode 100644 app/src/main/kotlin/at/bitfire/davdroid/util/MurenaServerConfig.kt diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9a3ce1ae3..cc05df8f6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,6 +21,10 @@ before_script: - echo GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID >> local.properties - echo GOOGLE_REDIRECT_URI=$GOOGLE_REDIRECT_URI >> local.properties - echo YAHOO_CLIENT_ID=$YAHOO_CLIENT_ID >> local.properties + - echo MURENA_BASE_URL_PRODUCTION=$MURENA_BASE_URL_PRODUCTION >> local.properties + - echo MURENA_DISCOVERY_END_POINT_PRODUCTION=$MURENA_DISCOVERY_END_POINT_PRODUCTION >> local.properties + - echo MURENA_BASE_URL_STAGING=$MURENA_BASE_URL_STAGING >> local.properties + - echo MURENA_DISCOVERY_END_POINT_STAGING=$MURENA_DISCOVERY_END_POINT_STAGING >> local.properties - export GRADLE_USER_HOME=$(pwd)/.gradle - chmod +x ./gradlew @@ -29,30 +33,9 @@ cache: paths: - .gradle/ -build-prod: +build: stage: build script: - - echo MURENA_BASE_URL=$MURENA_BASE_URL >> local.properties - - echo MURENA_DISCOVERY_END_POINT=$MURENA_DISCOVERY_END_POINT >> local.properties - - ./gradlew build -x test - - cd app/build/outputs/apk/ose/ - - | - if [[ ! -d "release" ]]; then - echo "$APK_PATH does not exist." - exit 1 - fi - cd "release" - unsigned_build=$(ls *.apk | grep "release") - mv $unsigned_build $UNSIGNED_APK - artifacts: - paths: - - app/build/outputs/apk/ose/ - -build-staging: - stage: build - script: - - echo MURENA_BASE_URL=$MURENA_BASE_URL_STAGING >> local.properties - - echo MURENA_DISCOVERY_END_POINT=$MURENA_DISCOVERY_END_POINT_STAGING >> local.properties - ./gradlew build -x test - cd app/build/outputs/apk/ose/ - | @@ -78,27 +61,11 @@ init_submodules: paths: - systemAppsUpdateInfo/scripts/ -generate-prod-apks: +generate-apks: stage: gitlab_release needs: - job: init_submodules - - job: build-prod - script: - - | - ./systemAppsUpdateInfo/scripts/generate-apks.sh \ - "$APK_PATH" "$UNSIGNED_APK" "$COMMUNITY_APK" "$OFFICIAL_APK" "$TEST_APK" - artifacts: - paths: - - $APK_PATH/$UNSIGNED_APK - - $APK_PATH/$COMMUNITY_APK - - $APK_PATH/$OFFICIAL_APK - - $APK_PATH/$TEST_APK - -generate-staging-apks: - stage: gitlab_release - needs: - - job: init_submodules - - job: build-staging + - job: build script: - | ./systemAppsUpdateInfo/scripts/generate-apks.sh \ @@ -114,7 +81,7 @@ create-json-files: stage: gitlab_release needs: - job: init_submodules - - job: generate-prod-apks + - job: generate-apks rules: - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"' when: on_success @@ -133,7 +100,7 @@ create-test-release: needs: - job: init_submodules - job: create-json-files - - job: generate-prod-apks + - job: generate-apks rules: - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"' when: manual @@ -150,7 +117,7 @@ create-release: needs: - init_submodules - create-json-files - - generate-prod-apks + - generate-apks rules: - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"' when: manual @@ -168,7 +135,7 @@ create-release: CI_PROJECT_SSH_URL: git@gitlab.e.foundation:$CI_PROJECT_PATH GIT_STRATEGY: none before_script: - - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )' + - "command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )" - eval $(ssh-agent -s) - echo "${SSH_E_ROBOT_PRIVATE_KEY}" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh @@ -211,5 +178,3 @@ update-default-branch: UPSTREAM_DEFAULT_BRANCH: release-ose UPSTREAM_URL: https://github.com/bitfireAT/davx5-ose.git TEMP_LATEST_TAG_BRANCH: latest_upstream_tag_branch - - diff --git a/app/build.gradle b/app/build.gradle index 8ec1b4426..699f7ed12 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -142,8 +142,10 @@ android { buildConfigField "String", "MURENA_CLIENT_ID", "\"${retrieveKey("MURENA_CLIENT_ID")}\"" buildConfigField "String", "MURENA_REDIRECT_URI", "\"${retrieveKey("MURENA_REDIRECT_URI")}\"" buildConfigField "String", "MURENA_LOGOUT_REDIRECT_URI", "\"${retrieveKey("MURENA_LOGOUT_REDIRECT_URI")}\"" - buildConfigField "String", "MURENA_BASE_URL", "\"${retrieveKey("MURENA_BASE_URL")}\"" - buildConfigField "String", "MURENA_DISCOVERY_END_POINT", "\"${retrieveKey("MURENA_DISCOVERY_END_POINT")}\"" + buildConfigField "String", "MURENA_BASE_URL_STAGING", "\"${retrieveKey("MURENA_BASE_URL_STAGING")}\"" + buildConfigField "String", "MURENA_BASE_URL_PRODUCTION", "\"${retrieveKey("MURENA_BASE_URL_PRODUCTION")}\"" + buildConfigField "String", "MURENA_DISCOVERY_END_POINT_STAGING", "\"${retrieveKey("MURENA_DISCOVERY_END_POINT_STAGING")}\"" + buildConfigField "String", "MURENA_DISCOVERY_END_POINT_PRODUCTION", "\"${retrieveKey("MURENA_DISCOVERY_END_POINT_PRODUCTION")}\"" buildConfigField "String", "GOOGLE_CLIENT_ID", "\"${retrieveKey("GOOGLE_CLIENT_ID")}\"" buildConfigField "String", "GOOGLE_REDIRECT_URI", "\"${retrieveKey("GOOGLE_REDIRECT_URI")}\"" diff --git a/app/src/main/kotlin/at/bitfire/davdroid/authorization/IdentityProvider.kt b/app/src/main/kotlin/at/bitfire/davdroid/authorization/IdentityProvider.kt index 02e843794..2aad06c6a 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/authorization/IdentityProvider.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/authorization/IdentityProvider.kt @@ -19,6 +19,7 @@ import android.content.Context import android.net.Uri import at.bitfire.davdroid.BuildConfig import at.bitfire.davdroid.R +import at.bitfire.davdroid.util.MurenaServerConfig import net.openid.appauth.AuthorizationServiceConfiguration import net.openid.appauth.AuthorizationServiceConfiguration.RetrieveConfigurationCallback @@ -38,7 +39,7 @@ enum class IdentityProvider( baseUrl: String? ) { MURENA( - discoveryEndpoint = BuildConfig.MURENA_DISCOVERY_END_POINT, + discoveryEndpoint = BuildConfig.MURENA_DISCOVERY_END_POINT_PRODUCTION, authEndpoint = null, tokenEndpoint = null, clientId = BuildConfig.MURENA_CLIENT_ID, @@ -47,7 +48,7 @@ enum class IdentityProvider( logoutRedirectUri = BuildConfig.MURENA_LOGOUT_REDIRECT_URI + ":/redirect", scope = "openid profile email offline_access", userInfoEndpoint = null, - baseUrl = BuildConfig.MURENA_BASE_URL, + baseUrl = BuildConfig.MURENA_BASE_URL_PRODUCTION, ), GOOGLE( discoveryEndpoint = "https://accounts.google.com/.well-known/openid-configuration", @@ -116,9 +117,26 @@ enum class IdentityProvider( this.baseUrl = baseUrl } - fun retrieveConfig(callback: RetrieveConfigurationCallback) { - if (mDiscoveryEndpoint != null) { - AuthorizationServiceConfiguration.fetchFromUrl(mDiscoveryEndpoint, callback) + fun getBaseUrl(context: Context): String? { + return if (this == MURENA) { + MurenaServerConfig.getBaseUrl(context) + } else { + baseUrl + } + } + + private fun getDiscoveryEndpoint(context: Context): Uri? { + return if (this == MURENA) { + retrieveUri(MurenaServerConfig.getDiscoveryUrl(context)) + } else { + mDiscoveryEndpoint + } + } + + fun retrieveConfig(context: Context, callback: RetrieveConfigurationCallback) { + val discoveryEndpoint = getDiscoveryEndpoint(context) + if (discoveryEndpoint != null) { + AuthorizationServiceConfiguration.fetchFromUrl(discoveryEndpoint, callback) } else { val config = AuthorizationServiceConfiguration(mAuthEndpoint!!, mTokenEndpoint!!, null) callback.onFetchConfigurationCompleted(config, null) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/AccountUtils.kt b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/AccountUtils.kt index 4cf9958c1..feabee062 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/AccountUtils.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/AccountUtils.kt @@ -173,11 +173,14 @@ object AccountUtils { accountManager.getUserData(account, Constants.KEY_OC_BASE_URL) ?: return false val baseUrl = extractBaseUrl(urlData) - val murenaBaseUrl = extractBaseUrl(BuildConfig.MURENA_BASE_URL) + val murenaBaseUrls = setOf( + extractBaseUrl(BuildConfig.MURENA_BASE_URL_PRODUCTION), + extractBaseUrl(BuildConfig.MURENA_BASE_URL_STAGING), + ) // User can have their own Murena account set up with custom Nextcloud instance, // so a check for base URL is necessary. - val isMurenaCloud = (baseUrl == murenaBaseUrl) + val isMurenaCloud = baseUrl in murenaBaseUrls val isMurenaAccountType = (account.type == context.getString(R.string.eelo_account_type)) return isMurenaCloud && isMurenaAccountType diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt index dbf0c0796..3ffa9123a 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt @@ -64,6 +64,10 @@ class MurenaOpenIdAuthFragment : OpenIdAuthenticationBaseFragment(IdentityProvid return } - proceedNext(userName, "${IdentityProvider.MURENA.baseUrl}$userName") + val baseUrl = IdentityProvider.MURENA.getBaseUrl(requireContext()) ?: run { + handleLoginFailedToast() + return + } + proceedNext(userName, "$baseUrl$userName") } } diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt index aa0bebad5..0c5ed6f9a 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt @@ -106,7 +106,7 @@ abstract class OpenIdAuthenticationBaseFragment(private val identityProvider: Id return } - viewModel.identityProvider?.retrieveConfig { serviceConfiguration, exception -> + viewModel.identityProvider?.retrieveConfig(requireContext()) { serviceConfiguration, exception -> if (exception != null || serviceConfiguration == null) { Logger.log.log(Level.SEVERE, "failed to fetch configuration", exception) handleLoginFailedToast() diff --git a/app/src/main/kotlin/at/bitfire/davdroid/util/MurenaServerConfig.kt b/app/src/main/kotlin/at/bitfire/davdroid/util/MurenaServerConfig.kt new file mode 100644 index 000000000..3f47989d0 --- /dev/null +++ b/app/src/main/kotlin/at/bitfire/davdroid/util/MurenaServerConfig.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2026 e Foundation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package at.bitfire.davdroid.util + +import android.content.Context +import android.provider.Settings +import at.bitfire.davdroid.BuildConfig + +object MurenaServerConfig { + const val MURENA_STAGING_SERVER_GLOBAL_KEY = "murena_server.staging" + + fun isStaging(context: Context): Boolean { + return Settings.Global.getInt(context.contentResolver, + MURENA_STAGING_SERVER_GLOBAL_KEY, 0) == 1 + } + + fun getBaseUrl(context: Context): String { + return if (isStaging(context)) { + BuildConfig.MURENA_BASE_URL_STAGING + } else { + BuildConfig.MURENA_BASE_URL_PRODUCTION + } + } + + fun getDiscoveryUrl(context: Context): String { + return if (isStaging(context)) { + BuildConfig.MURENA_DISCOVERY_END_POINT_STAGING + } else { + BuildConfig.MURENA_DISCOVERY_END_POINT_PRODUCTION + } + } +} -- GitLab