From 71b05d1f3254eff100085af1859ad006a4ed8135 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Tue, 13 Jul 2021 14:18:15 -0400 Subject: [PATCH] Support Basic and Digest authentication --- build.gradle.kts | 1 + .../ca/gosyer/data/server/HttpClient.kt | 29 +++++++++++++++++++ .../gosyer/data/server/ServerPreferences.kt | 12 ++++++++ .../ca/gosyer/data/server/model/Auth.kt | 16 ++++++++++ .../ui/base/prefs/PreferencesUiBuilder.kt | 7 +++-- .../ui/settings/SettingsServerScreen.kt | 26 +++++++++++++++++ src/main/resources/values/values/strings.xml | 6 ++++ 7 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/ca/gosyer/data/server/model/Auth.kt diff --git a/build.gradle.kts b/build.gradle.kts index 20320171..930d560c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -61,6 +61,7 @@ dependencies { implementation("io.ktor:ktor-client-serialization:$ktorVersion") implementation("io.ktor:ktor-client-logging:$ktorVersion") implementation("io.ktor:ktor-client-websockets:$ktorVersion") + implementation("io.ktor:ktor-client-auth:$ktorVersion") // Logging val slf4jVersion = "1.7.31" diff --git a/src/main/kotlin/ca/gosyer/data/server/HttpClient.kt b/src/main/kotlin/ca/gosyer/data/server/HttpClient.kt index d029e9fc..6f9748a2 100644 --- a/src/main/kotlin/ca/gosyer/data/server/HttpClient.kt +++ b/src/main/kotlin/ca/gosyer/data/server/HttpClient.kt @@ -7,11 +7,16 @@ package ca.gosyer.data.server import ca.gosyer.BuildConfig +import ca.gosyer.data.server.model.Auth import ca.gosyer.data.server.model.Proxy import io.ktor.client.HttpClient import io.ktor.client.engine.ProxyBuilder import io.ktor.client.engine.ProxyConfig import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.features.auth.providers.BasicAuthCredentials +import io.ktor.client.features.auth.providers.DigestAuthCredentials +import io.ktor.client.features.auth.providers.basic +import io.ktor.client.features.auth.providers.digest import io.ktor.client.features.json.JsonFeature import io.ktor.client.features.json.serializer.KotlinxSerializer import io.ktor.client.features.logging.LogLevel @@ -21,6 +26,7 @@ import io.ktor.http.URLBuilder import kotlinx.serialization.json.Json import javax.inject.Inject import javax.inject.Provider +import io.ktor.client.features.auth.Auth as AuthFeature typealias Http = HttpClient @@ -44,6 +50,29 @@ internal class HttpProvider @Inject constructor( ) } } + when (serverPreferences.auth().get()) { + Auth.NONE -> Unit + Auth.BASIC -> install(AuthFeature) { + basic { + credentials { + BasicAuthCredentials( + serverPreferences.authUsername().get(), + serverPreferences.authPassword().get() + ) + } + } + } + Auth.DIGEST -> install(AuthFeature) { + digest { + credentials { + DigestAuthCredentials( + serverPreferences.authUsername().get(), + serverPreferences.authPassword().get() + ) + } + } + } + } install(JsonFeature) { serializer = KotlinxSerializer( Json { diff --git a/src/main/kotlin/ca/gosyer/data/server/ServerPreferences.kt b/src/main/kotlin/ca/gosyer/data/server/ServerPreferences.kt index ad713380..1ac7fc1f 100644 --- a/src/main/kotlin/ca/gosyer/data/server/ServerPreferences.kt +++ b/src/main/kotlin/ca/gosyer/data/server/ServerPreferences.kt @@ -8,6 +8,7 @@ package ca.gosyer.data.server import ca.gosyer.common.prefs.Preference import ca.gosyer.common.prefs.PreferenceStore +import ca.gosyer.data.server.model.Auth import ca.gosyer.data.server.model.Proxy class ServerPreferences(private val preferenceStore: PreferenceStore) { @@ -47,4 +48,15 @@ class ServerPreferences(private val preferenceStore: PreferenceStore) { fun proxySocksPort(): Preference { return preferenceStore.getInt("proxy_socks_port") } + + fun auth(): Preference { + return preferenceStore.getJsonObject("auth", Auth.NONE, Auth.serializer()) + } + + fun authUsername(): Preference { + return preferenceStore.getString("auth_username") + } + fun authPassword(): Preference { + return preferenceStore.getString("auth_password") + } } diff --git a/src/main/kotlin/ca/gosyer/data/server/model/Auth.kt b/src/main/kotlin/ca/gosyer/data/server/model/Auth.kt new file mode 100644 index 00000000..c64b1efc --- /dev/null +++ b/src/main/kotlin/ca/gosyer/data/server/model/Auth.kt @@ -0,0 +1,16 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package ca.gosyer.data.server.model + +import kotlinx.serialization.Serializable + +@Serializable +enum class Auth { + NONE, + BASIC, + DIGEST +} diff --git a/src/main/kotlin/ca/gosyer/ui/base/prefs/PreferencesUiBuilder.kt b/src/main/kotlin/ca/gosyer/ui/base/prefs/PreferencesUiBuilder.kt index 90c1e12c..75ef8205 100644 --- a/src/main/kotlin/ca/gosyer/ui/base/prefs/PreferencesUiBuilder.kt +++ b/src/main/kotlin/ca/gosyer/ui/base/prefs/PreferencesUiBuilder.kt @@ -62,6 +62,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.takeOrElse import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -160,7 +161,8 @@ fun EditTextPreference( title: String, subtitle: String? = null, icon: ImageVector? = null, - enabled: Boolean = true + enabled: Boolean = true, + visualTransformation: VisualTransformation = VisualTransformation.None ) { var editText by remember { mutableStateOf(TextFieldValue(preference.value)) } PreferenceRow( @@ -178,7 +180,8 @@ fun EditTextPreference( editText, onValueChange = { editText = it - } + }, + visualTransformation = visualTransformation ) } }, diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt index 25db54ab..312f2d5a 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt @@ -11,7 +11,9 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.text.input.PasswordVisualTransformation import ca.gosyer.data.server.ServerPreferences +import ca.gosyer.data.server.model.Auth import ca.gosyer.data.server.model.Proxy import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.prefs.ChoicePreference @@ -46,12 +48,24 @@ class SettingsServerViewModel @Inject constructor( val httpPort = serverPreferences.proxyHttpPort().asStringStateIn(scope) val socksHost = serverPreferences.proxySocksHost().asStateIn(scope) val socksPort = serverPreferences.proxySocksPort().asStringStateIn(scope) + + val auth = serverPreferences.auth().asStateIn(scope) + + @Composable + fun getAuthChoices() = mapOf( + Auth.NONE to stringResource("no_auth"), + Auth.BASIC to stringResource("basic_auth"), + Auth.DIGEST to stringResource("digest_auth") + ) + val authUsername = serverPreferences.authUsername().asStateIn(scope) + val authPassword = serverPreferences.authPassword().asStateIn(scope) } @Composable fun SettingsServerScreen(navController: BackStack) { val vm = viewModel() val proxy by vm.proxy.collectAsState() + val auth by vm.auth.collectAsState() Column { Toolbar(stringResource("settings_server_screen"), navController, true) SwitchPreference(preference = vm.host, title = stringResource("host_server")) @@ -62,6 +76,7 @@ fun SettingsServerScreen(navController: BackStack) { item { EditTextPreference(vm.port, stringResource("server_port"), subtitle = vm.port.collectAsState().value) } + item { ChoicePreference(vm.proxy, vm.getProxyChoices(), stringResource("server_proxy")) } @@ -84,6 +99,17 @@ fun SettingsServerScreen(navController: BackStack) { } } } + item { + ChoicePreference(vm.auth, vm.getAuthChoices(), stringResource("authentication")) + } + if (auth != Auth.NONE) { + item { + EditTextPreference(vm.authUsername, stringResource("auth_username")) + } + item { + EditTextPreference(vm.authPassword, stringResource("auth_password"), visualTransformation = PasswordVisualTransformation()) + } + } } } } diff --git a/src/main/resources/values/values/strings.xml b/src/main/resources/values/values/strings.xml index a4d78bad..dbe21d08 100644 --- a/src/main/resources/values/values/strings.xml +++ b/src/main/resources/values/values/strings.xml @@ -176,4 +176,10 @@ Proxy access to the server HTTP PORT SOCKS PORT + Server authentication + No auth + Basic auth + Digest auth + Auth username + Auth password \ No newline at end of file