Move the :libraries:wellknown logic into enterprise modules (#7429)

* Extract `IsEnterpriseBuild` use case

Having it inside `EnterpriseService` made having DI cycles with the `BuildMeta` provider too easy

* Rename `EnterpriseService.defaultHomeserverList()` to `homeserverAllowList()`

This seems more aligned with the way this list works

* Move most of the logic from `:libraries:wellknown` to `:enterprise:feature:enterprise`, both `shared` and `impl` modules

Ideally I would have added everything into `impl`, but some of the classes needed to be shared between the different `:enterprise:features` modules, and those are in the `shared` module, lacking a better name/strategy

* Add `EnterpriseService.isElementProEnforced`

With this, we don't need to provide the `RemoteEnterpriseConfig` anymore to any consumers, everything goes through `EnterpriseService` or other providers

* Remove `EnterpriseService.overriddenElementWellKnown`

This leaks the remote enterprise config/element well known contents to the app in a public interface.

* Create `CustomMapTilerConfigProvider` to avoid leaking the `RemoteEnterpriseConfig` in public APIs

This commit also starts moving some of the well-known related values to the enterprise modules

* Add missing docs to `EnterpriseService` and `SessionEnterpriseService`

* Fix tests

* Fix lint issues

* Bump enterprise module
This commit is contained in:
Jorge Martin Espinosa
2026-08-17 15:21:47 +02:00
committed by GitHub
parent f94566e44f
commit 8b2c207728
72 changed files with 246 additions and 1607 deletions
@@ -1,23 +0,0 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
/**
* Server-driven settings for a user-chosen recovery passphrase, advertised under the well-known
* `custom_recovery_passphrase` key. Today the only rule is a minimum character count; additional
* settings can be added here as the schema grows.
*/
data class CustomRecoveryPassphrase(
val minCharacterCount: Int,
) {
/** True when [input] meets every active rule. */
fun isSatisfiedBy(input: String): Boolean = isSatisfiedBy(input.length)
/** True when an input of [length] characters meets every active rule. */
fun isSatisfiedBy(length: Int): Boolean = length >= minCharacterCount
}
@@ -1,36 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
data class ElementWellKnown(
val registrationHelperUrl: String?,
val enforceElementPro: Boolean?,
val rageshakeUrl: String?,
val brandColor: String?,
val notificationSound: String?,
val identityProviderAppScheme: String?,
val customRecoveryPassphrase: CustomRecoveryPassphrase?,
val contentScannerUrl: String?,
val forceDisableE2EE: Boolean?,
val mapTilerConfig: MapTilerConfig?,
)
/**
* A `MapTiler` configuration received from the server. This configuration is used to display maps in the app.
*/
data class MapTilerConfig(
/** The API key to use with MapTiler. This is always not null, but can be empty/blank. */
val apiKey: String,
/** The style ID to use for light mode. This is optional and can be null. */
val lightStyleId: String?,
/** The style ID to use for light mode. This is optional and can be null. */
val darkStyleId: String?,
/** The base URL to use for MapTiler. This is optional and can be null. */
val baseUrl: String?,
)
@@ -1,20 +0,0 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
/**
* Parses the raw JSON of an Element `.well-known` document.
*/
fun interface ElementWellKnownParser {
/**
* Parses the document, failing when it is not valid JSON; unknown fields are ignored so a newer server does not break an older client.
*
* @param json the raw document as served by the server.
*/
fun parse(json: String): Result<ElementWellKnown>
}
@@ -1,47 +0,0 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
/**
* On-disk cache of the Element `.well-known` documents already fetched, so the app has a configuration to work with while offline.
*/
interface ElementWellknownStore {
/**
* Reads the cached document of a domain.
* Entries older than a day are reported as outdated rather than missing, so the caller can use them while refreshing;
* a document that no longer parses is reported as an error.
*
* @param domain the server whose cached document is requested.
*/
suspend fun get(domain: String): WellknownRetrieverResult<ElementWellKnown>
/**
* Stores the document of a domain and stamps it as fetched now, replacing any previous entry.
*
* @param domain the server the document belongs to.
* @param wellknown the raw document, stored as-is rather than parsed.
*/
suspend fun update(domain: String, wellknown: String): Result<Unit>
/**
* Removes the cached document of a domain, used when the stored value turns out to be unusable.
*
* @param domain the server whose entry is removed.
*/
suspend fun delete(domain: String): Result<Unit>
/**
* Creates a store, one per configuration source so that their entries never collide.
*/
fun interface Factory {
/**
* @param prefix namespaces the cache keys, or `null` for the default well-known endpoint.
*/
fun create(prefix: String?): ElementWellknownStore
}
}
@@ -1,23 +0,0 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
/**
* The source from which the enterprise remote configuration is retrieved.
*/
enum class EnterpriseRemoteConfigSource {
/**
* Retrieve the enterprise remote configuration from the Element Server Suite configuration (ESS_CONFIG) endpoint.
*/
ESS_CONFIG,
/**
* Retrieve the enterprise remote configuration from the Element server's well-known endpoint.
*/
WELLKNOWN_ENDPOINT,
}
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
import io.element.android.libraries.matrix.api.UrlContentFetcher
/**
* Retrieves the Element specific `.well-known` configuration of a server, which is how a deployment advertises its own settings.
*/
interface WellknownRetriever {
/**
* Returns the configuration of a host, served from the local cache when possible.
* A cached value that has gone stale is returned as outdated while a refresh runs in the background, so this rarely waits on the network.
* An enterprise build with a hardcoded configuration always short-circuits and returns that instead.
*
* @param host the server to look up; a full URL is accepted and reduced to its host.
* @param source which endpoint to read the configuration from, which also selects the cache it is stored in.
*/
suspend fun getElementWellKnown(
host: String,
source: EnterpriseRemoteConfigSource
): WellknownRetrieverResult<ElementWellKnown>
/**
* Creates a retriever, which needs a fetcher because the configuration is read over HTTP.
*/
interface Factory {
/**
* @param urlContentFetcher used to perform the request; a client that is not authenticated yet also works.
*/
fun create(urlContentFetcher: UrlContentFetcher): WellknownRetriever
}
}
@@ -1,45 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
sealed interface WellknownRetrieverResult<out T> {
/**
* Well-known data has been successfully retrieved.
*/
data class Success<out T>(val data: T) : WellknownRetrieverResult<T>
/**
* Well-known data has been retrieved from the local cache but is outdated and a manual refresh has been launched.
*/
data class Outdated<out T>(val data: T) : WellknownRetrieverResult<T>
/**
* Well-known data is not found (file does not exist server side, we got a 404).
*/
data object NotFound : WellknownRetrieverResult<Nothing>
/**
* Any other error.
*/
data class Error(val exception: Exception) : WellknownRetrieverResult<Nothing>
fun dataOrNull(): T? = when (this) {
is Success<T> -> data
is Outdated<T> -> data
is Error -> null
NotFound -> null
}
fun upToDateDataOrNull(): T? = when (this) {
is Success<T> -> data
is Outdated<T> -> null
is Error -> null
NotFound -> null
}
}