Skip to content

Commit

Permalink
feat: add SES experiment toggle (iOS) (#8373)
Browse files Browse the repository at this point in the history
## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

A feature toggle for SES, within our settings menu under experiments,
enabled by default

TODO
- [x] add `react-native-mmkv`
- [x] MVP
- [x] ensure only visible on iOS not Android
  - show only on iOS
  - or show if storage key exists
- [x] check next to Blockaid experiment enabled
- [x] fix test, update snapshot
- [x] add descriptive content
- [x] translate text
- [x] update styling
- [x] <s>replace `react-native-mmkv` with
`react-native-default-preference`</s>
- attempted in
ea5674c
but only [partially
working](#8373 (comment))
- [x] fix Android debug bundling on Hermes
- [x] <s>consider content revision to include _Hardened JS_ and _SES
(Secure EcmaScript)_ terms</s>
- [x] update to newly discussed text with link
- [x] fix styling, move switch above next to title
- [x] display both SES and Blockaid under same _Security_ heading
- [x] preserve Android UI
- [x] update SES to be enabled by default

## **Related issues**

Fixes: partially mitigates rollout risk

Follow-up to
- #8033

## **Manual testing steps**

iOS
- boot app
- login / create wallet
- go to bottom tab Settings menu
- open Experimental menu
- _SES enabled by default, like currently in (main) branch_
- disable SES ft toggle
- reboot app
- _SES now disabled_
- verify in Experimental menu
- repeat steps above to re-enable

Android
- boot app
- login / create wallet
- go to bottom tab Settings menu
- open Experimental menu
- UI remains the same
  - Blockaid shown if feature is enabled

## **Screenshots/Recordings**

Previous MVP video (old UI)
[demo](https://consensys.slack.com/archives/C02U025CVU4/p1706035121992709?thread_ts=1705527596.738189&cid=C02U025CVU4)
showing the behaviour, a simple settings menu ft toggle that persists,
enabling/disabling lockdown upon app reboot, on iOS only

Android remains unchanged ([Blockaid
disabled](https://github.com/MetaMask/metamask-mobile/assets/1881059/d74a30be-e65e-4832-a21e-8aa1812df608),
[Blockaid
enabled](https://github.com/MetaMask/metamask-mobile/assets/1881059/77b9a24b-486b-4e6b-aa10-51eede8c2951))

### **Before**

Blockaid ft disabled

<img width="403" alt="Screenshot 2024-01-26 at 7 20 46 pm"
src="https://github.com/MetaMask/metamask-mobile/assets/1881059/ec120e0a-9ba5-454c-b4c8-21307ced7ea5">

Blockaid ft enabled

<img width="402" alt="Screenshot 2024-01-26 at 7 25 05 pm"
src="https://github.com/MetaMask/metamask-mobile/assets/1881059/4be5fda0-edfe-427f-8206-df6df100a6fc">

### **After**

Blockaid ft disabled

<img width="403" alt="Screenshot 2024-01-30 at 1 07 07 pm"
src="https://github.com/MetaMask/metamask-mobile/assets/1881059/bca71f83-ab01-4d70-bbc1-fac00dd76e23">

Blockaid ft enabled

<img width="401" alt="Screenshot 2024-01-30 at 1 07 48 pm"
src="https://github.com/MetaMask/metamask-mobile/assets/1881059/7d12aa9a-51e9-44d8-a6d0-6d9ca8aa9375">

Navigating to [Learn
more](https://github.com/endojs/endo/blob/master/packages/ses/README.md)

<img width="401" alt="Screenshot 2024-01-26 at 6 52 17 pm"
src="https://github.com/MetaMask/metamask-mobile/assets/1881059/a32d47b3-e95e-4a15-b745-3cbc7c444250">

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've clearly explained what problem this PR is solving and how it
is solved.
- [x] I've linked related issues
- [x] I've included manual testing steps
- [x] I've included screenshots/recordings if applicable
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
- [x] I’ve properly set the pull request status:
  - [x] In case it's not yet "ready for review", I've set it to "draft".
- [x] In case it's "ready for review", I've changed it from "draft" to
"non-draft".

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

---------

Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com>
Co-authored-by: sethkfman <seth.kaufman@consensys.net>
  • Loading branch information
3 people authored Jan 30, 2024
1 parent a3ea469 commit 6f84f18
Show file tree
Hide file tree
Showing 6 changed files with 366 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,113 @@ Array [
>
Security
</Text>
<View
style={
Object {
"marginVertical": 16,
}
}
>
<View
style={
Object {
"alignItems": "center",
"display": "flex",
"flexDirection": "row",
"justifyContent": "space-between",
}
}
>
<Text
accessibilityRole="text"
style={
Object {
"color": "#24272A",
"fontFamily": "Euclid Circular B",
"fontSize": 16,
"fontWeight": "500",
"letterSpacing": 0,
"lineHeight": 24,
}
}
>
Code Lockdown
</Text>
<RCTSwitch
accessibilityRole="switch"
onChange={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onTintColor="#0376C9"
style={
Array [
Object {
"height": 31,
"width": 51,
},
Array [
Object {
"alignSelf": "flex-end",
},
Object {
"backgroundColor": "#D6D9DC",
"borderRadius": 16,
},
],
]
}
tintColor="#D6D9DC"
value={false}
/>
</View>
<Text
accessibilityRole="text"
style={
Object {
"color": "#535A61",
"fontFamily": "Euclid Circular B",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
"marginTop": 8,
}
}
>
This is a test feature that blocks any changes to the app's JavaScript code without permission.
<Text
accessibilityRole="text"
onPress={[Function]}
onPressIn={[Function]}
onPressOut={[Function]}
style={
Object {
"backgroundColor": "transparent",
"color": "#24272A",
}
}
suppressHighlighting={true}
>
<Text
accessibilityRole="text"
style={
Object {
"color": "#0376C9",
"fontFamily": "Euclid Circular B",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
}
}
>
Learn more
</Text>
</Text>
.
</Text>
</View>
<View
style={
Object {
Expand Down Expand Up @@ -311,6 +418,113 @@ Array [
>
Security
</Text>
<View
style={
Object {
"marginVertical": 16,
}
}
>
<View
style={
Object {
"alignItems": "center",
"display": "flex",
"flexDirection": "row",
"justifyContent": "space-between",
}
}
>
<Text
accessibilityRole="text"
style={
Object {
"color": "#24272A",
"fontFamily": "Euclid Circular B",
"fontSize": 16,
"fontWeight": "500",
"letterSpacing": 0,
"lineHeight": 24,
}
}
>
Code Lockdown
</Text>
<RCTSwitch
accessibilityRole="switch"
onChange={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
onTintColor="#0376C9"
style={
Array [
Object {
"height": 31,
"width": 51,
},
Array [
Object {
"alignSelf": "flex-end",
},
Object {
"backgroundColor": "#D6D9DC",
"borderRadius": 16,
},
],
]
}
tintColor="#D6D9DC"
value={false}
/>
</View>
<Text
accessibilityRole="text"
style={
Object {
"color": "#535A61",
"fontFamily": "Euclid Circular B",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
"marginTop": 8,
}
}
>
This is a test feature that blocks any changes to the app's JavaScript code without permission.
<Text
accessibilityRole="text"
onPress={[Function]}
onPressIn={[Function]}
onPressOut={[Function]}
style={
Object {
"backgroundColor": "transparent",
"color": "#24272A",
}
}
suppressHighlighting={true}
>
<Text
accessibilityRole="text"
style={
Object {
"color": "#0376C9",
"fontFamily": "Euclid Circular B",
"fontSize": 14,
"fontWeight": "400",
"letterSpacing": 0,
"lineHeight": 22,
}
}
>
Learn more
</Text>
</Text>
.
</Text>
</View>
<View
style={
Object {
Expand Down
82 changes: 73 additions & 9 deletions app/components/Views/Settings/ExperimentalSettings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React, { FC, useCallback, useEffect } from 'react';
import { ScrollView, Switch, View } from 'react-native';
import React, { FC, useCallback, useEffect, useState } from 'react';
import { Linking, ScrollView, Switch, View } from 'react-native';

import { MMKV } from 'react-native-mmkv';
import { strings } from '../../../../../locales/i18n';
import Engine from '../../../../core/Engine';
import { colors as importedColors } from '../../../../styles/common';
import { useTheme } from '../../../../util/theme';
import Text, {
TextVariant,
Expand All @@ -24,6 +26,10 @@ import Button, {
ButtonSize,
ButtonWidthTypes,
} from '../../../../component-library/components/Buttons/Button';
import Device from '../../../../../app/util/device';
import { SES_URL } from '../../../../../app/constants/urls';

const storage = new MMKV(); // id: mmkv.default

/**
* Main view for app Experimental Settings
Expand All @@ -35,6 +41,15 @@ const ExperimentalSettings = ({ navigation, route }: Props) => {

const securityAlertsEnabled = useSelector(selectIsSecurityAlertsEnabled);

const [sesEnabled, setSesEnabled] = useState(
storage.getBoolean('is-ses-enabled'),
);

const toggleSesEnabled = () => {
storage.set('is-ses-enabled', !sesEnabled);
setSesEnabled(!sesEnabled);
};

const isFullScreenModal = route?.params?.isFullScreenModal;

const theme = useTheme();
Expand Down Expand Up @@ -81,6 +96,8 @@ const ExperimentalSettings = ({ navigation, route }: Props) => {
navigation.navigate('WalletConnectSessionsView');
}, [navigation]);

const openSesLink = () => Linking.openURL(SES_URL);

const WalletConnectSettings: FC = () => (
<>
<Text color={TextColor.Default} variant={TextVariant.BodyLGMedium}>
Expand All @@ -106,13 +123,15 @@ const ExperimentalSettings = ({ navigation, route }: Props) => {

const BlockaidSettings: FC = () => (
<>
<Text
color={TextColor.Default}
variant={TextVariant.HeadingLG}
style={styles.heading}
>
{strings('app_settings.security_heading')}
</Text>
{Device.isAndroid() && (
<Text
color={TextColor.Default}
variant={TextVariant.HeadingLG}
style={styles.heading}
>
{strings('app_settings.security_heading')}
</Text>
)}
<View style={styles.setting}>
<Text color={TextColor.Default} variant={TextVariant.BodyLGMedium}>
{strings('experimental_settings.security_alerts')}
Expand Down Expand Up @@ -153,9 +172,54 @@ const ExperimentalSettings = ({ navigation, route }: Props) => {
</>
);

const SesSettings: FC = () => (
<>
<Text
color={TextColor.Default}
variant={TextVariant.HeadingLG}
style={styles.heading}
>
{strings('app_settings.security_heading')}
</Text>
<View style={styles.setting}>
<View style={styles.switchElement}>
<Text color={TextColor.Default} variant={TextVariant.BodyLGMedium}>
{strings('app_settings.ses_heading')}
</Text>
<Switch
value={sesEnabled}
onValueChange={toggleSesEnabled}
trackColor={{
true: colors.primary.default,
false: colors.border.muted,
}}
thumbColor={importedColors.white}
style={styles.switch}
ios_backgroundColor={colors.border.muted}
/>
</View>
<Text
color={TextColor.Alternative}
variant={TextVariant.BodyMD}
style={styles.desc}
>
{strings('app_settings.ses_description')}{' '}
<Button
variant={ButtonVariants.Link}
size={ButtonSize.Auto}
onPress={openSesLink}
label={strings('app_settings.ses_link')}
/>
.
</Text>
</View>
</>
);

return (
<ScrollView style={styles.wrapper}>
<WalletConnectSettings />
{Device.isIos() && <SesSettings />}
{isBlockaidFeatureEnabled() && <BlockaidSettings />}
</ScrollView>
);
Expand Down
4 changes: 4 additions & 0 deletions app/constants/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export const CONNECTING_TO_A_DECEPTIVE_SITE =
// Policies
export const CONSENSYS_PRIVACY_POLICY = 'https://consensys.net/privacy-policy/';

// SES
export const SES_URL =
'https://github.com/endojs/endo/blob/master/packages/ses/README.md';

// Keystone
export const KEYSTONE_SUPPORT = 'https://keyst.one/mmm';
export const KEYSTONE_LEARN_MORE =
Expand Down
3 changes: 3 additions & 0 deletions locales/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,9 @@
"invalid_password": "Invalid password",
"invalid_password_message": "The password was not correct. Please try again.",
"security_heading": "Security",
"ses_heading": "Code Lockdown",
"ses_description": "This is a test feature that blocks any changes to the app's JavaScript code without permission.",
"ses_link": "Learn more",
"privacy_heading": "Privacy",
"failed_to_fetch_chain_id": "Could not fetch chain ID. Is your RPC URL correct?",
"endpoint_returned_different_chain_id": "The endpoint returned a different chain ID: %{chainIdReturned}",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
"@metamask/post-message-stream": "7.0.0",
"@metamask/ppom-validator": "0.22.0",
"@metamask/preferences-controller": "^4.0.0",
"@metamask/react-native-button": "^3.0.0",
"@metamask/scure-bip39": "^2.1.0",
"@metamask/sdk-communication-layer": "^0.12.0",
"@metamask/signature-controller": "4.0.1",
Expand Down Expand Up @@ -296,7 +297,6 @@
"react-native-blob-jsi-helper": "^0.3.1",
"react-native-branch": "^5.6.2",
"react-native-browser-polyfill": "0.1.2",
"@metamask/react-native-button": "^3.0.0",
"react-native-camera": "^3.36.0",
"react-native-confetti": "^0.1.0",
"react-native-confetti-cannon": "^1.5.0",
Expand Down
Loading

0 comments on commit 6f84f18

Please sign in to comment.