diff --git a/__mocks__/react-native-keychain.ts b/__mocks__/@interaxyz/react-native-keychain.ts similarity index 86% rename from __mocks__/react-native-keychain.ts rename to __mocks__/@interaxyz/react-native-keychain.ts index 4ca1163f48d..9af314df36f 100644 --- a/__mocks__/react-native-keychain.ts +++ b/__mocks__/@interaxyz/react-native-keychain.ts @@ -28,6 +28,14 @@ const keychainMock = { SECURE_HARDWARE: 'SECURE_HARDWARE', ANY: 'ANY', }, + STORAGE_TYPE: { + FB: 'MOCK_FacebookConceal', + AES: 'MOCK_KeystoreAESCBC', + AES_CBC: 'MOCK_KeystoreAESCBC', + AES_GCM_NO_AUTH: 'MOCK_KeystoreAESGCM_NoAuth', + AES_GCM: 'MOCK_KeystoreAESGCM', + RSA: 'MOCK_KeystoreRSAECB', + }, setGenericPassword: jest.fn(async (username, password, options) => { mockedItems.set(options.service, { username, password, options }) return true diff --git a/android/app/build.gradle b/android/app/build.gradle index bff7bb0c86c..5c6469ee38c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,5 +1,6 @@ apply plugin: "com.android.application" apply plugin: "com.facebook.react" +apply plugin: 'kotlin-android' import com.android.build.OutputFile import groovy.json.JsonSlurper diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3aaacfa16e2..8c5e213b116 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -783,7 +783,8 @@ PODS: - RNGestureHandler (2.21.2): - RCT-Folly (= 2021.07.22.00) - React-Core - - RNKeychain (8.2.0): + - RNKeychain (9.2.2): + - RCT-Folly (= 2021.07.22.00) - React-Core - RNLocalize (3.3.0): - React-Core @@ -947,7 +948,7 @@ DEPENDENCIES: - "RNFBRemoteConfig (from `../node_modules/@react-native-firebase/remote-config`)" - RNFS (from `../node_modules/react-native-fs`) - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - - RNKeychain (from `../node_modules/react-native-keychain`) + - "RNKeychain (from `../node_modules/@interaxyz/react-native-keychain`)" - RNLocalize (from `../node_modules/react-native-localize`) - RNPermissions (from `../node_modules/react-native-permissions`) - RNPersonaInquiry2 (from `../node_modules/react-native-persona`) @@ -1170,7 +1171,7 @@ EXTERNAL SOURCES: RNGestureHandler: :path: "../node_modules/react-native-gesture-handler" RNKeychain: - :path: "../node_modules/react-native-keychain" + :path: "../node_modules/@interaxyz/react-native-keychain" RNLocalize: :path: "../node_modules/react-native-localize" RNPermissions: @@ -1317,7 +1318,7 @@ SPEC CHECKSUMS: RNFBRemoteConfig: 1c92f072b1772b91663247b07a711cd4e9e191e8 RNFS: 89de7d7f4c0f6bafa05343c578f61118c8282ed8 RNGestureHandler: b81313e62e717cc165ea3b99436aa305d04c57b4 - RNKeychain: bbe2f6d5cc008920324acb49ef86ccc03d3b38e4 + RNKeychain: 91dc223bc77e3bb8576a3c75cdd28863bc2cb26e RNLocalize: d024afa9204c13885e61dc88b8190651bcaabac9 RNPermissions: 1d002266e43df33d7080d5355a64b7d12bdb5e75 RNPersonaInquiry2: 4202f797d7a172af2908f271954123858abe47bf diff --git a/package.json b/package.json index 1bc4eb572f6..af19b9cfdaf 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "@fiatconnect/fiatconnect-types": "^13.3.10", "@gorhom/bottom-sheet": "^5.0.6", "@interaxyz/react-navigation-bottom-sheet": "^0.3.2", + "@interaxyz/react-native-keychain": "^9.2.2", "@interaxyz/react-native-webview": "^13.13.4", "@json-rpc-tools/utils": "^1.7.6", "@noble/secp256k1": "^1.7.1", @@ -149,7 +150,6 @@ "react-native-gesture-handler": "^2.21.2", "react-native-haptic-feedback": "^2.3.3", "react-native-in-app-review": "^4.3.3", - "react-native-keychain": "^8.2.0", "react-native-launch-arguments": "^4.0.2", "react-native-linear-gradient": "^2.8.3", "react-native-localize": "^3.3.0", diff --git a/patches/react-native-keychain+8.2.0.patch b/patches/react-native-keychain+8.2.0.patch deleted file mode 100644 index 9d60fe66b02..00000000000 --- a/patches/react-native-keychain+8.2.0.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.m b/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.m -index 58d555f..e1e7c0f 100644 ---- a/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.m -+++ b/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.m -@@ -280,6 +280,8 @@ - (OSStatus)deleteCredentialsForServer:(NSString *)server - NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys: - (__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes, - (__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit, -+ // Silently skip any items that require user authentication. To avoid the auth prompt. -+ (__bridge id)kSecUseAuthenticationUISkip, (__bridge id)kSecUseAuthenticationUI, - nil]; - NSMutableArray *services = [NSMutableArray new]; - for (id secItemClass in secItemClasses) { diff --git a/src/account/ProfileSubmenu.test.tsx b/src/account/ProfileSubmenu.test.tsx index 76a9466bd37..db7f737b747 100644 --- a/src/account/ProfileSubmenu.test.tsx +++ b/src/account/ProfileSubmenu.test.tsx @@ -1,18 +1,18 @@ +import * as Keychain from '@interaxyz/react-native-keychain' +import { act, fireEvent, render, waitFor } from '@testing-library/react-native' +import { FetchMock } from 'jest-fetch-mock/types' import * as React from 'react' import 'react-native' import { Provider } from 'react-redux' import ProfileSubmenu from 'src/account/ProfileSubmenu' import { Screens } from 'src/navigator/Screens' +import Logger from 'src/utils/Logger' +import networkConfig from 'src/web3/networkConfig' import MockedNavigator from 'test/MockedNavigator' -import { FetchMock } from 'jest-fetch-mock/types' import { createMockStore, getMockStackScreenProps } from 'test/utils' import { mockE164Number } from 'test/values' -import networkConfig from 'src/web3/networkConfig' -import { act, fireEvent, render, waitFor } from '@testing-library/react-native' -import * as Keychain from 'react-native-keychain' const mockFetch = fetch as FetchMock const mockedKeychain = jest.mocked(Keychain) -import Logger from 'src/utils/Logger' jest.mock('src/utils/Logger') @@ -20,7 +20,7 @@ mockedKeychain.getGenericPassword.mockResolvedValue({ username: 'some username', password: 'someSignedMessage', service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, }) describe('ProfileSubmenu', () => { diff --git a/src/account/SecuritySubmenu.test.tsx b/src/account/SecuritySubmenu.test.tsx index 55c8d23ff99..ede6e713778 100644 --- a/src/account/SecuritySubmenu.test.tsx +++ b/src/account/SecuritySubmenu.test.tsx @@ -1,28 +1,28 @@ +import * as Keychain from '@interaxyz/react-native-keychain' +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' +import { act, fireEvent, render, waitFor } from '@testing-library/react-native' +import { FetchMock } from 'jest-fetch-mock/types' import * as React from 'react' import 'react-native' import { Provider } from 'react-redux' -import SecuritySubmenu from 'src/account/SecuritySubmenu' -import { Screens } from 'src/navigator/Screens' -import MockedNavigator from 'test/MockedNavigator' -import { createMockStore } from 'test/utils' -import { fireEvent, render, waitFor, act } from '@testing-library/react-native' -import { ensurePincode, navigate } from 'src/navigator/NavigationService' -import { FetchMock } from 'jest-fetch-mock/types' -import * as Keychain from 'react-native-keychain' -import { setAnalyticsEnabled } from 'src/app/actions' -import { showError } from 'src/alert/actions' -import { ErrorMessages } from 'src/app/ErrorMessages' import { setPincodeSuccess } from 'src/account/actions' -import { mockE164Number } from 'test/values' -import { BIOMETRY_TYPE } from 'react-native-keychain' import { PincodeType } from 'src/account/reducer' -import { removeStoredPin, setPincodeWithBiometry } from 'src/pincode/authentication' +import SecuritySubmenu from 'src/account/SecuritySubmenu' +import { showError } from 'src/alert/actions' import AppAnalytics from 'src/analytics/AppAnalytics' import { SettingsEvents } from 'src/analytics/Events' -import { getFeatureGate } from 'src/statsig/index' +import { setAnalyticsEnabled } from 'src/app/actions' +import { ErrorMessages } from 'src/app/ErrorMessages' import { deleteKeylessBackupStarted, hideDeleteKeylessBackupError } from 'src/keylessBackup/slice' import { KeylessBackupDeleteStatus } from 'src/keylessBackup/types' +import { ensurePincode, navigate } from 'src/navigator/NavigationService' +import { Screens } from 'src/navigator/Screens' +import { removeStoredPin, setPincodeWithBiometry } from 'src/pincode/authentication' +import { getFeatureGate } from 'src/statsig/index' import networkConfig from 'src/web3/networkConfig' +import MockedNavigator from 'test/MockedNavigator' +import { createMockStore } from 'test/utils' +import { mockE164Number } from 'test/values' const mockedEnsurePincode = jest.mocked(ensurePincode) const mockFetch = fetch as FetchMock @@ -31,7 +31,7 @@ mockedKeychain.getGenericPassword.mockResolvedValue({ username: 'some username', password: 'someSignedMessage', service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, }) jest.mock('src/analytics/AppAnalytics') diff --git a/src/account/saga.test.ts b/src/account/saga.test.ts index 10fa1df42a0..a066b1a02ac 100644 --- a/src/account/saga.test.ts +++ b/src/account/saga.test.ts @@ -1,5 +1,5 @@ +import * as Keychain from '@interaxyz/react-native-keychain' import { FetchMock } from 'jest-fetch-mock/types' -import * as Keychain from 'react-native-keychain' import { expectSaga } from 'redux-saga-test-plan' import * as matchers from 'redux-saga-test-plan/matchers' import { throwError } from 'redux-saga-test-plan/providers' @@ -103,7 +103,7 @@ describe('generateSignedMessage', () => { username: 'some username', password: 'someSignedMessage', service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, }) await expectSaga(generateSignedMessage) diff --git a/src/app/actions.ts b/src/app/actions.ts index a3fb4fb41c2..1ee9c377354 100644 --- a/src/app/actions.ts +++ b/src/app/actions.ts @@ -1,4 +1,4 @@ -import { BIOMETRY_TYPE } from 'react-native-keychain' +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' import { RemoteConfigValues } from 'src/app/saga' import { Screens } from 'src/navigator/Screens' diff --git a/src/app/reducers.ts b/src/app/reducers.ts index 1bb134bad2a..e308c72b80f 100644 --- a/src/app/reducers.ts +++ b/src/app/reducers.ts @@ -1,5 +1,5 @@ +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' import { Platform } from 'react-native' -import { BIOMETRY_TYPE } from 'react-native-keychain' import { Actions, ActionTypes, AppState } from 'src/app/actions' import { CeloNewsConfig } from 'src/celoNews/types' import { DEEP_LINK_URL_SCHEME } from 'src/config' diff --git a/src/app/saga.test.ts b/src/app/saga.test.ts index 6e7344a75a3..84ea7cb99c4 100644 --- a/src/app/saga.test.ts +++ b/src/app/saga.test.ts @@ -1,4 +1,4 @@ -import { BIOMETRY_TYPE } from 'react-native-keychain' +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' import * as RNLocalize from 'react-native-localize' import { expectSaga } from 'redux-saga-test-plan' import * as matchers from 'redux-saga-test-plan/matchers' diff --git a/src/app/saga.ts b/src/app/saga.ts index 7dd576beb34..7a6d7490129 100644 --- a/src/app/saga.ts +++ b/src/app/saga.ts @@ -1,8 +1,8 @@ +import * as Keychain from '@interaxyz/react-native-keychain' import locales from 'locales' import { AppState, Platform } from 'react-native' import DeviceInfo from 'react-native-device-info' import InAppReview from 'react-native-in-app-review' -import * as Keychain from 'react-native-keychain' import { findBestLanguageTag } from 'react-native-localize' import { eventChannel } from 'redux-saga' import AppAnalytics from 'src/analytics/AppAnalytics' diff --git a/src/backup/BackupPhrase.test.tsx b/src/backup/BackupPhrase.test.tsx index ca072c2b0ce..5d0453174a4 100644 --- a/src/backup/BackupPhrase.test.tsx +++ b/src/backup/BackupPhrase.test.tsx @@ -1,7 +1,7 @@ +import * as Keychain from '@interaxyz/react-native-keychain' import { fireEvent, render } from '@testing-library/react-native' import * as React from 'react' import 'react-native' -import * as Keychain from 'react-native-keychain' import { Provider } from 'react-redux' import BackupPhrase from 'src/backup/BackupPhrase' import { navigate } from 'src/navigator/NavigationService' diff --git a/src/onboarding/registration/EnableBiometry.test.tsx b/src/onboarding/registration/EnableBiometry.test.tsx index 9d714e338ab..eb210641e96 100644 --- a/src/onboarding/registration/EnableBiometry.test.tsx +++ b/src/onboarding/registration/EnableBiometry.test.tsx @@ -1,11 +1,11 @@ +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' import { act, fireEvent, render } from '@testing-library/react-native' import * as React from 'react' -import { BIOMETRY_TYPE } from 'react-native-keychain' import { Provider } from 'react-redux' import { setPincodeSuccess } from 'src/account/actions' import { PincodeType } from 'src/account/reducer' -import { OnboardingEvents } from 'src/analytics/Events' import AppAnalytics from 'src/analytics/AppAnalytics' +import { OnboardingEvents } from 'src/analytics/Events' import { Screens } from 'src/navigator/Screens' import EnableBiometry from 'src/onboarding/registration/EnableBiometry' import { goToNextOnboardingScreen } from 'src/onboarding/steps' diff --git a/src/onboarding/registration/EnableBiometry.tsx b/src/onboarding/registration/EnableBiometry.tsx index 68cdfd21aa3..aa5283990d2 100644 --- a/src/onboarding/registration/EnableBiometry.tsx +++ b/src/onboarding/registration/EnableBiometry.tsx @@ -1,9 +1,9 @@ +import * as Keychain from '@interaxyz/react-native-keychain' import { useHeaderHeight } from '@react-navigation/elements' import { NativeStackScreenProps } from '@react-navigation/native-stack' import React, { useEffect, useLayoutEffect } from 'react' import { useTranslation } from 'react-i18next' import { Image, ScrollView, StyleSheet, Text, View } from 'react-native' -import * as Keychain from 'react-native-keychain' import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' import { setPincodeSuccess } from 'src/account/actions' import { PincodeType } from 'src/account/reducer' diff --git a/src/onboarding/steps.test.ts b/src/onboarding/steps.test.ts index 37a196241d7..d81d9198e6c 100644 --- a/src/onboarding/steps.test.ts +++ b/src/onboarding/steps.test.ts @@ -1,4 +1,4 @@ -import { BIOMETRY_TYPE } from 'react-native-keychain' +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' import { initializeAccount } from 'src/account/actions' import { KeylessBackupFlow } from 'src/keylessBackup/types' import { navigate, navigateClearingStack, popToScreen } from 'src/navigator/NavigationService' diff --git a/src/onboarding/steps.ts b/src/onboarding/steps.ts index 9226eea75b4..e7ba9fa462a 100644 --- a/src/onboarding/steps.ts +++ b/src/onboarding/steps.ts @@ -1,4 +1,4 @@ -import { BIOMETRY_TYPE } from 'react-native-keychain' +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' import { createSelector } from 'reselect' import { initializeAccount } from 'src/account/actions' import { diff --git a/src/pincode/PincodeLock.test.tsx b/src/pincode/PincodeLock.test.tsx index e897fe6a383..c3956c31776 100644 --- a/src/pincode/PincodeLock.test.tsx +++ b/src/pincode/PincodeLock.test.tsx @@ -1,6 +1,6 @@ +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' import { act, fireEvent, render, waitFor } from '@testing-library/react-native' import * as React from 'react' -import { BIOMETRY_TYPE } from 'react-native-keychain' import { Provider } from 'react-redux' import { PincodeType } from 'src/account/reducer' import { appUnlock } from 'src/app/actions' diff --git a/src/pincode/PincodeSet.tsx b/src/pincode/PincodeSet.tsx index 1e06eb3f791..bd64bfa21ad 100644 --- a/src/pincode/PincodeSet.tsx +++ b/src/pincode/PincodeSet.tsx @@ -1,11 +1,11 @@ /** * This is a reactnavigation SCREEN, which we use to set a PIN. */ +import { BIOMETRY_TYPE } from '@interaxyz/react-native-keychain' import { NativeStackScreenProps } from '@react-navigation/native-stack' import * as React from 'react' import { WithTranslation } from 'react-i18next' import { StyleSheet } from 'react-native' -import { BIOMETRY_TYPE } from 'react-native-keychain' import { SafeAreaView } from 'react-native-safe-area-context' import { connect } from 'react-redux' import { initializeAccount, setPincodeSuccess } from 'src/account/actions' diff --git a/src/pincode/authentication.test.ts b/src/pincode/authentication.test.ts index 9c1ae4b8745..17d7795d94b 100644 --- a/src/pincode/authentication.test.ts +++ b/src/pincode/authentication.test.ts @@ -1,4 +1,4 @@ -import * as Keychain from 'react-native-keychain' +import * as Keychain from '@interaxyz/react-native-keychain' import { expectSaga } from 'redux-saga-test-plan' import { select } from 'redux-saga/effects' import { PincodeType } from 'src/account/reducer' @@ -70,7 +70,7 @@ const mockPepper = { password: '01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, } const mockPin = '111555' const mockedKeychain = jest.mocked(Keychain) @@ -169,7 +169,7 @@ describe(getPincode, () => { password: mockPin, username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const pin = await getPincode() @@ -180,6 +180,7 @@ describe(getPincode, () => { authenticationPrompt: { title: 'unlockWithBiometryPrompt', }, + rules: 'none', service: 'PIN', }) }) @@ -198,6 +199,7 @@ describe(getPincode, () => { authenticationPrompt: { title: 'unlockWithBiometryPrompt', }, + rules: 'none', service: 'PIN', }) expect(loggerErrorSpy).toHaveBeenCalledWith( @@ -224,6 +226,7 @@ describe(getPincode, () => { authenticationPrompt: { title: 'unlockWithBiometryPrompt', }, + rules: 'none', service: 'PIN', }) expect(loggerErrorSpy).not.toHaveBeenCalled() @@ -253,7 +256,7 @@ describe(getPincodeWithBiometry, () => { password: mockPin, username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const retrievedPin = await getPincodeWithBiometry() @@ -299,7 +302,7 @@ describe(setPincodeWithBiometry, () => { password: mockPin, username: 'username', service: 'PIN', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) await setPincodeWithBiometry() @@ -311,7 +314,6 @@ describe(setPincodeWithBiometry, () => { expect.objectContaining({ service: 'PIN', accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET, - authenticationType: Keychain.AUTHENTICATION_TYPE.BIOMETRICS, }) ) }) @@ -324,7 +326,7 @@ describe(setPincodeWithBiometry, () => { password: mockPin, username: 'username', service: 'PIN', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) await setPincodeWithBiometry() @@ -337,7 +339,6 @@ describe(setPincodeWithBiometry, () => { expect.objectContaining({ service: 'PIN', accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET, - authenticationType: Keychain.AUTHENTICATION_TYPE.BIOMETRICS, }) ) }) @@ -347,7 +348,7 @@ describe(setPincodeWithBiometry, () => { password: 'some random password', username: 'username', service: 'PIN', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) await expect(setPincodeWithBiometry()).rejects.toThrowError( @@ -373,31 +374,32 @@ describe(updatePin, () => { encryptedMnemonicOldPin = await encryptMnemonic(mockMnemonic, oldPassword) mockedKeychain.getGenericPassword.mockImplementation((options) => { - if (options?.service === 'PEPPER') { + const service = (options as Keychain.GetOptions)?.service ?? options + if (service === 'PEPPER') { return Promise.resolve(mockPepper) } - if (options?.service === 'mnemonic') { + if (service === 'mnemonic') { return Promise.resolve({ username: 'some username', password: encryptedMnemonicOldPin, service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, }) } - if (options?.service === accountHash) { + if (service === accountHash) { return Promise.resolve({ username: 'some username', password: newPasswordHash, service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, }) } - if (options?.service === 'PIN') { + if (service === 'PIN') { return Promise.resolve({ username: 'some username', password: mockPin, service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, }) } return Promise.resolve(false) @@ -453,7 +455,6 @@ describe(updatePin, () => { expect.objectContaining({ service: 'PIN', accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET, - authenticationType: Keychain.AUTHENTICATION_TYPE.BIOMETRICS, }) ) }) @@ -504,7 +505,7 @@ describe(retrieveOrGeneratePepper, () => { mockedKeychain.getGenericPassword.mockResolvedValueOnce(false) mockedKeychain.setGenericPassword.mockResolvedValueOnce({ service: 'PEPPER', - storage: 'some storage', + storage: Keychain.STORAGE_TYPE.RSA, }) mockedKeychain.getGenericPassword.mockResolvedValueOnce(mockPepper) const pepper = await retrieveOrGeneratePepper() @@ -517,7 +518,7 @@ describe(retrieveOrGeneratePepper, () => { mockedKeychain.getGenericPassword.mockResolvedValueOnce(false) mockedKeychain.setGenericPassword.mockResolvedValueOnce({ service: 'PEPPER', - storage: 'some storage', + storage: Keychain.STORAGE_TYPE.RSA, }) mockedKeychain.getGenericPassword.mockResolvedValueOnce({ ...mockPepper, diff --git a/src/pincode/authentication.ts b/src/pincode/authentication.ts index e39efc369a2..8b84b9f0dd8 100644 --- a/src/pincode/authentication.ts +++ b/src/pincode/authentication.ts @@ -5,8 +5,8 @@ * The password is a combination of the two. It is used for unlocking the account in the keychain */ +import * as Keychain from '@interaxyz/react-native-keychain' import crypto from 'crypto' -import * as Keychain from 'react-native-keychain' import { PincodeType } from 'src/account/reducer' import { pincodeTypeSelector } from 'src/account/selectors' import AppAnalytics from 'src/analytics/AppAnalytics' @@ -191,7 +191,6 @@ function storePinWithBiometry(pin: string) { options: { accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET, accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, - authenticationType: Keychain.AUTHENTICATION_TYPE.BIOMETRICS, securityLevel: Keychain.SECURITY_LEVEL.SECURE_SOFTWARE, }, }) diff --git a/src/storage/keychain.tsx b/src/storage/keychain.tsx index 57be5194730..d0de7fc261d 100644 --- a/src/storage/keychain.tsx +++ b/src/storage/keychain.tsx @@ -1,4 +1,4 @@ -import * as Keychain from 'react-native-keychain' +import * as Keychain from '@interaxyz/react-native-keychain' import Logger from 'src/utils/Logger' import { ensureError } from 'src/utils/ensureError' @@ -13,7 +13,7 @@ const KEYCHAIN_USER_CANCELLED_ERRORS = [ interface SecureStorage { key: string value: string - options?: Keychain.Options + options?: Keychain.SetOptions } export function isUserCancelledError(error: Error) { @@ -27,7 +27,6 @@ export async function storeItem({ key, value, options = {} }: SecureStorage) { const result = await Keychain.setGenericPassword('CELO', value, { service: key, accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, - rules: Keychain.SECURITY_RULES.NONE, ...options, }) if (result === false) { @@ -52,10 +51,11 @@ export async function storeItem({ key, value, options = {} }: SecureStorage) { } } -export async function retrieveStoredItem(key: string, options: Keychain.Options = {}) { +export async function retrieveStoredItem(key: string, options: Keychain.GetOptions = {}) { try { const item = await Keychain.getGenericPassword({ service: key, + rules: Keychain.SECURITY_RULES.NONE, ...options, }) if (!item) { @@ -85,7 +85,7 @@ export async function removeStoredItem(key: string) { export async function listStoredItems() { try { - return Keychain.getAllGenericPasswordServices() + return Keychain.getAllGenericPasswordServices({ skipUIAuth: true }) } catch (error) { Logger.error(TAG, 'Error listing items', error, true) throw error diff --git a/src/utils/accountChecker.test.ts b/src/utils/accountChecker.test.ts index b3df03ca8af..9871df89546 100644 --- a/src/utils/accountChecker.test.ts +++ b/src/utils/accountChecker.test.ts @@ -1,5 +1,5 @@ +import * as Keychain from '@interaxyz/react-native-keychain' import * as Sentry from '@sentry/react-native' -import * as Keychain from 'react-native-keychain' import AppAnalytics from 'src/analytics/AppAnalytics' import { resetStateOnInvalidStoredAccount } from 'src/utils/accountChecker' import { clearStoredAccounts } from 'src/web3/KeychainAccounts' @@ -48,7 +48,7 @@ describe('resetStateOnInvalidStoredAccount', () => { password: 'some hash', username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const state = getMockStoreData() expect(walletAddressSelector(state)).toEqual('0x0000000000000000000000000000000000007e57') diff --git a/src/verify/VerificationCodeInputScreen.test.tsx b/src/verify/VerificationCodeInputScreen.test.tsx index f75c7cd4f1d..76eca71f591 100644 --- a/src/verify/VerificationCodeInputScreen.test.tsx +++ b/src/verify/VerificationCodeInputScreen.test.tsx @@ -1,8 +1,8 @@ +import * as Keychain from '@interaxyz/react-native-keychain' import { act, fireEvent, render, waitFor, within } from '@testing-library/react-native' import { FetchMock } from 'jest-fetch-mock/types' import MockDate from 'mockdate' import React from 'react' -import * as Keychain from 'react-native-keychain' import SmsRetriever from 'react-native-sms-retriever' import { Provider } from 'react-redux' import { showError } from 'src/alert/actions' @@ -30,7 +30,7 @@ mockedKeychain.getGenericPassword.mockResolvedValue({ username: 'some username', password: 'someSignedMessage', service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, }) const mockedSmsRetriever = jest.mocked(SmsRetriever) diff --git a/src/verify/VerificationStartScreen.test.tsx b/src/verify/VerificationStartScreen.test.tsx index 2d7d30625c3..4e886b1141c 100644 --- a/src/verify/VerificationStartScreen.test.tsx +++ b/src/verify/VerificationStartScreen.test.tsx @@ -1,6 +1,6 @@ +import * as Keychain from '@interaxyz/react-native-keychain' import { fireEvent, render, waitFor, within } from '@testing-library/react-native' import React from 'react' -import * as Keychain from 'react-native-keychain' import { Provider } from 'react-redux' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' @@ -56,7 +56,7 @@ describe('VerificationStartScreen', () => { password: 'some signed message', username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const { getByText, getByTestId, queryByTestId, queryByText } = renderComponent() @@ -75,7 +75,7 @@ describe('VerificationStartScreen', () => { password: 'some signed message', username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const { getByText, getByTestId } = renderComponent({ hasOnboarded: false }) @@ -96,7 +96,7 @@ describe('VerificationStartScreen', () => { password: 'some signed message', username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const { getByText, getByTestId, queryByTestId } = renderComponent({ hasOnboarded: false }, true) @@ -152,7 +152,7 @@ describe('VerificationStartScreen', () => { password: 'some signed message', username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const { getByText, getByTestId } = renderComponent({ hasOnboarded: false }) @@ -175,7 +175,7 @@ describe('VerificationStartScreen', () => { password: 'some signed message', username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const { getByText, getByTestId } = renderComponent({ hasOnboarded: false }, true) @@ -198,7 +198,7 @@ describe('VerificationStartScreen', () => { password: 'some signed message', username: 'username', service: 'service', - storage: 'storage', + storage: Keychain.STORAGE_TYPE.RSA, }) const { getByText, getByTestId } = renderComponent({ hasOnboarded: true }, false) diff --git a/src/verify/hooks.test.tsx b/src/verify/hooks.test.tsx index fe49f30b448..130674c31ae 100644 --- a/src/verify/hooks.test.tsx +++ b/src/verify/hooks.test.tsx @@ -1,8 +1,8 @@ +import * as Keychain from '@interaxyz/react-native-keychain' import { act, fireEvent, render } from '@testing-library/react-native' import { FetchMock } from 'jest-fetch-mock/types' import React from 'react' import { Text } from 'react-native' -import * as Keychain from 'react-native-keychain' import { Provider } from 'react-redux' import { phoneNumberRevoked } from 'src/app/actions' import Touchable from 'src/components/Touchable' @@ -17,7 +17,7 @@ mockedKeychain.getGenericPassword.mockResolvedValue({ username: 'some username', password: 'someSignedMessage', service: 'some service', - storage: 'some string', + storage: Keychain.STORAGE_TYPE.RSA, }) function TestComponent() { diff --git a/test/mockedKeychain.ts b/test/mockedKeychain.ts index c35e7c3080c..768e62f8619 100644 --- a/test/mockedKeychain.ts +++ b/test/mockedKeychain.ts @@ -1,4 +1,4 @@ -import * as Keychain from 'react-native-keychain' +import * as Keychain from '@interaxyz/react-native-keychain' // This is exposed via __mocks__ // @ts-ignore diff --git a/yarn.lock b/yarn.lock index 31a894e601a..ab4359d0ddb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1666,6 +1666,11 @@ resolved "https://registry.yarnpkg.com/@interaxyz/react-navigation-bottom-sheet/-/react-navigation-bottom-sheet-0.3.2.tgz#e2ed37e5c407647434053d79fd4b7241fc8cab69" integrity sha512-8Q8A8GmqlMF4W0f+GL9+FBFRn2syNgL8ngJyA9V3uIQskAlr4bGe25iX+UB7ccksU8BpniRcNAD6gl0vq4CnBg== +"@interaxyz/react-native-keychain@^9.2.2": + version "9.2.2" + resolved "https://registry.yarnpkg.com/@interaxyz/react-native-keychain/-/react-native-keychain-9.2.2.tgz#4e32c162ac3fabe4d2b9eb10b2b4f79a480d19a6" + integrity sha512-Gd8PSr/H0AA/XgU8/Xo5uzJ27im6Nghl/K3vkvu54HBa07Bc4eBRNhr5g+JoMrji3z8eRXBRRFuMmslz9jGP2g== + "@interaxyz/react-native-webview@^13.13.4": version "13.13.4" resolved "https://registry.yarnpkg.com/@interaxyz/react-native-webview/-/react-native-webview-13.13.4.tgz#a0528e4515e305edd3395e286b19c335ec08a90d" @@ -12647,11 +12652,6 @@ react-native-in-app-review@^4.3.3: resolved "https://registry.yarnpkg.com/react-native-in-app-review/-/react-native-in-app-review-4.3.3.tgz#61f09f110de18f0a470a9bb55b9f49600390085f" integrity sha512-Q9sXBtK8tCBYFPCGmMgeMlkxXC5e6vAyPZK26OC1oOKUuKUd0QORnryk/qbwnuN4fLshHQN8UKlLgyHLGRuK3A== -react-native-keychain@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/react-native-keychain/-/react-native-keychain-8.2.0.tgz#aea82df37aacbb04f8b567a8e0e6d7292025610a" - integrity sha512-SkRtd9McIl1Ss2XSWNLorG+KMEbgeVqX+gV+t3u1EAAqT8q2/OpRmRbxpneT2vnb/dMhiU7g6K/pf3nxLUXRvA== - react-native-kill-packager@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/react-native-kill-packager/-/react-native-kill-packager-1.0.0.tgz#8d5dc706429805800298acabca45598d0d39b391"