Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
Closes #7344: Login storage refactor
Browse files Browse the repository at this point in the history
The a-c side of this work is in mozilla-mobile/android-components#6128

This switches Fenix to use `SyncableLoginsStorage`, which caches a connection internally
on first access, and doesn't expose any lock/unlock APIs at the public boundary.
  • Loading branch information
Grisha Kruglov authored and pocmo committed Mar 3, 2020
1 parent 6a75d82 commit 04f33cf
Show file tree
Hide file tree
Showing 8 changed files with 26 additions and 66 deletions.
12 changes: 4 additions & 8 deletions app/src/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import android.content.Context
import android.os.Bundle
import mozilla.components.browser.engine.gecko.autofill.GeckoLoginDelegateWrapper
import mozilla.components.browser.engine.gecko.glean.GeckoAdapter
import mozilla.components.concept.storage.LoginsStorage
import mozilla.components.lib.crash.handler.CrashHandlerService
import mozilla.components.lib.dataprotect.SecureAbove22Preferences
import mozilla.components.service.experiments.Experiments
import mozilla.components.service.sync.logins.AsyncLoginsStorage
import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate
import org.mozilla.fenix.Config
import org.mozilla.fenix.ext.settings
Expand All @@ -24,20 +23,18 @@ object GeckoProvider {
@Synchronized
fun getOrCreateRuntime(
context: Context,
storage: AsyncLoginsStorage,
securePreferences: SecureAbove22Preferences
storage: LoginsStorage
): GeckoRuntime {
if (runtime == null) {
runtime = createRuntime(context, storage, securePreferences)
runtime = createRuntime(context, storage)
}

return runtime!!
}

private fun createRuntime(
context: Context,
storage: AsyncLoginsStorage,
securePreferences: SecureAbove22Preferences
storage: LoginsStorage
): GeckoRuntime {
val builder = GeckoRuntimeSettings.Builder()

Expand Down Expand Up @@ -69,7 +66,6 @@ object GeckoProvider {
val geckoRuntime = GeckoRuntime.create(context, runtimeSettings)
val loginStorageDelegate = GeckoLoginStorageDelegate(
storage,
securePreferences,
{ context.settings().shouldAutofillLogins && context.settings().shouldPromptToSaveLogins }
)
geckoRuntime.loginStorageDelegate = GeckoLoginDelegateWrapper(loginStorageDelegate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import android.content.Context
import android.os.Bundle
import mozilla.components.browser.engine.gecko.autofill.GeckoLoginDelegateWrapper
import mozilla.components.browser.engine.gecko.glean.GeckoAdapter
import mozilla.components.concept.storage.LoginsStorage
import mozilla.components.lib.crash.handler.CrashHandlerService
import mozilla.components.lib.dataprotect.SecureAbove22Preferences
import mozilla.components.service.sync.logins.AsyncLoginsStorage
import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate
import org.mozilla.fenix.Config
import org.mozilla.fenix.ext.settings
Expand All @@ -23,20 +22,18 @@ object GeckoProvider {
@Synchronized
fun getOrCreateRuntime(
context: Context,
storage: AsyncLoginsStorage,
securePreferences: SecureAbove22Preferences
storage: LoginsStorage
): GeckoRuntime {
if (runtime == null) {
runtime = createRuntime(context, storage, securePreferences)
runtime = createRuntime(context, storage)
}

return runtime!!
}

private fun createRuntime(
context: Context,
storage: AsyncLoginsStorage,
securePreferences: SecureAbove22Preferences
storage: LoginsStorage
): GeckoRuntime {
val builder = GeckoRuntimeSettings.Builder()

Expand All @@ -61,7 +58,6 @@ object GeckoProvider {
val geckoRuntime = GeckoRuntime.create(context, runtimeSettings)
val loginStorageDelegate = GeckoLoginStorageDelegate(
storage,
securePreferences,
{ context.settings().shouldAutofillLogins && context.settings().shouldPromptToSaveLogins }
)
geckoRuntime.loginStorageDelegate = GeckoLoginDelegateWrapper(loginStorageDelegate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
customTabId = customTabSessionId,
fragmentManager = parentFragmentManager,
loginValidationDelegate = DefaultLoginValidationDelegate(
context.components.core.asyncPasswordsStorage,
context.components.core.getSecureAbove22Preferences()
context.components.core.passwordsStorage
),
isSaveLoginEnabled = {
context.settings().shouldPromptToSaveLogins
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import mozilla.components.feature.accounts.push.SendTabFeature
import mozilla.components.feature.push.AutoPushFeature
import mozilla.components.feature.push.PushConfig
import mozilla.components.lib.crash.CrashReporter
import mozilla.components.lib.dataprotect.SecureAbove22Preferences
import mozilla.components.service.fxa.DeviceConfig
import mozilla.components.service.fxa.ServerConfig
import mozilla.components.service.fxa.SyncConfig
Expand All @@ -30,7 +29,7 @@ import mozilla.components.service.fxa.manager.SCOPE_SESSION
import mozilla.components.service.fxa.manager.SCOPE_SYNC
import mozilla.components.service.fxa.manager.SyncEnginesStorage
import mozilla.components.service.fxa.sync.GlobalSyncableStoreProvider
import mozilla.components.service.sync.logins.SyncableLoginsStore
import mozilla.components.service.sync.logins.SyncableLoginsStorage
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.Config
import org.mozilla.fenix.FeatureFlags
Expand All @@ -51,8 +50,7 @@ class BackgroundServices(
crashReporter: CrashReporter,
historyStorage: PlacesHistoryStorage,
bookmarkStorage: PlacesBookmarksStorage,
passwordsStorage: SyncableLoginsStore,
secureAbove22Preferences: SecureAbove22Preferences
passwordsStorage: SyncableLoginsStorage
) {
fun defaultDeviceName(context: Context): String =
context.getString(
Expand Down Expand Up @@ -88,7 +86,7 @@ class BackgroundServices(
syncPeriodInMinutes = 240L) // four hours
}

val pushService by lazy { FirebasePushService() }
private val pushService by lazy { FirebasePushService() }

val push by lazy { makePushConfig()?.let { makePush(it) } }

Expand All @@ -97,7 +95,6 @@ class BackgroundServices(
GlobalSyncableStoreProvider.configureStore(SyncEngine.History to historyStorage)
GlobalSyncableStoreProvider.configureStore(SyncEngine.Bookmarks to bookmarkStorage)
GlobalSyncableStoreProvider.configureStore(SyncEngine.Passwords to passwordsStorage)
GlobalSyncableStoreProvider.configureKeyStorage(secureAbove22Preferences)
}

private val telemetryAccountObserver = TelemetryAccountObserver(
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/java/org/mozilla/fenix/components/Components.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ class Components(private val context: Context) {
analytics.crashReporter,
core.historyStorage,
core.bookmarksStorage,
core.syncablePasswordsStorage,
core.getSecureAbove22Preferences()
core.passwordsStorage
)
}
val services by lazy { Services(context, backgroundServices.accountManager) }
Expand Down
39 changes: 8 additions & 31 deletions app/src/main/java/org/mozilla/fenix/components/Core.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import android.app.Application
import android.content.Context
import android.content.res.Configuration
import io.sentry.Sentry
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -38,16 +37,14 @@ import mozilla.components.feature.webcompat.WebCompatFeature
import mozilla.components.feature.webnotifications.WebNotificationFeature
import mozilla.components.lib.dataprotect.SecureAbove22Preferences
import mozilla.components.lib.dataprotect.generateEncryptionKey
import mozilla.components.service.sync.logins.AsyncLoginsStorageAdapter
import mozilla.components.service.sync.logins.SyncableLoginsStore
import mozilla.components.service.sync.logins.SyncableLoginsStorage
import org.mozilla.fenix.AppRequestInterceptor
import org.mozilla.fenix.Config
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.test.Mockable
import java.io.File
import java.util.concurrent.TimeUnit

/**
Expand Down Expand Up @@ -76,9 +73,7 @@ class Core(private val context: Context) {
GeckoEngine(
context,
defaultSettings,
GeckoProvider.getOrCreateRuntime(
context, asyncPasswordsStorage, getSecureAbove22Preferences()
)
GeckoProvider.getOrCreateRuntime(context, passwordsStorage)
).also {
WebCompatFeature.install(it)
}
Expand All @@ -90,11 +85,7 @@ class Core(private val context: Context) {
val client: Client by lazy {
GeckoViewFetchClient(
context,
GeckoProvider.getOrCreateRuntime(
context,
asyncPasswordsStorage,
getSecureAbove22Preferences()
)
GeckoProvider.getOrCreateRuntime(context, passwordsStorage)
)
}

Expand Down Expand Up @@ -201,6 +192,8 @@ class Core(private val context: Context) {

val bookmarksStorage by lazy { PlacesBookmarksStorage(context) }

val passwordsStorage by lazy { SyncableLoginsStorage(context, passwordsEncryptionKey) }

val tabCollectionStorage by lazy { TabCollectionStorage(context, sessionManager) }

val topSiteStorage by lazy { TopSiteStorage(context) }
Expand All @@ -209,36 +202,19 @@ class Core(private val context: Context) {

val webAppManifestStorage by lazy { ManifestStorage(context) }

val asyncPasswordsStorage by lazy {
AsyncLoginsStorageAdapter.forDatabase(
File(
context.filesDir,
"logins.sqlite"
).canonicalPath
)
}

val syncablePasswordsStorage by lazy {
SyncableLoginsStore(
asyncPasswordsStorage
) {
CompletableDeferred(passwordsEncryptionKey)
}
}

/**
* Shared Preferences that encrypt/decrypt using Android KeyStore and lib-dataprotect for 23+
* only on Nightly/Debug for now, otherwise simply stored.
* See https://github.com/mozilla-mobile/fenix/issues/8324
*/
fun getSecureAbove22Preferences() =
private fun getSecureAbove22Preferences() =
SecureAbove22Preferences(
context = context,
name = KEY_STORAGE_NAME,
forceInsecure = !Config.channel.isNightlyOrDebug
)

val passwordsEncryptionKey: String =
private val passwordsEncryptionKey by lazy {
getSecureAbove22Preferences().getString(PASSWORDS_KEY)
?: generateEncryptionKey(KEY_STRENGTH).also {
if (context.settings().passwordsEncryptionKeyGenerated) {
Expand All @@ -248,6 +224,7 @@ class Core(private val context: Context) {
context.settings().recordPasswordsEncryptionKeyGenerated()
getSecureAbove22Preferences().putString(PASSWORDS_KEY, it)
}
}

val trackingProtectionPolicyFactory = TrackingProtectionPolicyFactory(context.settings())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,7 @@ class SavedLoginSiteInfoFragment : Fragment(R.layout.fragment_saved_login_site_i
var deleteLoginJob: Deferred<Boolean>? = null
val deleteJob = lifecycleScope.launch(IO) {
deleteLoginJob = async {
requireContext().components.core.syncablePasswordsStorage.withUnlocked {
it.delete(args.savedLoginItem.id).await()
}
requireContext().components.core.passwordsStorage.delete(args.savedLoginItem.id)
}
deleteLoginJob?.await()
withContext(Main) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.appservices.logins.ServerPassword
import mozilla.components.concept.storage.Login
import mozilla.components.lib.state.ext.consumeFrom
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
Expand Down Expand Up @@ -103,18 +103,16 @@ class SavedLoginsFragment : Fragment() {
}

private fun loadAndMapLogins() {
var deferredLogins: Deferred<List<ServerPassword>>? = null
var deferredLogins: Deferred<List<Login>>? = null
val fetchLoginsJob = lifecycleScope.launch(IO) {
deferredLogins = async {
requireContext().components.core.syncablePasswordsStorage.withUnlocked {
it.list().await()
}
requireContext().components.core.passwordsStorage.list()
}
val logins = deferredLogins?.await()
logins?.let {
withContext(Main) {
savedLoginsStore.dispatch(SavedLoginsFragmentAction.UpdateLogins(logins.map { item ->
SavedLoginsItem(item.hostname, item.username, item.password, item.id)
SavedLoginsItem(item.origin, item.username, item.password, item.guid!!)
}))
}
}
Expand Down

0 comments on commit 04f33cf

Please sign in to comment.