Commit 1953a944 authored by Gabriel Luong's avatar Gabriel Luong Committed by mergify[bot]
Browse files

Issue #10140 - Part 3: Implement the new Autocomplete.StorageDelegate...

Issue #10140 - Part 3: Implement the new Autocomplete.StorageDelegate interface in GeckoAutocompleteStorageDelegate

- Uses the new GeckoView's `Autocomplete.StorageDelegate` interface in GeckoStorageDelegate
- Implements GeckoView's `Autocomplete.StorageDelegate.onCreditCardFetch`
parent 40254845
Loading
Loading
Loading
Loading
+44 −9
Original line number Diff line number Diff line
@@ -9,30 +9,65 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import mozilla.components.browser.engine.gecko.ext.toLogin
import mozilla.components.browser.engine.gecko.ext.toLoginEntry
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardsAddressesStorageDelegate
import mozilla.components.concept.storage.Login
import mozilla.components.concept.storage.LoginStorageDelegate
import org.mozilla.geckoview.Autocomplete
import org.mozilla.geckoview.GeckoResult

/**
 * This class exists only to convert incoming [LoginEntry] arguments into [Login]s, then forward
 * them to [storageDelegate]. This allows us to avoid duplicating [LoginStorageDelegate] code
 * between different versions of GeckoView, by duplicating this wrapper instead.
 * Gecko credit card and login storage delegate that handles runtime storage requests. This allows
 * the Gecko runtime to call the underlying storage to handle requests for fetching, saving and
 * updating of autocomplete items in the storage.
 *
 * @param creditCardsAddressesStorageDelegate An instance of [CreditCardsAddressesStorageDelegate].
 * Provides methods for retrieving [CreditCard]s from the underlying storage.
 * @param loginStorageDelegate An instance of [LoginStorageDelegate].
 * Provides read/write methods for the [Login] storage.
 */
@Suppress("Deprecation")
// This will be addressed in https://github.com/mozilla-mobile/android-components/issues/10093
class GeckoLoginDelegate(private val storageDelegate: LoginStorageDelegate) :
    Autocomplete.LoginStorageDelegate {
class GeckoAutocompleteStorageDelegate(
    private val creditCardsAddressesStorageDelegate: CreditCardsAddressesStorageDelegate,
    private val loginStorageDelegate: LoginStorageDelegate
) : Autocomplete.StorageDelegate {

    override fun onCreditCardFetch(): GeckoResult<Array<Autocomplete.CreditCard>>? {
        val result = GeckoResult<Array<Autocomplete.CreditCard>>()

        GlobalScope.launch(IO) {
            val creditCards = creditCardsAddressesStorageDelegate.onCreditCardsFetch().await()
                .mapNotNull {
                    val plaintextCardNumber =
                        creditCardsAddressesStorageDelegate.decrypt(it.encryptedCardNumber)?.number

                    if (plaintextCardNumber == null) {
                        null
                    } else {
                        Autocomplete.CreditCard.Builder()
                            .guid(it.guid)
                            .name(it.billingName)
                            .number(plaintextCardNumber)
                            .expirationMonth(it.expiryMonth.toString())
                            .expirationYear(it.expiryYear.toString())
                            .build()
                    }
                }
                .toTypedArray()
            result.complete(creditCards)
        }

        return result
    }

    override fun onLoginSave(login: Autocomplete.LoginEntry) {
        storageDelegate.onLoginSave(login.toLogin())
        loginStorageDelegate.onLoginSave(login.toLogin())
    }

    override fun onLoginFetch(domain: String): GeckoResult<Array<Autocomplete.LoginEntry>>? {
        val result = GeckoResult<Array<Autocomplete.LoginEntry>>()

        GlobalScope.launch(IO) {
            val storedLogins = storageDelegate.onLoginFetch(domain)
            val storedLogins = loginStorageDelegate.onLoginFetch(domain)

            val logins = storedLogins.await()
                .map { it.toLoginEntry() }
+49 −0
Original line number Diff line number Diff line
@@ -104,6 +104,46 @@ interface CreditCardsAddressesStorage {
     * @param guid Unique identifier for the desired address.
     */
    suspend fun touchAddress(guid: String)

    /**
     * Returns an instance of [CreditCardCrypto] that knows how to encrypt and decrypt credit card
     * numbers.
     *
     * @return [CreditCardCrypto] instance.
     */
    fun getCreditCardCrypto(): CreditCardCrypto
}

/**
 * An interface that defines methods for encrypting and decrypting a credit card number.
 */
interface CreditCardCrypto : KeyProvider {

    /**
     * Encrypt a [CreditCardNumber.Plaintext] using the provided key. A `null` result means a
     * bad key was provided. In that case caller should obtain a new key and try again.
     *
     * @param key The encryption key to encrypt the plaintext credit card number.
     * @param plaintextCardNumber A plaintext credit card number to be encrypted.
     * @return An encrypted credit card number or `null` if a bad [key] was provided.
     */
    fun encrypt(
        key: ManagedKey,
        plaintextCardNumber: CreditCardNumber.Plaintext
    ): CreditCardNumber.Encrypted?

    /**
     * Decrypt a [CreditCardNumber.Encrypted] using the provided key. A `null` result means a
     * bad key was provided. In that case caller should obtain a new key and try again.
     *
     * @param key The encryption key to decrypt the decrypt credit card number.
     * @param encryptedCardNumber An encrypted credit card number to be decrypted.
     * @return A plaintext, non-encrypted credit card number or `null` if a bad [key] was provided.
     */
    fun decrypt(
        key: ManagedKey,
        encryptedCardNumber: CreditCardNumber.Encrypted
    ): CreditCardNumber.Plaintext?
}

/**
@@ -273,6 +313,15 @@ data class UpdatableAddressFields(
 */
interface CreditCardsAddressesStorageDelegate {

    /**
     * Decrypt a [CreditCardNumber.Encrypted] into its plaintext equivalent or `null` if
     * it fails to decrypt.
     *
     * @param encryptedCardNumber An encrypted credit card number to be decrypted.
     * @return A plaintext, non-encrypted credit card number.
     */
    fun decrypt(encryptedCardNumber: CreditCardNumber.Encrypted): CreditCardNumber.Plaintext?

    /**
     * Returns all stored addresses. This is called when the engine believes an address field
     * should be autofilled.
+1 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package mozilla.components.lib.dataprotect
package mozilla.components.concept.storage

/**
 * Knows how to provide a [ManagedKey].
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ android {
dependencies {
    // Types defined in concept-sync are part of the public API of this module.
    api project(':concept-sync')
    api project(':concept-storage')

    // Parts of this dependency are typealiase'd or are otherwise part of this module's public API.
    api Dependencies.mozilla_fxa
+1 −1
Original line number Diff line number Diff line
@@ -4,8 +4,8 @@

package mozilla.components.service.fxa.sync

import mozilla.components.concept.storage.KeyProvider
import mozilla.components.concept.sync.SyncableStore
import mozilla.components.lib.dataprotect.KeyProvider
import mozilla.components.service.fxa.SyncConfig
import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.SyncEnginesStorage
Loading