Merge pull request #1443 from vector-im/feature/bma/httpHomeserver
Ensure http url entered by the user are provided to the SDK without being altered
This commit is contained in:
commit
2763c43a04
15 changed files with 65 additions and 21 deletions
|
|
@ -28,6 +28,7 @@
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.ElementX"
|
android:theme="@style/Theme.ElementX"
|
||||||
|
|
@ -81,11 +82,12 @@
|
||||||
tools:node="remove" />
|
tools:node="remove" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:authorities="${applicationId}.fileprovider"
|
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:grantUriPermissions="true"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
android:exported="false">
|
android:exported="false"
|
||||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/file_providers" />
|
android:resource="@xml/file_providers" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
|
|
||||||
35
app/src/main/res/xml/network_security_config.xml
Normal file
35
app/src/main/res/xml/network_security_config.xml
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<!-- Ref: https://developer.android.com/training/articles/security-config.html -->
|
||||||
|
<!-- By default, do not allow clearText traffic -->
|
||||||
|
<base-config cleartextTrafficPermitted="false" />
|
||||||
|
|
||||||
|
<!-- Allow clearText traffic on some specified host -->
|
||||||
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
|
<!-- Localhost -->
|
||||||
|
<domain includeSubdomains="true">localhost</domain>
|
||||||
|
<domain includeSubdomains="true">127.0.0.1</domain>
|
||||||
|
<!-- Localhost for Android emulator -->
|
||||||
|
<domain includeSubdomains="true">10.0.2.2</domain>
|
||||||
|
<!-- Onion services -->
|
||||||
|
<domain includeSubdomains="true">onion</domain>
|
||||||
|
|
||||||
|
<!-- Domains that are used for LANs -->
|
||||||
|
<!-- These are IANA recognized special use domain names, see https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml -->
|
||||||
|
<domain includeSubdomains="true">home.arpa</domain>
|
||||||
|
<domain includeSubdomains="true">local</domain> <!-- Note this has been reserved for use with mDNS -->
|
||||||
|
<domain includeSubdomains="true">test</domain>
|
||||||
|
<!-- These are observed in the wild either by convention or RFCs that have not been accepted, and are not currently TLDs -->
|
||||||
|
<domain includeSubdomains="true">home</domain>
|
||||||
|
<domain includeSubdomains="true">lan</domain>
|
||||||
|
<domain includeSubdomains="true">localdomain</domain>
|
||||||
|
</domain-config>
|
||||||
|
|
||||||
|
<debug-overrides>
|
||||||
|
<trust-anchors>
|
||||||
|
<certificates src="system" />
|
||||||
|
<certificates src="user" />
|
||||||
|
</trust-anchors>
|
||||||
|
</debug-overrides>
|
||||||
|
|
||||||
|
</network-security-config>
|
||||||
|
|
@ -16,8 +16,9 @@
|
||||||
|
|
||||||
package io.element.android.features.login.impl.accountprovider
|
package io.element.android.features.login.impl.accountprovider
|
||||||
|
|
||||||
data class AccountProvider constructor(
|
data class AccountProvider(
|
||||||
val title: String,
|
val url: String,
|
||||||
|
val title: String = url.removePrefix("https://").removePrefix("http://"),
|
||||||
val subtitle: String? = null,
|
val subtitle: String? = null,
|
||||||
val isPublic: Boolean = false,
|
val isPublic: Boolean = false,
|
||||||
val isMatrixOrg: Boolean = false,
|
val isMatrixOrg: Boolean = false,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package io.element.android.features.login.impl.accountprovider
|
package io.element.android.features.login.impl.accountprovider
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
import io.element.android.features.login.impl.util.LoginConstants
|
||||||
|
|
||||||
open class AccountProviderProvider : PreviewParameterProvider<AccountProvider> {
|
open class AccountProviderProvider : PreviewParameterProvider<AccountProvider> {
|
||||||
override val values: Sequence<AccountProvider>
|
override val values: Sequence<AccountProvider>
|
||||||
|
|
@ -31,7 +32,7 @@ open class AccountProviderProvider : PreviewParameterProvider<AccountProvider> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun anAccountProvider() = AccountProvider(
|
fun anAccountProvider() = AccountProvider(
|
||||||
title = "matrix.org",
|
url = LoginConstants.MATRIX_ORG_URL,
|
||||||
subtitle = "Matrix.org is an open network for secure, decentralized communication.",
|
subtitle = "Matrix.org is an open network for secure, decentralized communication.",
|
||||||
isPublic = true,
|
isPublic = true,
|
||||||
isMatrixOrg = true,
|
isMatrixOrg = true,
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class ChangeServerPresenter @Inject constructor(
|
||||||
changeServerAction: MutableState<Async<Unit>>,
|
changeServerAction: MutableState<Async<Unit>>,
|
||||||
) = launch {
|
) = launch {
|
||||||
suspend {
|
suspend {
|
||||||
authenticationService.setHomeserver(data.title).map {
|
authenticationService.setHomeserver(data.url).map {
|
||||||
authenticationService.getHomeserverDetails().value!!
|
authenticationService.getHomeserverDetails().value!!
|
||||||
// Valid, remember user choice
|
// Valid, remember user choice
|
||||||
accountProviderDataSource.userSelection(data)
|
accountProviderDataSource.userSelection(data)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package io.element.android.features.login.impl.screens.changeaccountprovider
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import io.element.android.features.login.impl.accountprovider.AccountProvider
|
import io.element.android.features.login.impl.accountprovider.AccountProvider
|
||||||
import io.element.android.features.login.impl.changeserver.ChangeServerPresenter
|
import io.element.android.features.login.impl.changeserver.ChangeServerPresenter
|
||||||
|
import io.element.android.features.login.impl.util.LoginConstants
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -33,7 +34,7 @@ class ChangeAccountProviderPresenter @Inject constructor(
|
||||||
// Just matrix.org by default for now
|
// Just matrix.org by default for now
|
||||||
accountProviders = listOf(
|
accountProviders = listOf(
|
||||||
AccountProvider(
|
AccountProvider(
|
||||||
title = "matrix.org",
|
url = LoginConstants.MATRIX_ORG_URL,
|
||||||
subtitle = null,
|
subtitle = null,
|
||||||
isPublic = true,
|
isPublic = true,
|
||||||
isMatrixOrg = true,
|
isMatrixOrg = true,
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ fun ChangeAccountProviderView(
|
||||||
// Other
|
// Other
|
||||||
AccountProviderView(
|
AccountProviderView(
|
||||||
item = AccountProvider(
|
item = AccountProvider(
|
||||||
|
url = "",
|
||||||
title = stringResource(id = R.string.screen_change_account_provider_other),
|
title = stringResource(id = R.string.screen_change_account_provider_other),
|
||||||
),
|
),
|
||||||
onClick = onOtherProviderClicked
|
onClick = onOtherProviderClicked
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ class ConfirmAccountProviderPresenter @AssistedInject constructor(
|
||||||
fun handleEvents(event: ConfirmAccountProviderEvents) {
|
fun handleEvents(event: ConfirmAccountProviderEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
ConfirmAccountProviderEvents.Continue -> {
|
ConfirmAccountProviderEvents.Continue -> {
|
||||||
localCoroutineScope.submit(accountProvider.title, loginFlowAction)
|
localCoroutineScope.submit(accountProvider.url, loginFlowAction)
|
||||||
}
|
}
|
||||||
ConfirmAccountProviderEvents.ClearError -> loginFlowAction.value = Async.Uninitialized
|
ConfirmAccountProviderEvents.ClearError -> loginFlowAction.value = Async.Uninitialized
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ data class ConfirmAccountProviderState(
|
||||||
val loginFlow: Async<LoginFlow>,
|
val loginFlow: Async<LoginFlow>,
|
||||||
val eventSink: (ConfirmAccountProviderEvents) -> Unit
|
val eventSink: (ConfirmAccountProviderEvents) -> Unit
|
||||||
) {
|
) {
|
||||||
val submitEnabled: Boolean get() = accountProvider.title.isNotEmpty() && (loginFlow is Async.Uninitialized || loginFlow is Async.Loading)
|
val submitEnabled: Boolean get() = accountProvider.url.isNotEmpty() && (loginFlow is Async.Uninitialized || loginFlow is Async.Loading)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface LoginFlow {
|
sealed interface LoginFlow {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package io.element.android.features.login.impl.screens.searchaccountprovider
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.features.login.impl.changeserver.aChangeServerState
|
import io.element.android.features.login.impl.changeserver.aChangeServerState
|
||||||
import io.element.android.features.login.impl.resolver.HomeserverData
|
import io.element.android.features.login.impl.resolver.HomeserverData
|
||||||
|
import io.element.android.features.login.impl.util.LoginConstants
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
|
|
||||||
open class SearchAccountProviderStateProvider : PreviewParameterProvider<SearchAccountProviderState> {
|
open class SearchAccountProviderStateProvider : PreviewParameterProvider<SearchAccountProviderState> {
|
||||||
|
|
@ -49,7 +50,7 @@ fun aHomeserverDataList(): List<HomeserverData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun aHomeserverData(
|
fun aHomeserverData(
|
||||||
homeserverUrl: String = "https://matrix.org",
|
homeserverUrl: String = LoginConstants.MATRIX_ORG_URL,
|
||||||
isWellknownValid: Boolean = true,
|
isWellknownValid: Boolean = true,
|
||||||
supportSlidingSync: Boolean = true,
|
supportSlidingSync: Boolean = true,
|
||||||
): HomeserverData {
|
): HomeserverData {
|
||||||
|
|
|
||||||
|
|
@ -54,12 +54,13 @@ import io.element.android.features.login.impl.accountprovider.AccountProviderVie
|
||||||
import io.element.android.features.login.impl.changeserver.ChangeServerEvents
|
import io.element.android.features.login.impl.changeserver.ChangeServerEvents
|
||||||
import io.element.android.features.login.impl.changeserver.ChangeServerView
|
import io.element.android.features.login.impl.changeserver.ChangeServerView
|
||||||
import io.element.android.features.login.impl.resolver.HomeserverData
|
import io.element.android.features.login.impl.resolver.HomeserverData
|
||||||
|
import io.element.android.features.login.impl.util.LoginConstants
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.IconButton
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
|
|
@ -195,9 +196,9 @@ fun SearchAccountProviderView(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun HomeserverData.toAccountProvider(): AccountProvider {
|
private fun HomeserverData.toAccountProvider(): AccountProvider {
|
||||||
val isMatrixOrg = homeserverUrl == "https://matrix.org"
|
val isMatrixOrg = homeserverUrl == LoginConstants.MATRIX_ORG_URL
|
||||||
return AccountProvider(
|
return AccountProvider(
|
||||||
title = homeserverUrl.removePrefix("http://").removePrefix("https://"),
|
url = homeserverUrl,
|
||||||
subtitle = if (isMatrixOrg) stringResource(id = R.string.screen_change_account_provider_matrix_org_subtitle) else null,
|
subtitle = if (isMatrixOrg) stringResource(id = R.string.screen_change_account_provider_matrix_org_subtitle) else null,
|
||||||
isPublic = isMatrixOrg, // There is no need to know for other servers right now
|
isPublic = isMatrixOrg, // There is no need to know for other servers right now
|
||||||
isMatrixOrg = isMatrixOrg,
|
isMatrixOrg = isMatrixOrg,
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,14 @@ package io.element.android.features.login.impl.util
|
||||||
import io.element.android.features.login.impl.accountprovider.AccountProvider
|
import io.element.android.features.login.impl.accountprovider.AccountProvider
|
||||||
|
|
||||||
object LoginConstants {
|
object LoginConstants {
|
||||||
const val MATRIX_ORG_URL = "matrix.org"
|
const val MATRIX_ORG_URL = "https://matrix.org"
|
||||||
|
|
||||||
const val DEFAULT_HOMESERVER_URL = "matrix.org"
|
const val DEFAULT_HOMESERVER_URL = "https://matrix.org"
|
||||||
const val SLIDING_SYNC_READ_MORE_URL = "https://github.com/matrix-org/sliding-sync/blob/main/docs/Landing.md"
|
const val SLIDING_SYNC_READ_MORE_URL = "https://github.com/matrix-org/sliding-sync/blob/main/docs/Landing.md"
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaultAccountProvider = AccountProvider(
|
val defaultAccountProvider = AccountProvider(
|
||||||
title = LoginConstants.DEFAULT_HOMESERVER_URL,
|
url = LoginConstants.DEFAULT_HOMESERVER_URL,
|
||||||
subtitle = null,
|
subtitle = null,
|
||||||
isPublic = LoginConstants.DEFAULT_HOMESERVER_URL == LoginConstants.MATRIX_ORG_URL,
|
isPublic = LoginConstants.DEFAULT_HOMESERVER_URL == LoginConstants.MATRIX_ORG_URL,
|
||||||
isMatrixOrg = LoginConstants.DEFAULT_HOMESERVER_URL == LoginConstants.MATRIX_ORG_URL,
|
isMatrixOrg = LoginConstants.DEFAULT_HOMESERVER_URL == LoginConstants.MATRIX_ORG_URL,
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class ChangeServerPresenterTest {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.changeServerAction).isEqualTo(Async.Uninitialized)
|
assertThat(initialState.changeServerAction).isEqualTo(Async.Uninitialized)
|
||||||
authenticationService.givenHomeserver(A_HOMESERVER)
|
authenticationService.givenHomeserver(A_HOMESERVER)
|
||||||
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(AccountProvider(A_HOMESERVER_URL)))
|
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(AccountProvider(url = A_HOMESERVER_URL)))
|
||||||
val loadingState = awaitItem()
|
val loadingState = awaitItem()
|
||||||
assertThat(loadingState.changeServerAction).isInstanceOf(Async.Loading::class.java)
|
assertThat(loadingState.changeServerAction).isInstanceOf(Async.Loading::class.java)
|
||||||
val successState = awaitItem()
|
val successState = awaitItem()
|
||||||
|
|
@ -83,7 +83,7 @@ class ChangeServerPresenterTest {
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.changeServerAction).isEqualTo(Async.Uninitialized)
|
assertThat(initialState.changeServerAction).isEqualTo(Async.Uninitialized)
|
||||||
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(AccountProvider(A_HOMESERVER_URL)))
|
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(AccountProvider(url = A_HOMESERVER_URL)))
|
||||||
val loadingState = awaitItem()
|
val loadingState = awaitItem()
|
||||||
assertThat(loadingState.changeServerAction).isInstanceOf(Async.Loading::class.java)
|
assertThat(loadingState.changeServerAction).isInstanceOf(Async.Loading::class.java)
|
||||||
val failureState = awaitItem()
|
val failureState = awaitItem()
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ class ChangeAccountProviderPresenterTest {
|
||||||
assertThat(initialState.accountProviders).isEqualTo(
|
assertThat(initialState.accountProviders).isEqualTo(
|
||||||
listOf(
|
listOf(
|
||||||
AccountProvider(
|
AccountProvider(
|
||||||
|
url = "https://matrix.org",
|
||||||
title = "matrix.org",
|
title = "matrix.org",
|
||||||
subtitle = null,
|
subtitle = null,
|
||||||
isPublic = true,
|
isPublic = true,
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ class LoginScreen(private val authenticationService: MatrixAuthenticationService
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
authenticationService.setHomeserver(defaultAccountProvider.title)
|
authenticationService.setHomeserver(defaultAccountProvider.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
val state = presenter.present()
|
val state = presenter.present()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue