[fenix] Fix breaking changes introduced by credit card encryption APIs

pull/600/head
Grisha Kruglov 3 years ago committed by Sebastian Kaspari
parent e7ca8c22be
commit 632ba92ad5

@ -95,8 +95,8 @@ class BackgroundServices(
private val syncConfig = SyncConfig(supportedEngines, PeriodicSyncConfig(periodMinutes = 240)) // four hours
init {
/* Make the "history", "bookmark", "passwords", and "tabs" stores accessible to workers
spawned by the sync manager. */
// Make the "history", "bookmark", "passwords", "tabs" stores
// accessible to workers spawned by the sync manager.
GlobalSyncableStoreProvider.configureStore(SyncEngine.History to historyStorage)
GlobalSyncableStoreProvider.configureStore(SyncEngine.Bookmarks to bookmarkStorage)
GlobalSyncableStoreProvider.configureStore(SyncEngine.Passwords to passwordsStorage)

@ -291,7 +291,7 @@ class Core(
val lazyHistoryStorage = lazyMonitored { PlacesHistoryStorage(context, crashReporter) }
val lazyBookmarksStorage = lazyMonitored { PlacesBookmarksStorage(context) }
val lazyPasswordsStorage = lazyMonitored { SyncableLoginsStorage(context, passwordsEncryptionKey) }
val lazyAutofillStorage = lazyMonitored { AutofillCreditCardsAddressesStorage(context) }
private val lazyAutofillStorage = lazyMonitored { AutofillCreditCardsAddressesStorage(context, lazySecurePrefs) }
/**
* The storage component to sync and persist tabs in a Firefox Sync account.
@ -390,6 +390,7 @@ class Core(
* 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
* Also, this needs revision. See https://github.com/mozilla-mobile/fenix/issues/19155
*/
private fun getSecureAbove22Preferences() =
SecureAbove22Preferences(
@ -398,6 +399,9 @@ class Core(
forceInsecure = !Config.channel.isNightlyOrDebug
)
// Temporary. See https://github.com/mozilla-mobile/fenix/issues/19155
private val lazySecurePrefs = lazyMonitored { getSecureAbove22Preferences() }
private val passwordsEncryptionKey by lazyMonitored {
getSecureAbove22Preferences().getString(PASSWORDS_KEY)
?: generateEncryptionKey(KEY_STRENGTH).also {

@ -14,6 +14,8 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import kotlinx.android.synthetic.main.fragment_credit_card_editor.*
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.R
@ -69,6 +71,7 @@ class CreditCardEditorFragment : Fragment(R.layout.fragment_credit_card_editor)
menu.findItem(R.id.delete_credit_card_button).isVisible = isEditing
}
@Suppress("MagicNumber")
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
R.id.delete_credit_card_button -> {
args.creditCard?.let { interactor.onDeleteCardButtonClicked(it.guid) }
@ -78,18 +81,30 @@ class CreditCardEditorFragment : Fragment(R.layout.fragment_credit_card_editor)
view?.hideKeyboard()
val creditCard = args.creditCard
val creditCardFields = UpdatableCreditCardFields(
billingName = name_on_card_input.text.toString(),
cardNumber = card_number_input.text.toString(),
expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(),
expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(),
cardType = CARD_TYPE_PLACEHOLDER
)
// TODO need to know if we're updating a number, or just round-tripping it
val cardNumber = card_number_input.text.toString()
if (creditCard != null) {
interactor.onUpdateCreditCard(creditCard.guid, creditCardFields)
val fields = UpdatableCreditCardFields(
billingName = name_on_card_input.text.toString(),
cardNumber = CreditCardNumber.Plaintext(cardNumber),
cardNumberLast4 = cardNumber.substring(cardNumber.length - 5, cardNumber.length - 1),
expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(),
expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(),
cardType = CARD_TYPE_PLACEHOLDER
)
interactor.onUpdateCreditCard(creditCard.guid, fields)
} else {
interactor.onSaveCreditCard(creditCardFields)
val fields = NewCreditCardFields(
billingName = name_on_card_input.text.toString(),
plaintextCardNumber = CreditCardNumber.Plaintext(cardNumber),
cardNumberLast4 = cardNumber.substring(cardNumber.length - 5, cardNumber.length - 1),
expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(),
expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(),
cardType = CARD_TYPE_PLACEHOLDER
)
interactor.onSaveCreditCard(fields)
}
true

@ -37,7 +37,8 @@ fun CreditCard.toCreditCardEditorState(): CreditCardEditorState {
return CreditCardEditorState(
guid = guid,
billingName = billingName,
cardNumber = cardNumber,
// TODO - need to represented a full CreditCardNumber object here, along with last4
cardNumber = encryptedCardNumber.number,
expiryMonth = expiryMonth.toInt(),
expiryYears = Pair(startYear, endYear),
isEditing = true

@ -9,6 +9,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage
import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment
@ -33,7 +34,7 @@ interface CreditCardEditorController {
/**
* @see [CreditCardEditorInteractor.onSaveCreditCard]
*/
fun handleSaveCreditCard(creditCardFields: UpdatableCreditCardFields)
fun handleSaveCreditCard(creditCardFields: NewCreditCardFields)
/**
* @see [CreditCardEditorInteractor.onUpdateCreditCard]
@ -71,7 +72,7 @@ class DefaultCreditCardEditorController(
}
}
override fun handleSaveCreditCard(creditCardFields: UpdatableCreditCardFields) {
override fun handleSaveCreditCard(creditCardFields: NewCreditCardFields) {
lifecycleScope.launch(ioDispatcher) {
storage.addCreditCard(creditCardFields)

@ -4,6 +4,7 @@
package org.mozilla.fenix.settings.creditcards.interactor
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import org.mozilla.fenix.settings.creditcards.controller.CreditCardEditorController
@ -30,9 +31,9 @@ interface CreditCardEditorInteractor {
* Saves the provided credit card field into the credit card storage. Called when a user
* taps on the save menu item or "Save" button.
*
* @param creditCardFields A [UpdatableCreditCardFields] record to add.
* @param creditCardFields A [NewCreditCardFields] record to add.
*/
fun onSaveCreditCard(creditCardFields: UpdatableCreditCardFields)
fun onSaveCreditCard(creditCardFields: NewCreditCardFields)
/**
* Updates the provided credit card with the new credit card fields. Called when a user
@ -62,7 +63,7 @@ class DefaultCreditCardEditorInteractor(
controller.handleDeleteCreditCard(guid)
}
override fun onSaveCreditCard(creditCardFields: UpdatableCreditCardFields) {
override fun onSaveCreditCard(creditCardFields: NewCreditCardFields) {
controller.handleSaveCreditCard(creditCardFields)
}

@ -9,6 +9,8 @@ import android.view.View
import android.widget.ArrayAdapter
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.fragment_credit_card_editor.*
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.ext.toEditable
@ -30,6 +32,7 @@ class CreditCardEditorView(
/**
* Binds the given [CreditCardEditorState] in the [CreditCardEditorFragment].
*/
@Suppress("MagicNumber")
fun bind(state: CreditCardEditorState) {
if (state.isEditing) {
delete_button.apply {
@ -48,18 +51,29 @@ class CreditCardEditorView(
save_button.setOnClickListener {
containerView.hideKeyboard()
val creditCardFields = UpdatableCreditCardFields(
billingName = name_on_card_input.text.toString(),
cardNumber = card_number_input.text.toString(),
expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(),
expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(),
cardType = CARD_TYPE_PLACEHOLDER
)
// TODO same as in the corresponding fragment, plaintext number if it's being updated or
// round-tripped otherwise. Also, why is there so much duplication?
val cardNumber = card_number_input.text.toString()
if (state.isEditing) {
interactor.onUpdateCreditCard(state.guid, creditCardFields)
val fields = UpdatableCreditCardFields(
billingName = name_on_card_input.text.toString(),
cardNumber = CreditCardNumber.Encrypted(cardNumber),
cardNumberLast4 = cardNumber.substring(cardNumber.length - 4),
expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(),
expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(),
cardType = CARD_TYPE_PLACEHOLDER
)
interactor.onUpdateCreditCard(state.guid, fields)
} else {
interactor.onSaveCreditCard(creditCardFields)
val fields = NewCreditCardFields(
billingName = name_on_card_input.text.toString(),
plaintextCardNumber = CreditCardNumber.Plaintext(cardNumber),
cardNumberLast4 = cardNumber.substring(cardNumber.length - 4),
expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(),
expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(),
cardType = CARD_TYPE_PLACEHOLDER
)
interactor.onSaveCreditCard(fields)
}
}

@ -23,7 +23,9 @@ class CreditCardItemViewHolder(
) : ViewHolder(view) {
fun bind(creditCard: CreditCard) {
credit_card_number.text = creditCard.cardNumber
// TODO this should be last4 instead...
// and option to explicitly decrypt if necessary to show full number
credit_card_number.text = creditCard.encryptedCardNumber.number
bindCreditCardExpiryDate(creditCard)

@ -5,6 +5,7 @@
package org.mozilla.fenix.settings.creditcards
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@ -17,7 +18,8 @@ class CreditCardEditorStateTest {
private val creditCard = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryMonth = 5,
expiryYear = 2030,
cardType = "amex",
@ -36,7 +38,7 @@ class CreditCardEditorStateTest {
with(state) {
assertEquals(creditCard.guid, guid)
assertEquals(creditCard.billingName, billingName)
assertEquals(creditCard.cardNumber, cardNumber)
assertEquals(creditCard.encryptedCardNumber.number, cardNumber)
assertEquals(creditCard.expiryMonth.toInt(), expiryMonth)
assertEquals(Pair(startYear, endYear), expiryYears)
assertTrue(isEditing)

@ -10,6 +10,8 @@ import io.mockk.mockk
import io.mockk.verify
import kotlinx.android.synthetic.main.fragment_credit_card_editor.view.*
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
@ -35,7 +37,8 @@ class CreditCardEditorViewTest {
private val creditCard = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryMonth = 5,
expiryYear = 2030,
cardType = "amex",
@ -83,7 +86,7 @@ class CreditCardEditorViewTest {
fun `GIVEN a credit card THEN credit card form inputs are displaying the provided credit card information`() {
creditCardEditorView.bind(creditCard.toCreditCardEditorState())
assertEquals(creditCard.cardNumber, view.card_number_input.text.toString())
assertEquals(creditCard.encryptedCardNumber.number, view.card_number_input.text.toString())
assertEquals(creditCard.billingName, view.name_on_card_input.text.toString())
with(view.expiry_month_drop_down) {
@ -139,9 +142,10 @@ class CreditCardEditorViewTest {
verify {
interactor.onSaveCreditCard(
UpdatableCreditCardFields(
NewCreditCardFields(
billingName = billingName,
cardNumber = cardNumber,
plaintextCardNumber = CreditCardNumber.Plaintext(cardNumber),
cardNumberLast4 = "1110",
expiryMonth = expiryMonth.toLong(),
expiryYear = expiryYear.toLong(),
cardType = CARD_TYPE_PLACEHOLDER
@ -161,7 +165,8 @@ class CreditCardEditorViewTest {
guid = creditCard.guid,
creditCardFields = UpdatableCreditCardFields(
billingName = creditCard.billingName,
cardNumber = creditCard.cardNumber,
cardNumber = creditCard.encryptedCardNumber,
cardNumberLast4 = creditCard.cardNumberLast4,
expiryMonth = creditCard.expiryMonth,
expiryYear = creditCard.expiryYear,
cardType = CARD_TYPE_PLACEHOLDER

@ -10,6 +10,7 @@ import io.mockk.mockk
import io.mockk.verify
import kotlinx.android.synthetic.main.credit_card_list_item.view.*
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Before
@ -28,7 +29,8 @@ class CreditCardItemViewHolderTest {
private val creditCard = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
@ -48,7 +50,7 @@ class CreditCardItemViewHolderTest {
fun `GIVEN a new credit card item on bind THEN set the card number and expiry date text`() {
CreditCardItemViewHolder(view, interactor).bind(creditCard)
assertEquals(creditCard.cardNumber, view.credit_card_number.text)
assertEquals(creditCard.encryptedCardNumber.number, view.credit_card_number.text)
assertEquals("0${creditCard.expiryMonth}/${creditCard.expiryYear}", view.expiry_date.text)
}

@ -5,6 +5,7 @@
package org.mozilla.fenix.settings.creditcards
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
@ -17,7 +18,8 @@ class CreditCardsAdapterTest {
val creditCard1 = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
@ -29,7 +31,8 @@ class CreditCardsAdapterTest {
val creditCard2 = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
@ -49,7 +52,8 @@ class CreditCardsAdapterTest {
val creditCard3 = CreditCard(
guid = "id3",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",

@ -13,7 +13,8 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.test.runBlockingTest
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage
import mozilla.components.support.test.rule.MainCoroutineRule
@ -66,32 +67,22 @@ class DefaultCreditCardEditorControllerTest {
@Test
fun handleDeleteCreditCard() = testCoroutineScope.runBlockingTest {
val creditCard = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,
timesUsed = 1L
)
val creditCardId = "id"
controller.handleDeleteCreditCard(creditCard.guid)
controller.handleDeleteCreditCard(creditCardId)
coVerify {
storage.deleteCreditCard(creditCard.guid)
storage.deleteCreditCard(creditCardId)
navController.popBackStack()
}
}
@Test
fun handleSaveCreditCard() = testCoroutineScope.runBlockingTest {
val creditCardFields = UpdatableCreditCardFields(
val creditCardFields = NewCreditCardFields(
billingName = "Banana Apple",
cardNumber = "4111111111111112",
plaintextCardNumber = CreditCardNumber.Plaintext("4111111111111112"),
cardNumberLast4 = "1112",
expiryMonth = 1,
expiryYear = 2030,
cardType = "discover"
@ -107,30 +98,20 @@ class DefaultCreditCardEditorControllerTest {
@Test
fun handleUpdateCreditCard() = testCoroutineScope.runBlockingTest {
val creditCard = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,
timesUsed = 1L
)
val creditCardId = "id"
val creditCardFields = UpdatableCreditCardFields(
billingName = "Banana Apple",
cardNumber = "4111111111111112",
cardNumber = CreditCardNumber.Plaintext("4111111111111112"),
cardNumberLast4 = "1112",
expiryMonth = 1,
expiryYear = 2034,
cardType = "discover"
)
controller.handleUpdateCreditCard(creditCard.guid, creditCardFields)
controller.handleUpdateCreditCard(creditCardId, creditCardFields)
coVerify {
storage.updateCreditCard(creditCard.guid, creditCardFields)
storage.updateCreditCard(creditCardId, creditCardFields)
navController.popBackStack()
}
}

@ -7,6 +7,8 @@ package org.mozilla.fenix.settings.creditcards
import io.mockk.mockk
import io.mockk.verify
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import org.junit.Before
import org.junit.Test
@ -35,7 +37,8 @@ class DefaultCreditCardEditorInteractorTest {
val creditCard = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
@ -50,9 +53,10 @@ class DefaultCreditCardEditorInteractorTest {
@Test
fun onSaveButtonClicked() {
val creditCardFields = UpdatableCreditCardFields(
val creditCardFields = NewCreditCardFields(
billingName = "Banana Apple",
cardNumber = "4111111111111112",
plaintextCardNumber = CreditCardNumber.Plaintext("4111111111111112"),
cardNumberLast4 = "1112",
expiryMonth = 1,
expiryYear = 2030,
cardType = "discover"
@ -66,7 +70,8 @@ class DefaultCreditCardEditorInteractorTest {
val guid = "id"
val creditCardFields = UpdatableCreditCardFields(
billingName = "Banana Apple",
cardNumber = "4111111111111112",
cardNumber = CreditCardNumber.Encrypted("4111111111111112"),
cardNumberLast4 = "1112",
expiryMonth = 1,
expiryYear = 2034,
cardType = "discover"

@ -9,6 +9,7 @@ import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -38,8 +39,9 @@ class DefaultCreditCardsManagementControllerTest {
val creditCard = CreditCard(
guid = "id",
billingName = "Banana Apple",
cardNumber = "4111111111111110",
expiryMonth = 1,
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryYear = 2030,
cardType = "amex",
timeCreated = 1L,

Loading…
Cancel
Save