From 84ae9fb3110153ff0fb96ca7756823bf19bf2db5 Mon Sep 17 00:00:00 2001 From: Ivan Sorokin Date: Wed, 29 Jul 2020 19:40:13 +0300 Subject: [PATCH] [Wallet] fix attestation codes being wrongly set as completed (#4557) ### Description Fix a bug, described in details here - https://github.com/celo-org/celo-monorepo/issues/4477#issuecomment-665275466 ### Other changes * Remove error toast, when verification fails, cause we show Modal instead. * Fix a bug, when user presses `Enter Codes` on the error modal but nothing happens until timer has elapsed. ### Tested iOS simulator ### Related issues - Fixes https://github.com/celo-org/celo-monorepo/issues/4477 ### Backwards compatibility Yes --- .../locales/en-US/nuxVerification2.json | 2 +- .../locales/es-419/nuxVerification2.json | 2 +- packages/mobile/src/identity/actions.ts | 20 ++++++++++++++----- packages/mobile/src/identity/reducer.ts | 14 +++++++------ .../mobile/src/identity/verification.test.ts | 12 ++++++----- packages/mobile/src/identity/verification.ts | 8 +++----- packages/mobile/src/redux/migrations.test.ts | 11 ++++++++++ packages/mobile/src/redux/migrations.ts | 9 +++++++++ packages/mobile/src/redux/store.ts | 2 +- .../src/verify/VerificationFailedModal.tsx | 1 + 10 files changed, 57 insertions(+), 24 deletions(-) diff --git a/packages/mobile/locales/en-US/nuxVerification2.json b/packages/mobile/locales/en-US/nuxVerification2.json index e803ee76022..c5ee9275884 100644 --- a/packages/mobile/locales/en-US/nuxVerification2.json +++ b/packages/mobile/locales/en-US/nuxVerification2.json @@ -48,7 +48,7 @@ "body2InsufficientBalance": "Please try again when you have added funds to your wallet.", "body1SaltQuotaExceeded": "Your phone number lookup quota is used up", "body2SaltQuotaExceeded": "Please try again when you have purchased more lookups", - "enterCodesBody": " If you already received three codes via SMS, you can still enter them.", + "enterCodesBody": "If you already received three codes via SMS, you can still enter them.", "enterCodesButton": "Enter Codes" }, "retryWithFornoModal": { diff --git a/packages/mobile/locales/es-419/nuxVerification2.json b/packages/mobile/locales/es-419/nuxVerification2.json index e373dba4a5f..f990be79f29 100755 --- a/packages/mobile/locales/es-419/nuxVerification2.json +++ b/packages/mobile/locales/es-419/nuxVerification2.json @@ -48,7 +48,7 @@ "body2InsufficientBalance": "Intente nuevamente cuando haya agregado fondos a su billetera.", "body1SaltQuotaExceeded": "Su cuota de búsqueda de número de teléfono está agotada", "body2SaltQuotaExceeded": "Intente nuevamente cuando haya comprado más búsquedas", - "enterCodesBody": " Si ya recibió tres códigos por SMS, aún puede ingresarlos.", + "enterCodesBody": "Si ya recibió tres códigos por SMS, aún puede ingresarlos.", "enterCodesButton": "Ingresar códigos" }, "retryWithFornoModal": { diff --git a/packages/mobile/src/identity/actions.ts b/packages/mobile/src/identity/actions.ts index fc55fea9391..1257d8c2d86 100644 --- a/packages/mobile/src/identity/actions.ts +++ b/packages/mobile/src/identity/actions.ts @@ -15,6 +15,7 @@ export enum Actions { RESET_VERIFICATION = 'IDENTITY/RESET_VERIFICATION', SET_VERIFICATION_STATUS = 'IDENTITY/SET_VERIFICATION_STATUS', SET_SEEN_VERIFICATION_NUX = 'IDENTITY/SET_SEEN_VERIFICATION_NUX', + SET_COMPLETED_CODES = 'IDENTITY/SET_COMPLETED_CODES', REVOKE_VERIFICATION = 'IDENTITY/REVOKE_VERIFICATION', RECEIVE_ATTESTATION_MESSAGE = 'IDENTITY/RECEIVE_ATTESTATION_MESSAGE', INPUT_ATTESTATION_CODE = 'IDENTITY/INPUT_ATTESTATION_CODE', @@ -69,6 +70,11 @@ export interface ReceiveAttestationMessageAction { inputType: CodeInputType } +export interface SetCompletedCodesAction { + type: Actions.SET_COMPLETED_CODES + numComplete: number +} + export interface InputAttestationCodeAction { type: Actions.INPUT_ATTESTATION_CODE code: AttestationCode @@ -76,7 +82,7 @@ export interface InputAttestationCodeAction { export interface CompleteAttestationCodeAction { type: Actions.COMPLETE_ATTESTATION_CODE - numComplete: number + code: AttestationCode } export interface UpdateE164PhoneNumberAddressesAction { @@ -173,6 +179,7 @@ export type ActionTypes = | ResetVerificationAction | SetVerificationStatusAction | SetHasSeenVerificationNux + | SetCompletedCodesAction | ReceiveAttestationMessageAction | InputAttestationCodeAction | CompleteAttestationCodeAction @@ -227,16 +234,19 @@ export const receiveAttestationMessage = ( inputType, }) +export const setCompletedCodes = (numComplete: number): SetCompletedCodesAction => ({ + type: Actions.SET_COMPLETED_CODES, + numComplete, +}) + export const inputAttestationCode = (code: AttestationCode): InputAttestationCodeAction => ({ type: Actions.INPUT_ATTESTATION_CODE, code, }) -export const completeAttestationCode = ( - numComplete: number = 1 -): CompleteAttestationCodeAction => ({ +export const completeAttestationCode = (code: AttestationCode): CompleteAttestationCodeAction => ({ type: Actions.COMPLETE_ATTESTATION_CODE, - numComplete, + code, }) export const fetchAddressesAndValidate = ( diff --git a/packages/mobile/src/identity/reducer.ts b/packages/mobile/src/identity/reducer.ts index 48218024a5e..6cb28c982cc 100644 --- a/packages/mobile/src/identity/reducer.ts +++ b/packages/mobile/src/identity/reducer.ts @@ -119,26 +119,28 @@ export const reducer = ( return { ...state, verificationStatus: action.status, - // Reset accepted codes on fail otherwise there's no way for user - // to try again with same codes - acceptedAttestationCodes: - action.status === VerificationStatus.Failed ? [] : state.acceptedAttestationCodes, } case Actions.SET_SEEN_VERIFICATION_NUX: return { ...state, hasSeenVerificationNux: action.status, } + case Actions.SET_COMPLETED_CODES: + return { + ...state, + ...completeCodeReducer(state, action.numComplete), + } + case Actions.INPUT_ATTESTATION_CODE: return { ...state, attestationCodes: [...state.attestationCodes, action.code], - acceptedAttestationCodes: [...state.acceptedAttestationCodes, action.code], } case Actions.COMPLETE_ATTESTATION_CODE: return { ...state, - ...completeCodeReducer(state, state.numCompleteAttestations + action.numComplete), + ...completeCodeReducer(state, state.numCompleteAttestations + 1), + acceptedAttestationCodes: [...state.acceptedAttestationCodes, action.code], } case Actions.UPDATE_E164_PHONE_NUMBER_ADDRESSES: return { diff --git a/packages/mobile/src/identity/verification.test.ts b/packages/mobile/src/identity/verification.test.ts index fb86a3fd8c8..4152202ddd5 100644 --- a/packages/mobile/src/identity/verification.test.ts +++ b/packages/mobile/src/identity/verification.test.ts @@ -12,6 +12,7 @@ import { ErrorMessages } from 'src/app/ErrorMessages' import { cancelVerification, completeAttestationCode, + setCompletedCodes, setVerificationStatus, } from 'src/identity/actions' import { fetchPhoneHashPrivate } from 'src/identity/privateHashing' @@ -225,11 +226,12 @@ describe('Do Verification Saga', () => { ]) .put(setVerificationStatus(VerificationStatus.Prepping)) .put(setVerificationStatus(VerificationStatus.GettingStatus)) + .put(setCompletedCodes(0)) .put(setVerificationStatus(VerificationStatus.RequestingAttestations)) .put(setVerificationStatus(VerificationStatus.RevealingNumber)) - .put(completeAttestationCode()) - .put(completeAttestationCode()) - .put(completeAttestationCode()) + .put(completeAttestationCode(attestationCode0)) + .put(completeAttestationCode(attestationCode1)) + .put(completeAttestationCode(attestationCode2)) .put(setVerificationStatus(VerificationStatus.Done)) .put(setNumberVerified(true)) .returns(true) @@ -255,7 +257,8 @@ describe('Do Verification Saga', () => { [call(balanceSufficientForAttestations, mockAttestationsRemainingForPartialVerified), true], [select(attestationCodesSelector), attestationCodes], ]) - .put(completeAttestationCode()) + .put(setCompletedCodes(2)) + .put(completeAttestationCode(attestationCode0)) .put(setVerificationStatus(VerificationStatus.Done)) .put(setNumberVerified(true)) .returns(true) @@ -355,7 +358,6 @@ describe('Do Verification Saga', () => { [call(balanceSufficientForAttestations, mockAttestationsRemainingForPartialVerified), true], [select(attestationCodesSelector), attestationCodes], ]) - .put(showError(ErrorMessages.REVEAL_ATTESTATION_FAILURE)) .put(setVerificationStatus(VerificationStatus.RevealAttemptFailed)) .run() }) diff --git a/packages/mobile/src/identity/verification.ts b/packages/mobile/src/identity/verification.ts index 81b52bfa272..bdb83b66b18 100644 --- a/packages/mobile/src/identity/verification.ts +++ b/packages/mobile/src/identity/verification.ts @@ -30,6 +30,7 @@ import { InputAttestationCodeAction, ReceiveAttestationMessageAction, resetVerification, + setCompletedCodes, setVerificationStatus, } from 'src/identity/actions' import { fetchPhoneHashPrivate, PhoneNumberHashDetails } from 'src/identity/privateHashing' @@ -154,9 +155,7 @@ export function* doVerificationFlow() { } // Mark codes completed in previous attempts - yield put( - completeAttestationCode(NUM_ATTESTATIONS_REQUIRED - status.numAttestationsRemaining) - ) + yield put(setCompletedCodes(NUM_ATTESTATIONS_REQUIRED - status.numAttestationsRemaining)) yield put(setVerificationStatus(VerificationStatus.RequestingAttestations)) @@ -516,7 +515,7 @@ function* revealAndCompleteAttestation( ValoraAnalytics.track(VerificationEvents.verification_reveal_attestation_complete, { issuer }) - yield put(completeAttestationCode()) + yield put(completeAttestationCode(code)) Logger.debug(TAG + '@revealAttestation', `Attestation for issuer ${issuer} completed`) } @@ -609,7 +608,6 @@ function* tryRevealPhoneNumber( issuer, error: error.message, }) - yield put(showError(ErrorMessages.REVEAL_ATTESTATION_FAILURE)) yield put(setVerificationStatus(VerificationStatus.RevealAttemptFailed)) } } diff --git a/packages/mobile/src/redux/migrations.test.ts b/packages/mobile/src/redux/migrations.test.ts index c038a966bf7..b9ed046c2c3 100644 --- a/packages/mobile/src/redux/migrations.test.ts +++ b/packages/mobile/src/redux/migrations.test.ts @@ -59,4 +59,15 @@ describe('Redux persist migrations', () => { const migratedSchema = migrations[3](v2Stub) expect(migratedSchema.send.recentPayments.length).toEqual(0) }) + it('works for v3 to v4', () => { + const v3Stub = { + ...v2Schema, + identity: { + ...v2Schema.identity, + acceptedAttestationCodes: [{ code: 'code', issuer: 'issuer' }], + }, + } + const migratedSchema = migrations[4](v3Stub) + expect(migratedSchema.identity.acceptedAttestationCodes.length).toEqual(0) + }) }) diff --git a/packages/mobile/src/redux/migrations.ts b/packages/mobile/src/redux/migrations.ts index 9c1215c29ac..b8e969d745c 100644 --- a/packages/mobile/src/redux/migrations.ts +++ b/packages/mobile/src/redux/migrations.ts @@ -54,4 +54,13 @@ export const migrations = { }, } }, + 4: (state: any) => { + return { + ...state, + identity: { + ...state.identity, + acceptedAttestationCodes: [], + }, + } + }, } diff --git a/packages/mobile/src/redux/store.ts b/packages/mobile/src/redux/store.ts index db299938e9f..819b0cd11e6 100644 --- a/packages/mobile/src/redux/store.ts +++ b/packages/mobile/src/redux/store.ts @@ -9,7 +9,7 @@ import { rootSaga } from 'src/redux/sagas' const persistConfig: any = { key: 'root', - version: 3, // default is -1, increment as we make migrations + version: 4, // default is -1, increment as we make migrations storage: AsyncStorage, blacklist: ['home', 'geth', 'networkInfo', 'alert', 'fees', 'recipients', 'imports'], stateReconciler: autoMergeLevel2, diff --git a/packages/mobile/src/verify/VerificationFailedModal.tsx b/packages/mobile/src/verify/VerificationFailedModal.tsx index 458b1ae5859..0ebf8994ad7 100644 --- a/packages/mobile/src/verify/VerificationFailedModal.tsx +++ b/packages/mobile/src/verify/VerificationFailedModal.tsx @@ -27,6 +27,7 @@ export function VerificationFailedModal({ verificationStatus, retryWithForno, fo const onDismiss = () => { setIsDismissed(true) + navigate(Screens.VerificationInputScreen) } const onSkip = () => {