Private
Public Access
1
0

Settings: Save server, username, password

This commit is contained in:
2024-02-26 23:03:10 -08:00
parent 175a83ca21
commit 077b12b1ac
4 changed files with 91 additions and 7 deletions

View File

@@ -61,6 +61,7 @@ dependencies {
// Kordophone lib // Kordophone lib
implementation project(':backend') implementation project(':backend')
implementation 'androidx.security:security-crypto-ktx:1.1.0-alpha06'
// Navigation // Navigation
def nav_version = "2.6.0" def nav_version = "2.6.0"

View File

@@ -98,8 +98,8 @@ fun SettingsFormView(
}) })
} }
var usernameInput by remember { mutableStateOf(TextFieldValue()) } var usernameInput by remember { mutableStateOf(TextFieldValue(userName.value)) }
var passwordInput by remember { mutableStateOf(TextFieldValue()) } var passwordInput by remember { mutableStateOf(TextFieldValue(password.value)) }
SettingsTextField( SettingsTextField(
name = "Authentication", name = "Authentication",
icon = R.drawable.account_circle, icon = R.drawable.account_circle,

View File

@@ -23,6 +23,15 @@ class SettingsViewModel @Inject constructor(
private val _passwordPreference: MutableStateFlow<String> = MutableStateFlow("") private val _passwordPreference: MutableStateFlow<String> = MutableStateFlow("")
var passwordPreference = _passwordPreference.asStateFlow() var passwordPreference = _passwordPreference.asStateFlow()
init {
val serverConfig = serverConfigRepository.serverConfig.value
serverConfig.serverName?.let { _serverPreference.value = it }
serverConfig.authentication?.let {
_usernamePreference.value = it.username
_passwordPreference.value = it.password
}
}
fun saveServerPreference(serverName: String) { fun saveServerPreference(serverName: String) {
_serverPreference.value = serverName _serverPreference.value = serverName
@@ -36,7 +45,7 @@ class SettingsViewModel @Inject constructor(
_passwordPreference.value = password _passwordPreference.value = password
serverConfigRepository.applyConfig { serverConfigRepository.applyConfig {
authentication = ServerAuthentication(username, password) this.authentication = ServerAuthentication(username, password)
} }
} }
} }

View File

@@ -1,28 +1,102 @@
package net.buzzert.kordophonedroid.ui.shared package net.buzzert.kordophonedroid.ui.shared
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import java.lang.reflect.Constructor
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
data class ServerConfig( data class ServerConfig(
var serverName: String? = null, var serverName: String? = null,
var authentication: ServerAuthentication? = null, var authentication: ServerAuthentication? = null,
) ) {
companion object {
private const val SHARED_PREF_NAME = "KordophonePreferences"
fun loadFromSettings(context: Context): ServerConfig {
val prefs = getSharedPreferences(context)
return ServerConfig(
serverName = prefs.getString("serverName", null),
authentication = ServerAuthentication.loadFromEncryptedSettings(context)
)
}
private fun getSharedPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
}
}
fun saveToSettings(context: Context) {
val prefs = getSharedPreferences(context)
prefs.edit {
putString("serverName", serverName)
apply()
}
authentication?.saveToEncryptedSettings(context)
}
}
data class ServerAuthentication( data class ServerAuthentication(
val username: String, val username: String,
val password: String, val password: String,
) ) {
companion object {
fun loadFromEncryptedSettings(context: Context): ServerAuthentication? {
val prefs = getEncryptedSharedPreferences(context)
val username = prefs.getString("username", null)
val password = prefs.getString("password", null)
if (username != null && password != null) {
return ServerAuthentication(username, password)
}
return null
}
private fun getEncryptedSharedPreferences(context: Context): SharedPreferences {
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
return EncryptedSharedPreferences(
context,
"secrets",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
}
fun saveToEncryptedSettings(context: Context) {
val prefs = getEncryptedSharedPreferences(context)
prefs.edit {
putString("username", username)
putString("password", password)
apply()
}
}
}
@Singleton @Singleton
class ServerConfigRepository @Inject constructor() { class ServerConfigRepository @Inject constructor(
@ApplicationContext val context: Context,
) {
// TODO: Initial config should be loaded from device settings. // TODO: Initial config should be loaded from device settings.
private val _serverConfig = MutableStateFlow(ServerConfig()) // Initial config private val _serverConfig = MutableStateFlow(ServerConfig.loadFromSettings(context)) // Initial config
val serverConfig: StateFlow<ServerConfig> = _serverConfig val serverConfig: StateFlow<ServerConfig> = _serverConfig
fun applyConfig(applicator: ServerConfig.() -> Unit) { fun applyConfig(applicator: ServerConfig.() -> Unit) {
val config = _serverConfig.value.copy() val config = _serverConfig.value.copy()
_serverConfig.value = config.apply(applicator) _serverConfig.value = config.apply(applicator)
_serverConfig.value.saveToSettings(context)
} }
} }