Skip to content

Commit 39c5772

Browse files
renanvalentinDominikGuzei
authored andcommitted
[DDW-814] Discreet mode - hide sensitive information (#2742)
* [DDW-814] Fix React Dev Tools installation * [DDW-814] Hide sensitive values * [DDW-814] Setup storybook * [DDW-814] Localstorage factory * [DDW-814] Hide token amount for decimal config * [DDW-814] Refactor discreet mode ui components * [DDW-814] Directly use discreet mode feature in toggle * [DDW-814] Introduce configurable replacer pattern * [DDW-814] Create LocalStorageFeatureProvider * [DDW-814] Fix flow * [DDW-814] Fix topbar * [DDW-814] React to state changes on WalletUTXO description * [DDW-814] Preseve Stake pools ranking slider value * [DDW-814] Hide filter input * [DDW-814] Prevent stake pools from refreshing * [DDW-814] Update README * [DDW-814] Hide wallets dropdown in discreet mode * [DDW-814] Disable All transactions button on Filter dialog * [DDW-814] Rename DiscreetToggle component * [DDW-814] Add unit tests for discreet replacers * [DDW-814] Cleanup minor issues * [DDW-814] Fix prettier * [DDW-814] Revert istanbul * [DDW-814] Fix flow errors * [DDW-814] Add discreet toggle mode knob Co-authored-by: Dominik Guzei <[email protected]>
1 parent c1a32b4 commit 39c5772

File tree

77 files changed

+1167
-665
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+1167
-665
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
### Features
2727

28-
- Implemented "discreet mode" ([PR 2723](https://github.com/input-output-hk/daedalus/pull/2723), [PR 2724](https://github.com/input-output-hk/daedalus/pull/2724), [PR 2725](https://github.com/input-output-hk/daedalus/pull/2725))
28+
- Implemented "discreet mode" ([PR 2723](https://github.com/input-output-hk/daedalus/pull/2723), [PR 2724](https://github.com/input-output-hk/daedalus/pull/2724), [PR 2725](https://github.com/input-output-hk/daedalus/pull/2725), [PR 2742](https://github.com/input-output-hk/daedalus/pull/2742))
2929
- Implemented "Catalyst Fund7" voting registration changes ([PR 2732](https://github.com/input-output-hk/daedalus/pull/2732))
3030
- Added "Over-saturation" warning in the delegation wizard ([PR 2733](https://github.com/input-output-hk/daedalus/pull/2733), [PR 2738](https://github.com/input-output-hk/daedalus/pull/2738))
3131
- Added Catalyst footer links ([PR 2721](https://github.com/input-output-hk/daedalus/pull/2721))

jest.config.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ module.exports = {
8585
// ],
8686

8787
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
88-
// moduleNameMapper: {},
88+
moduleNameMapper: {
89+
// Jest does not support WASM imports from ESM modules
90+
// https://github.com/facebook/jest/issues/9430
91+
'^@iohk-jormungandr/wallet-js$': 'identity-obj-proxy',
92+
},
8993

9094
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
9195
// modulePathIgnorePatterns: [],
@@ -121,7 +125,7 @@ module.exports = {
121125
// rootDir: undefined,
122126

123127
// A list of paths to directories that Jest should use to search for files in
124-
roots: ['<rootDir>/tests'],
128+
roots: ['<rootDir>/tests', '<rootDir>/source'],
125129

126130
// Allows you to use a custom runner instead of Jest's default test runner
127131
// runner: "jest-runner",

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"start:dev": "NODE_ENV=development gulp start",
1313
"dev": "IS_WATCH_MODE=true gulp dev",
1414
"test": "NODE_ENV=test yarn build && yarn test:unit && yarn test:e2e:fail-fast",
15-
"test:jest": "jest",
15+
"test:jest": "NODE_OPTIONS=--experimental-vm-modules jest",
1616
"test:generate:report": "node tests/reporter.js",
1717
"test:unit": "yarn cucumber:run --require 'tests/**/unit/**/*.js' --tags '@unit and not @skip and not @wip'",
1818
"test:unit:rerun": "yarn cucumber:rerun --require 'tests/**/unit/**/*.js' --tags '@unit and not @skip and not @wip'",
@@ -132,6 +132,7 @@
132132
"husky": "4.3.0",
133133
"jest": "26.6.3",
134134
"jest-environment-jsdom": "26.6.2",
135+
"identity-obj-proxy": "3.0.0",
135136
"markdown-loader": "5.1.0",
136137
"mini-css-extract-plugin": "0.9.0",
137138
"minimist": "1.2.5",
Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
// @flow
22
export const installChromeExtensions = async (isDev: boolean) => {
33
if (isDev) {
4-
const installer = require('electron-devtools-installer'); // eslint-disable-line global-require
4+
const {
5+
default: installExtension,
6+
REACT_DEVELOPER_TOOLS,
7+
} = require('electron-devtools-installer'); // eslint-disable-line global-require
8+
const { app } = require('electron');
59

6-
const extensions = ['REACT_DEVELOPER_TOOLS'];
7-
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
8-
for (const name of extensions) {
9-
try {
10-
await installer.default(installer[name], forceDownload);
11-
} catch (e) {} // eslint-disable-line
12-
}
10+
const extensions = [REACT_DEVELOPER_TOOLS];
11+
const options = {
12+
loadExtensionOptions: { allowFileAccess: true },
13+
};
14+
15+
try {
16+
await app.whenReady();
17+
await installExtension(extensions, options);
18+
} catch (e) {} // eslint-disable-line
1319
}
1420
};
Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// @flow
2-
import React, { Component } from 'react';
2+
import React from 'react';
33
import BigNumber from 'bignumber.js';
44
import classnames from 'classnames';
55
import { PopOver } from 'react-polymorph/lib/components/PopOver';
6-
import { defineMessages, intlShape, FormattedHTMLMessage } from 'react-intl';
6+
import { defineMessages, FormattedHTMLMessage } from 'react-intl';
77
import { observer } from 'mobx-react';
8+
import { discreetWalletTokenAmount } from '../../features/discreet-mode/replacers/discreetWalletTokenAmount';
89
import styles from './AssetAmount.scss';
9-
import { formattedTokenWalletAmount } from '../../utils/formatters';
1010
import type { AssetMetadata } from '../../api/assets/types';
11+
import { useDiscreetModeFeature } from '../../features/discreet-mode';
1112

1213
const messages = defineMessages({
1314
unformattedAmount: {
@@ -26,47 +27,57 @@ type Props = {
2627
isShort?: boolean,
2728
};
2829

29-
@observer
30-
export default class AssetAmount extends Component<Props> {
31-
static contextTypes = {
32-
intl: intlShape.isRequired,
33-
};
30+
function AssetAmount({
31+
amount,
32+
metadata,
33+
decimals,
34+
isLoading,
35+
className,
36+
isShort,
37+
}: Props) {
38+
const discreetModeFeature = useDiscreetModeFeature();
3439

35-
render() {
36-
const {
37-
amount,
38-
metadata,
39-
decimals,
40-
isLoading,
41-
className,
42-
isShort,
43-
} = this.props;
44-
if (isLoading) return '-';
45-
const componentStyles = classnames([styles.component, className]);
46-
const content = !isLoading
47-
? formattedTokenWalletAmount(amount, metadata, decimals, isShort)
48-
: '-';
49-
return (
50-
<div className={componentStyles}>
51-
{decimals ? (
52-
<PopOver
53-
content={
54-
<FormattedHTMLMessage
55-
{...messages.unformattedAmount}
56-
values={{
57-
amount: formattedTokenWalletAmount(amount, null, 0),
58-
}}
59-
/>
60-
}
61-
visible={decimals ? undefined : false}
62-
className={styles.unformattedAmount}
63-
>
64-
{content}
65-
</PopOver>
66-
) : (
67-
<span>{content}</span>
68-
)}
69-
</div>
70-
);
71-
}
40+
if (isLoading) return '-';
41+
const componentStyles = classnames([styles.component, className]);
42+
const content = !isLoading
43+
? discreetModeFeature.discreetValue({
44+
replacer: discreetWalletTokenAmount({
45+
amount,
46+
metadata,
47+
decimals,
48+
isShort,
49+
}),
50+
})
51+
: '-';
52+
53+
return (
54+
<div className={componentStyles}>
55+
{decimals ? (
56+
<PopOver
57+
content={
58+
<FormattedHTMLMessage
59+
{...messages.unformattedAmount}
60+
values={{
61+
amount: discreetModeFeature.discreetValue({
62+
replacer: discreetWalletTokenAmount({
63+
amount,
64+
metadata: null,
65+
decimals: 0,
66+
}),
67+
}),
68+
}}
69+
/>
70+
}
71+
visible={decimals ? undefined : false}
72+
className={styles.unformattedAmount}
73+
>
74+
{content}
75+
</PopOver>
76+
) : (
77+
<span>{content}</span>
78+
)}
79+
</div>
80+
);
7281
}
82+
83+
export default observer(AssetAmount);

source/renderer/app/components/assets/AssetContent.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
line-height: 1.33;
2020
text-align: right;
2121
white-space: nowrap;
22-
width: 120px;
22+
width: 70px;
2323
}
2424

2525
dd {

source/renderer/app/components/assets/AssetSettingsDialog.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ import Dialog from '../widgets/Dialog';
1212
import styles from './AssetSettingsDialog.scss';
1313
import globalMessages from '../../i18n/global-messages';
1414
import type { AssetToken } from '../../api/assets/types';
15-
import { formattedTokenWalletAmount } from '../../utils/formatters';
1615
import warningIcon from '../../assets/images/asset-token-warning-ic.inline.svg';
1716
import {
1817
DEFAULT_DECIMAL_PRECISION,
1918
MAX_DECIMAL_PRECISION,
2019
} from '../../config/assetsConfig';
20+
import { DiscreetTokenWalletAmount } from '../../features/discreet-mode';
2121

2222
const messages = defineMessages({
2323
title: {
@@ -180,16 +180,22 @@ export default class AssetSettingsDialog extends Component<Props, State> {
180180
<div className={styles.label}>
181181
{intl.formatMessage(messages.unformattedBalanceLabel)}
182182
</div>
183-
<p>{formattedTokenWalletAmount(asset.quantity, null, 0)}</p>
183+
<p>
184+
<DiscreetTokenWalletAmount
185+
amount={asset.quantity}
186+
metadata={null}
187+
decimals={0}
188+
/>
189+
</p>
184190
<div className={styles.label}>
185191
{intl.formatMessage(messages.formattedBalanceLabel)}
186192
</div>
187193
<p>
188-
{formattedTokenWalletAmount(
189-
asset.quantity,
190-
asset.metadata,
191-
decimals
192-
)}
194+
<DiscreetTokenWalletAmount
195+
amount={asset.quantity}
196+
metadata={asset.metadata}
197+
decimals={decimals}
198+
/>
193199
</p>
194200
<Select
195201
options={options}

source/renderer/app/components/layout/TopBar.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import LegacyBadge, { LEGACY_BADGE_MODES } from '../notifications/LegacyBadge';
99
import LegacyNotification from '../notifications/LegacyNotification';
1010
import Wallet from '../../domains/Wallet';
1111
import styles from './TopBar.scss';
12-
import { formattedWalletAmount } from '../../utils/formatters';
1312
import headerLogo from '../../assets/images/header-logo.inline.svg';
13+
import { DiscreetWalletAmount } from '../../features/discreet-mode';
1414

1515
type Props = {
1616
onLeftIconClick?: ?Function,
@@ -69,7 +69,11 @@ export default class TopBar extends Component<Props> {
6969
<span className={styles.walletAmount}>
7070
{
7171
// show currency and use long format
72-
isRestoreActive ? '-' : formattedWalletAmount(activeWallet.amount)
72+
isRestoreActive ? (
73+
'-'
74+
) : (
75+
<DiscreetWalletAmount amount={activeWallet.amount} />
76+
)
7377
}
7478
</span>
7579
</span>

source/renderer/app/components/sidebar/wallets/SidebarWalletMenuItem.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import ProgressBar from '../../widgets/ProgressBar';
1010
import styles from './SidebarWalletMenuItem.scss';
1111
import { isHardwareWalletIndicatorEnabled } from '../../../config/hardwareWalletsConfig';
1212
import hardwareWalletsIcon from '../../../assets/images/hardware-wallet/connect-ic.inline.svg';
13+
import { DiscreetWalletAmount } from '../../../features/discreet-mode';
1314

1415
type Props = {
1516
title: string,
16-
info: string,
17+
amount: number,
1718
active: boolean,
1819
className: string,
1920
onClick: Function,
@@ -32,7 +33,7 @@ export default class SidebarWalletMenuItem extends Component<Props> {
3233
render() {
3334
const {
3435
title,
35-
info,
36+
amount,
3637
active,
3738
className,
3839
onClick,
@@ -77,7 +78,13 @@ export default class SidebarWalletMenuItem extends Component<Props> {
7778
</div>
7879
)}
7980
</div>
80-
<div className={styles.info}>{isRestoreActive ? '-' : info}</div>
81+
<div className={styles.info}>
82+
{isRestoreActive ? (
83+
'-'
84+
) : (
85+
<DiscreetWalletAmount amount={amount} withCurrency long={false} />
86+
)}
87+
</div>
8188
{isRestoreActive ? <ProgressBar progress={restoreProgress} /> : null}
8289
{showLegacyBadge && (
8390
<LegacyBadge mode={LEGACY_BADGE_MODES.FLOATING} />

source/renderer/app/components/sidebar/wallets/SidebarWalletsMenu.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default class SidebarWalletsMenu extends Component<Props> {
6767
{map(wallets, (wallet) => (
6868
<SidebarWalletMenuItem
6969
title={wallet.title}
70-
info={wallet.info}
70+
amount={wallet.amount}
7171
active={isActiveWallet(wallet.id)}
7272
onClick={() => onWalletItemClick(wallet.id)}
7373
key={wallet.id}

0 commit comments

Comments
 (0)