Skip to content

Commit

Permalink
US-2039 [Security] Prevent user from taking screenshot of the mnemonic (
Browse files Browse the repository at this point in the history
#828)

* feat: prevent screenshoting of menmonic

* test: mock react-native-screenshot-prevent
  • Loading branch information
TravellerOnTheRun authored Dec 6, 2023
1 parent 3347032 commit 30edeb2
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 6 deletions.
8 changes: 7 additions & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ PODS:
- RNScreens (3.18.2):
- React-Core
- React-RCTImage
- RNScreenshotPrevent (1.1.9):
- React
- RNSVG (12.4.4):
- React-Core
- RNVectorIcons (9.2.0):
Expand Down Expand Up @@ -599,6 +601,7 @@ DEPENDENCIES:
- RNQrGenerator (from `../node_modules/rn-qr-generator`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNScreenshotPrevent (from `../node_modules/react-native-screenshot-prevent`)
- RNSVG (from `../node_modules/react-native-svg`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- vision-camera-code-scanner (from `../node_modules/vision-camera-code-scanner`)
Expand Down Expand Up @@ -746,6 +749,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-reanimated"
RNScreens:
:path: "../node_modules/react-native-screens"
RNScreenshotPrevent:
:path: "../node_modules/react-native-screenshot-prevent"
RNSVG:
:path: "../node_modules/react-native-svg"
RNVectorIcons:
Expand Down Expand Up @@ -838,6 +843,7 @@ SPEC CHECKSUMS:
RNQrGenerator: 90461ba3ca88c1d38ef73da50fade35d9648215d
RNReanimated: bec7736122a268883bdede07f1bf9cf4b40158db
RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d
RNScreenshotPrevent: cdfbe213203774c7486c6a2f198af8a4ebe10c47
RNSVG: ecd661f380a07ba690c9c5929c475a44f432d674
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Expand All @@ -850,4 +856,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 078a56513c6ebe1366f300f18d66914e074eca6f

COCOAPODS: 1.13.0
COCOAPODS: 1.12.0
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"react-native-reanimated-carousel": "^3.3.0",
"react-native-safe-area-context": "^4.4.1",
"react-native-screens": "^3.18.2",
"react-native-screenshot-prevent": "^1.1.9",
"react-native-snap-carousel": "^3.9.1",
"react-native-ssl-public-key-pinning": "^1.1.3",
"react-native-svg": "^12.1.1",
Expand Down
3 changes: 3 additions & 0 deletions src/lib/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ const resources = {
ramp_error_title: 'Not Available',
ramp_error: 'Adding funds is not available yet.',
wallet_deployment_label: 'Rif Wallet Deployment',
wallet_backup_title: 'Warning!',
wallet_backup_message:
'We have disabled the ability to take a picture of the mnemonic because it is important that you keep it private. Please write it down instead',
},
},
es: {
Expand Down
3 changes: 2 additions & 1 deletion src/screens/createKeys/new/NewMasterKeyScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
RootTabsScreenProps,
} from 'navigation/rootNavigator'
import { sharedColors, sharedStyles } from 'shared/constants'
import { castStyle } from 'shared/utils'
import { castStyle, usePreventScreenshot } from 'shared/utils'
import { useAppDispatch } from 'store/storeUtils'
import { createWallet } from 'store/slices/settingsSlice'
import { saveKeyVerificationReminder } from 'storage/MainStorage'
Expand All @@ -39,6 +39,7 @@ export const NewMasterKeyScreen = ({ navigation }: Props) => {
const initializeWallet = useInitializeWallet()
const dispatch = useAppDispatch()
const { t } = useTranslation()
usePreventScreenshot(t)
const mnemonic = useMemo(() => KeyManagementSystem.create().mnemonic, [])
const mnemonicArray = mnemonic ? mnemonic.split(' ') : []
const [isMnemonicVisible, setIsMnemonicVisible] = useState(false)
Expand Down
5 changes: 3 additions & 2 deletions src/screens/settings/WalletBackup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ import {
SettingsScreenProps,
settingsStackRouteNames,
} from 'navigation/settingsNavigator/types'
import { castStyle } from 'shared/utils'
import { castStyle, usePreventScreenshot } from 'shared/utils'
import { getKeys } from 'storage/SecureStorage'
import { DeleteWalletModal } from 'components/modal/deleteWalletModal'
import { getCurrentChainId } from 'src/storage/ChainStorage'
import { getCurrentChainId } from 'storage/ChainStorage'

type Props = SettingsScreenProps<settingsStackRouteNames.WalletBackup>

export const WalletBackup = (_: Props) => {
const { t } = useTranslation()
usePreventScreenshot(t)
const [isDeleteConfirmationVisible, setIsDeleteConfirmationVisible] =
useState<boolean>(false)

Expand Down
52 changes: 50 additions & 2 deletions src/shared/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import { createRef } from 'react'
import { ImageStyle, TextInput, TextStyle, ViewStyle } from 'react-native'
import { createRef, useEffect } from 'react'
import {
Alert,
ImageStyle,
TextInput,
TextStyle,
ViewStyle,
} from 'react-native'
import {
addListener,
enabled,
enableSecureView,
disableSecureView,
} from 'react-native-screenshot-prevent'
import { useTranslation } from 'react-i18next'
import { useIsFocused } from '@react-navigation/native'

import { ErrorWithMessage } from '../types'

Expand Down Expand Up @@ -35,3 +49,37 @@ export const getRandomNumber = (max: number, min: number) => {
max = Math.floor(max)
return Math.floor(Math.random() * (max - min + 1)) + min
}

export const usePreventScreenshot = (
t: ReturnType<typeof useTranslation>['t'],
) => {
const isFocused = useIsFocused()

useEffect(() => {
const subs = addListener(() => {
Alert.alert(t('wallet_backup_title'), t('wallet_backup_message'), [
{ text: t('ok') },
])
})

console.log('CREATE SUBS', subs)

return () => {
subs.remove()
}
}, [t])

useEffect(() => {
if (isFocused) {
console.log('ENABLE')
enabled(true)
enableSecureView()
return
}

console.log('DISABLE')

enabled(false)
disableSecureView()
}, [isFocused])
}
7 changes: 7 additions & 0 deletions testLib/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ jest.mock('redux-persist', () => ({
jest.mock('react-native-bootsplash', () => ({
hide: jest.fn(),
}))

jest.mock('react-native-screenshot-prevent', () => ({
addListener: jest.fn(),
enabled: jest.fn(),
enableSecureView: jest.fn(),
disableSecureView: jest.fn(),
}))
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9464,6 +9464,11 @@ react-native-screens@^3.18.2:
react-freeze "^1.0.0"
warn-once "^0.1.0"

react-native-screenshot-prevent@^1.1.9:
version "1.1.9"
resolved "https://registry.yarnpkg.com/react-native-screenshot-prevent/-/react-native-screenshot-prevent-1.1.9.tgz#937f41cd685c12c1e0ef20c8020a93600790cc92"
integrity sha512-VGhW3MkuHw3fK9nJD4ijC8truQXv0pSDj9x+mmoA5xTNIeuSoFSfFhXZG+WFcFknK54iIniFLMoGToKuKXkB3g==

react-native-snap-carousel@^3.9.1:
version "3.9.1"
resolved "https://registry.yarnpkg.com/react-native-snap-carousel/-/react-native-snap-carousel-3.9.1.tgz#6fd9bd8839546c2c6043a41d2035afbc6fe0443e"
Expand Down

0 comments on commit 30edeb2

Please sign in to comment.