Put login and password in encrypted shared preferences

This commit is contained in:
Shinokuni 2024-05-10 14:02:45 +02:00
parent b3c252a434
commit 0fbaec1263
6 changed files with 43 additions and 3 deletions

View File

@ -91,4 +91,6 @@ dependencies {
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:4.9.0'
coreLibraryDesugaring(libs.jdk.desugar)
implementation(libs.encrypted.preferences)
}

View File

@ -1,5 +1,7 @@
package com.readrops.app.compose
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.readrops.api.services.Credentials
import com.readrops.app.compose.account.AccountScreenModel
import com.readrops.app.compose.account.credentials.AccountCredentialsScreenModel
@ -13,6 +15,7 @@ import com.readrops.app.compose.repositories.LocalRSSRepository
import com.readrops.app.compose.timelime.TimelineScreenModel
import com.readrops.db.entities.account.Account
import com.readrops.db.entities.account.AccountType
import org.koin.android.ext.koin.androidContext
import org.koin.core.parameter.parametersOf
import org.koin.dsl.module
@ -44,4 +47,18 @@ val composeAppModule = module {
else -> throw IllegalArgumentException("Unknown account type")
}
}
single {
val masterKey = MasterKey.Builder(androidContext())
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
EncryptedSharedPreferences.create(
androidContext(),
"account_credentials",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
}

View File

@ -36,8 +36,8 @@ import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import com.readrops.app.compose.R
import com.readrops.app.compose.home.HomeScreen
import com.readrops.app.compose.util.components.AndroidScreen
import com.readrops.app.compose.util.ErrorMessage
import com.readrops.app.compose.util.components.AndroidScreen
import com.readrops.app.compose.util.theme.ShortSpacer
import com.readrops.app.compose.util.theme.VeryLargeSpacer
import com.readrops.app.compose.util.theme.spacing
@ -118,7 +118,7 @@ class AccountCredentialsScreen(
label = { Text(text = stringResource(id = R.string.login)) },
singleLine = true,
isError = state.isLoginError,
supportingText = { Text(text = state.passwordError?.errorText().orEmpty()) },
supportingText = { Text(text = state.loginError?.errorText().orEmpty()) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
modifier = Modifier.fillMaxWidth()
)

View File

@ -1,5 +1,6 @@
package com.readrops.app.compose.account.credentials
import android.content.SharedPreferences
import android.util.Patterns
import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
@ -72,7 +73,13 @@ class AccountCredentialsScreenModel(
return@launch
}
database.newAccountDao().insert(account)
account.id = database.newAccountDao().insert(account).toInt()
get<SharedPreferences>().edit()
.putString(account.loginKey, account.login)
.putString(account.passwordKey, account.password)
.apply()
mutableState.update { it.copy(goToHomeScreen = true) }
}
}

View File

@ -1,7 +1,10 @@
package com.readrops.app.compose.base
import android.content.SharedPreferences
import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import com.readrops.api.services.Credentials
import com.readrops.api.utils.AuthInterceptor
import com.readrops.app.compose.repositories.BaseRepository
import com.readrops.db.Database
import com.readrops.db.entities.account.Account
@ -35,8 +38,17 @@ abstract class TabScreenModel(
.distinctUntilChanged()
.collect { account ->
if (account != null) {
if (account.login == null || account.password == null) {
val encryptedPreferences = get<SharedPreferences>()
account.login = encryptedPreferences.getString(account.loginKey, null)
account.password = encryptedPreferences.getString(account.passwordKey, null)
}
currentAccount = account
repository = get(parameters = { parametersOf(account) })
// very important to avoid credentials conflicts between accounts
get<AuthInterceptor>().credentials = Credentials.toCredentials(account)
accountEvent.emit(account)
}

View File

@ -65,6 +65,8 @@ kotlinxmlbuilder = "org.redundent:kotlin-xml-builder:1.7.3" #TODO update this
jdk-desugar = "com.android.tools:desugar_jdk_libs:2.0.4"
encrypted-preferences = "androidx.security:security-crypto:1.1.0-alpha06"
[bundles]
compose = ["bom", "compose-foundation", "compose-runtime", "compose-animation",
"compose-ui", "compose-ui-tooling", "compose-ui-tooling-preview", "compose-material3"]