Skip to content

Commit

Permalink
chore(IT Wallet): [SIW-1945] Disable screenshots and recordings on IT…
Browse files Browse the repository at this point in the history
…W screens (#6595)

## Short description
This PR prevents screenshots and screen recordings in several IT Wallet
screens. In order to work on iOS, `react-native-flag-secure-android`
(currently used) has been changed with
`react-native-screenshot-prevent`.

The implementation is the following:
- On Android it leverages the `FLAG_SECURE` option;
- On iOS it creates a hidden secure text field, that renders the screen
blank.

## List of changes proposed in this pull request
- Removed `react-native-flag-secure-android`
- Installed `react-native-screenshot-prevent` 
- Added ITW routes to `screenBlackList`

## How to test
Ensure it is not possible to take screenshots or record the content of
the screen in the following:
- CIE pin screen during identification
- Trust issuer screen 
- Credential preview and detail (including trustmark)

Be sure to **disable debug mode**, because
`isAllowedSnapshotCurrentScreen` always returns true in debug.

> [!NOTE]
> iOS does not seem to offer a direct API to disable screenshots.
`react-native-screenshot-prevent` makes use of a workaround solution, so
please test it thoroughly on iOS.
  • Loading branch information
gispada authored Jan 15, 2025
1 parent ea95f85 commit 9382eeb
Show file tree
Hide file tree
Showing 23 changed files with 151 additions and 145 deletions.
2 changes: 1 addition & 1 deletion android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ rootProject.name = 'ItaliaApp'
include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin')
include ':react-native-cie'
project(':react-native-cie').projectDir = new File(rootProject.projectDir, '../node_modules/@pagopa/react-native-cie/android')
project(':react-native-cie').projectDir = new File(rootProject.projectDir, '../node_modules/@pagopa/react-native-cie/android')
6 changes: 6 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2022,6 +2022,8 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- RNScreenshotPrevent (1.2.1):
- React
- RNSentry (6.4.0):
- DoubleConversion
- glog
Expand Down Expand Up @@ -2199,6 +2201,7 @@ DEPENDENCIES:
- RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNScreenshotPrevent (from `../node_modules/react-native-screenshot-prevent`)
- "RNSentry (from `../node_modules/@sentry/react-native`)"
- RNShare (from `../node_modules/react-native-share`)
- RNStoreReview (from `../node_modules/react-native-store-review`)
Expand Down Expand Up @@ -2448,6 +2451,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-reanimated"
RNScreens:
:path: "../node_modules/react-native-screens"
RNScreenshotPrevent:
:path: "../node_modules/react-native-screenshot-prevent"
RNSentry:
:path: "../node_modules/@sentry/react-native"
RNShare:
Expand Down Expand Up @@ -2575,6 +2580,7 @@ SPEC CHECKSUMS:
RNReactNativeHapticFeedback: 00ba111b82aa266bb3ee1aa576831c2ea9a9dfad
RNReanimated: 26a5a401a5de1c0cf1a3226873825b00ffa85377
RNScreens: 35bb8e81aeccf111baa0ea01a54231390dbbcfd9
RNScreenshotPrevent: 5f8473abaa2db2476561ef8f3704b66491ce7b01
RNSentry: c5075bc124ebc8afa84e037c7fe257053a0b2cda
RNShare: 694e19d7f74ac4c04de3a8af0649e9ccc03bd8b1
RNStoreReview: 613c43e9132998ed41a65946e20c223c91b36464
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@
"react-native-easing-gradient": "^1.1.1",
"react-native-exception-handler": "^2.10.8",
"react-native-fingerprint-scanner": "git+https://github.com/hieuvp/react-native-fingerprint-scanner.git#9cecc0db326471c571553ea85f7c016fee2f803d",
"react-native-flag-secure-android": "^1.0.3",
"react-native-fs": "^2.18.0",
"react-native-gesture-handler": "^2.18.1",
"react-native-haptic-feedback": "^2.3.3",
Expand All @@ -142,6 +141,7 @@
"react-native-safe-area-context": "^4.10.5",
"react-native-screen-brightness": "^2.0.0-alpha",
"react-native-screens": "^3.35.0",
"react-native-screenshot-prevent": "^1.2.1",
"react-native-share": "^10.2.1",
"react-native-splash-screen": "^3.2.0",
"react-native-store-review": "^0.4.3",
Expand Down
2 changes: 2 additions & 0 deletions patches/patches.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ Created on **24/03/2022**

Created on **29/08/2022**

Removed on **10/01/2025** and replaced with `react-native-screenshot-prevent`

#### Reason:

- This patch is going to fix a gradle issue that breaks the compile on android platform, due to gradle imcompatibility
Expand Down
15 changes: 0 additions & 15 deletions patches/react-native-flag-secure-android+1.0.3.patch

This file was deleted.

4 changes: 0 additions & 4 deletions ts/@types/react-native-flag-secure-android.d.ts

This file was deleted.

3 changes: 0 additions & 3 deletions ts/RootContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ import {
AppState,
AppStateStatus,
NativeEventSubscription,
Platform,
StatusBar
} from "react-native";
import SplashScreen from "react-native-splash-screen";
import { connect } from "react-redux";
import configurePushNotifications from "./features/pushNotifications/utils/configurePushNotification";
import DebugInfoOverlay from "./components/DebugInfoOverlay";
import FlagSecureComponent from "./components/FlagSecure";
import PagoPATestIndicatorOverlay from "./components/PagoPATestIndicatorOverlay";
import { LightModalRoot } from "./components/ui/LightModal";
import { setLocale } from "./i18n";
Expand Down Expand Up @@ -101,7 +99,6 @@ class RootContainer extends React.PureComponent<Props> {
barStyle={"dark-content"}
backgroundColor={customVariables.androidStatusBarColor}
/>
{Platform.OS === "android" && <FlagSecureComponent />}

<IONavigationContainer
routingInstrumentation={this.props.routingInstumentation}
Expand Down
32 changes: 0 additions & 32 deletions ts/components/FlagSecure.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import I18n from "../../../../../i18n";
import { useIOSelector } from "../../../../../store/hooks";
import { setAccessibilityFocus } from "../../../../../utils/accessibility";
import { useIOBottomSheetAutoresizableModal } from "../../../../../utils/hooks/bottomSheet";
import { usePreventScreenCapture } from "../../../../../utils/hooks/usePreventScreenCapture";
import { withTrailingPoliceCarLightEmojii } from "../../../../../utils/strings";
import { openWebUrl } from "../../../../../utils/url";
import {
Expand Down Expand Up @@ -61,6 +62,8 @@ const ForgottenPin = () => (
);

export const ItwCiePinScreen = () => {
usePreventScreenCapture();

const useCieUat = useIOSelector(isCieLoginUatEnabledSelector);
const machineRef = ItwEidIssuanceMachineContext.useActorRef();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
selectCredentialOption,
selectCredentialTypeOption
} from "../../machine/credential/selectors";
import { usePreventScreenCapture } from "../../../../utils/hooks/usePreventScreenCapture";
import { ItwCredentialIssuanceMachineContext } from "../../machine/provider";
import { ItwCredentialPreviewClaimsList } from "../components/ItwCredentialPreviewClaimsList";
import { ITW_ROUTES } from "../../navigation/routes";
Expand All @@ -45,6 +46,7 @@ export const ItwIssuanceCredentialPreviewScreen = () => {
selectCredentialOption
);

usePreventScreenCapture();
useItwDisableGestureNavigation();
useAvoidHardwareBackButton();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
trackWalletDataShareAccepted
} from "../../analytics";
import LoadingScreenContent from "../../../../components/screens/LoadingScreenContent";
import { usePreventScreenCapture } from "../../../../utils/hooks/usePreventScreenCapture";
import { itwIpzsPrivacyUrl } from "../../../../config";
import { ITW_ROUTES } from "../../navigation/routes";

Expand All @@ -68,6 +69,7 @@ const ItwIssuanceCredentialTrustIssuerScreen = () => {
selectCredentialTypeOption
);

usePreventScreenCapture();
useItwDisableGestureNavigation();
useAvoidHardwareBackButton();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import { ItwCredentialIssuanceMachineContext } from "../../../machine/provider";
import { ITW_ROUTES } from "../../../navigation/routes";
import { ItwIssuanceCredentialTrustIssuerScreen } from "../ItwIssuanceCredentialTrustIssuerScreen";

jest.mock("../../../../../utils/hooks/usePreventScreenCapture", () => ({
usePreventScreenCapture: jest.fn()
}));

describe("ItwIssuanceCredentialTrustIssuerScreen", () => {
it("it should render the screen correctly", () => {
const component = renderComponent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { ParsedCredential } from "../../common/utils/itwTypesUtils";
import { ItwParamsList } from "../../navigation/ItwParamsList";
import { trackWalletCredentialFAC_SIMILE } from "../../analytics";
import { usePreventScreenCapture } from "../../../../utils/hooks/usePreventScreenCapture";

// We currently only support PDF files, extend this if needed
type SupportedAttachmentType = "application/pdf";
Expand Down Expand Up @@ -49,6 +50,7 @@ export const ItwPresentationCredentialAttachmentScreen = ({
safeBottomAreaHeight: 0
});

usePreventScreenCapture();
useFocusEffect(trackWalletCredentialFAC_SIMILE);

useHeaderSecondLevel({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from "../../common/utils/itwTypesUtils";
import { ItwParamsList } from "../../navigation/ItwParamsList";
import { ItwPresentationCredentialCardFlipButton } from "../components/ItwPresentationCredentialCardFlipButton";
import { usePreventScreenCapture } from "../../../../utils/hooks/usePreventScreenCapture";

export type ItwPresentationCredentialCardModalNavigationParams = {
credential: StoredCredential;
Expand All @@ -41,6 +42,7 @@ const ItwPresentationCredentialCardModal = ({ route, navigation }: Props) => {
const [isFlipped, setFlipped] = React.useState(false);
const theme = useIOTheme();

usePreventScreenCapture();
useMaxBrightness({ useSmoothTransition: true });

React.useLayoutEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
import { ItwCredentialTrustmark } from "../../trustmark/components/ItwCredentialTrustmark";
import ItwCredentialNotFound from "../../common/components/ItwCredentialNotFound";
import { ItwPresentationCredentialUnknownStatus } from "../components/ItwPresentationCredentialUnknownStatus";
import { usePreventScreenCapture } from "../../../../utils/hooks/usePreventScreenCapture";

export type ItwPresentationCredentialDetailNavigationParams = {
credentialType: string;
Expand Down Expand Up @@ -81,6 +82,7 @@ const ItwPresentationCredentialDetail = ({
);

useDebugInfo(credential);
usePreventScreenCapture();

useFocusEffect(() => {
trackCredentialDetail({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
selectFiscalCodeFromEid,
selectNameSurnameFromEid
} from "../../credentials/store/selectors";
import { usePreventScreenCapture } from "../../../../utils/hooks/usePreventScreenCapture";

/**
* This magic number is the lenght of the encoded fiscal code in a CODE39 barcode.
Expand Down Expand Up @@ -72,6 +73,7 @@ const ItwPresentationCredentialFiscalCodeModal = () => {
const nameSurname = useIOSelector(selectNameSurnameFromEid);
const fiscalCode = useIOSelector(selectFiscalCodeFromEid);

usePreventScreenCapture();
useMaxBrightness({ useSmoothTransition: true });

React.useLayoutEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ItwParamsList } from "../../navigation/ItwParamsList";
import { ItwTrustmarkExpirationTimer } from "../components/ItwTrustmarkExpirationTimer";
import { ItwTrustmarkQrCode } from "../components/ItwTrustmarkQrCode";
import { ItwTrustmarkMachineProvider } from "../machine/provider";
import { usePreventScreenCapture } from "../../../../utils/hooks/usePreventScreenCapture";

export type ItwCredentialTrustmarkScreenNavigationParams = {
credentialType: string;
Expand All @@ -22,6 +23,7 @@ type ScreenProps = IOStackNavigationRouteProps<
export const ItwCredentialTrustmarkScreen = (params: ScreenProps) => {
const { credentialType } = params.route.params;

usePreventScreenCapture();
useMaxBrightness({ useSmoothTransition: true });

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import { PaymentsOnboardingRoutes } from "../navigation/routes";
import { paymentsOnboardingGetMethodsAction } from "../store/actions";
import { selectPaymentOnboardingMethods } from "../store/selectors";
import { IOScrollViewWithLargeHeader } from "../../../../components/ui/IOScrollViewWithLargeHeader";
import { usePreventScreenCapture } from "../../../../utils/hooks/usePreventScreenCapture";

const PaymentsOnboardingSelectMethodScreen = () => {
usePreventScreenCapture();

const navigation = useIONavigation();
const dispatch = useIODispatch();

Expand Down
63 changes: 0 additions & 63 deletions ts/store/reducers/__tests__/allowedSnapshotScreens.test.ts

This file was deleted.

18 changes: 0 additions & 18 deletions ts/store/reducers/allowedSnapshotScreens.ts

This file was deleted.

Loading

0 comments on commit 9382eeb

Please sign in to comment.