diff --git a/README.md b/README.md
index 8e26c20..31fd851 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ We use the yarn package manager instead of the default `npm`. There are multiple
```bash
npm install -g yarn
yarn global add babel-cli
-yarn install
+yarn install --frozen-lockfile
yarn run build
```
To run condenser in production mode, run:
diff --git a/src/app/components/App.scss b/src/app/components/App.scss
index b54392e..ddf2f5c 100644
--- a/src/app/components/App.scss
+++ b/src/app/components/App.scss
@@ -1,3 +1,5 @@
+@import "./cards/TransferHistoryRow";
+
.App {
min-height: 100vh;
padding-top: 50px;
diff --git a/src/app/components/cards/TransferHistoryRow.jsx b/src/app/components/cards/TransferHistoryRow.jsx
index 705db0f..93ede5e 100644
--- a/src/app/components/cards/TransferHistoryRow.jsx
+++ b/src/app/components/cards/TransferHistoryRow.jsx
@@ -1,11 +1,12 @@
import React from 'react';
import {connect} from 'react-redux'
import {Link} from 'react-router';
+import tt from 'counterpart';
import TimeAgoWrapper from '../elements/TimeAgoWrapper';
// import Icon from '../elements/Icon';
import Memo from '../elements/Memo'
import {numberWithCommas, vestsToSp} from '../../utils/StateFunctions'
-import tt from 'counterpart';
+import BadActorList from '../../utils/BadActorList';
class TransferHistoryRow extends React.Component {
render() {
@@ -110,7 +111,13 @@ class TransferHistoryRow extends React.Component {
{description_end}
-
+ -1
+ }
+ />
|
);
diff --git a/src/app/components/cards/TransferHistoryRow.scss b/src/app/components/cards/TransferHistoryRow.scss
new file mode 100644
index 0000000..eb3ee8b
--- /dev/null
+++ b/src/app/components/cards/TransferHistoryRow.scss
@@ -0,0 +1,19 @@
+.Memo--badActor {
+ .bad-actor-caution {
+ color: darken($color-red, 20%);
+ font-size: 75%;
+ font-weight: bold;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ }
+ .bad-actor-explained {
+ opacity: .5;
+ font-size: 75%;
+ max-width: 30em;
+ }
+ .bad-actor-reveal-memo {
+ opacity: .5;
+ font-size: 75%;
+ text-decoration: underline;
+ }
+}
diff --git a/src/app/components/elements/Memo.js b/src/app/components/elements/Memo.js
index 558f4ac..e6baa94 100644
--- a/src/app/components/elements/Memo.js
+++ b/src/app/components/elements/Memo.js
@@ -3,40 +3,84 @@ import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import shouldComponentUpdate from '../../utils/shouldComponentUpdate';
import tt from 'counterpart';
+import classnames from 'classnames';
import {memo} from '@smokenetwork/smoke-js';
class Memo extends React.Component {
static propTypes = {
text: PropTypes.string,
// username: PropTypes.string,
- memo_private: PropTypes.object,
+ username: PropTypes.string,
+ isFromBadActor: PropTypes.bool.isRequired,
// redux props
myAccount: PropTypes.bool,
+ memo_private: PropTypes.object,
}
constructor() {
super()
this.shouldComponentUpdate = shouldComponentUpdate(this, 'Memo');
- this.decodeMemo = (memo_private, text) => {
- try {
- return memo.decode(memo_private, text)
- } catch (e) {
- // if(/Invalid key/i.test(e.toString())) {
+ this.state = {
+ revealBadActorMemo: false,
+ }
+ }
+
+ decodeMemo(memo_private, text) {
+ try {
+ return memo.decode(memo_private, text);
+ } catch (e) {
console.error('memo decryption error', text, e);
- return 'Invalid memo'
- }
+ return 'Invalid memo';
}
}
+ onRevealBadActorMemo = e => {
+ e.preventDefault();
+ this.setState({ revealBadActorMemo: true });
+ };
+
render() {
const {decodeMemo} = this
- const {memo_private, text, myAccount} = this.props;
+ const { memo_private, text, myAccount, isFromBadActor } = this.props;
const isEncoded = /^#/.test(text);
- if (!isEncoded) return {text}
- if (!myAccount) return
- if (memo_private) return {decodeMemo(memo_private, text)}
- return {tt('g.login_to_see_memo')}
+ const classes = classnames({
+ Memo: true,
+ 'Memo--badActor': isFromBadActor,
+ 'Memo--private': memo_private,
+ });
+
+ let renderText = '';
+
+ if (!isEncoded) {
+ renderText = text;
+ } else if (memo_private) {
+ renderText = myAccount
+ ? decodeMemo(memo_private, text)
+ : tt('g.login_to_see_memo');
+ }
+
+ if (isFromBadActor && !this.state.revealBadActorMemo) {
+ renderText = (
+
+
+ {tt('transferhistoryrow_jsx.bad_actor_caution')}
+
+
+ {tt('transferhistoryrow_jsx.bad_actor_explained')}
+
+
+ {tt('transferhistoryrow_jsx.bad_actor_reveal_memo')}
+
+
+ );
+ }
+
+ return {renderText};
}
}
diff --git a/src/app/locales/en.json b/src/app/locales/en.json
index dd55f99..63b4bbc 100644
--- a/src/app/locales/en.json
+++ b/src/app/locales/en.json
@@ -491,7 +491,10 @@
"transferhistoryrow_jsx": {
"stop_power_down": "Stop power down",
"start_power_down_of": "Start power down of",
- "receive_interest_of": "Receive interest of"
+ "receive_interest_of": "Receive interest of",
+ "bad_actor_caution": "Caution",
+ "bad_actor_explained": "This is from an account that may be malicious. If you wish, you may temporarily reveal this memo which may contain dangerous links.",
+ "bad_actor_reveal_memo": "I understand the risk; show anyway."
},
"explorepost_jsx": {
"copied": "Copied!",