add checks for TOS violation conditions (#74)

* add checks for TOS violation conditions

uppercase letters
less than 4
contains 0x

* force lowercase on searching

* use css for lowercase textTransform

* uncomment edit button

* add addressLikeUsername to TOS violation check

* remove possible state update race condition

* add inputs for editing

* update embark to web3 version 34
This commit is contained in:
Barry G 2018-10-28 14:05:04 +01:00 committed by Ricardo Guilherme Schmidt
parent 608f1e9df7
commit 02b9461d68
6 changed files with 137 additions and 88 deletions

View File

@ -23,12 +23,15 @@ export const fetchAndDispatchAccountsWithBalances = (web3, dispatch) => {
}
})
}
export const checkAndDispatchStatusContactCode = (dispatch, callback) => {
export const checkAndDispatchStatusContactCode = (dispatch) => {
window.web3.currentProvider.status
.getContactCode()
.then(data => {
callback(data);
dispatch(receiveStatusContactCode(data));
setTimeout(() => {
// This seems to be required with Status api calls.
// This could be a bug with the client itself as the issue is found in other contexts.
dispatch(receiveStatusContactCode(data))
}, 0);
})
.catch(err => {
console.warn('Error:', err);

View File

@ -3,7 +3,6 @@ import web3 from 'web3';
import EmbarkJS from 'Embark/EmbarkJS';
import { connect } from 'react-redux';
import { actions as accountActions, getDefaultAccount } from '../../reducers/accounts';
import { checkAndDispatchStatusContactCode } from '../../actions/accounts';
import { hash } from 'eth-ens-namehash';
import { isNil } from 'lodash';
import Hidden from '@material-ui/core/Hidden';
@ -36,6 +35,7 @@ import DisplayBox from './DisplayBox';
import styled from "styled-components";
import { Route } from "react-router-dom";
import { ReservedUsernames } from '../../../config/ens-usernames/reservedNames'
import { addressLikeUsername } from '../ens/utils/slashing';
const normalizer = new IDNANormalizer();
const invalidSuffix = '0000000000000000000000000000000000000000'
@ -149,7 +149,7 @@ class RenderAddresses extends PureComponent {
</Hidden>
<Hidden mdUp>
{submitted ? <TransactionComplete type={editAction} setStatus={setStatus} /> : <MobileAddressDisplay {...this.props} isOwner={isOwner} edit={editAction === 'edit'} onSubmit={() => { this.setState({ submitted: true}) }}/>}
{/* {isOwner && !editAction && <MobileButton text="Edit" style={{ margin: 'auto', display: 'block' }} onClick={onClickEdit}/>} */}
{isOwner && !editAction && <MobileButton text="Edit" style={{ margin: 'auto', display: 'block' }} onClick={onClickEdit}/>}
<EditOptions open={editMenu} onClose={onClose} canBeReleased={canBeReleased} />
<ReleaseDomainAlert open={editAction === 'release' && !submitted} handleClose={closeReleaseAlert} />
</Hidden>
@ -164,7 +164,6 @@ const InfoHeading = styled.h2`
text-align: center;
letter-spacing: -0.275px;
margin: 0 0 12px 0;
color: #FFFFFF;
`;
@ -294,8 +293,9 @@ class WarningBlock extends React.Component {
if (status && status.domainNameStatus === DomainNameStatus.InvalidName) {
return <Warning>Names are made with<br/>letters and numbers only</Warning>
}
else if (status) {
} else if (status && status.domainNameStatus === DomainNameStatus.TosViolation) {
return <Warning>This name is not allowed by the terms & conditions. Please try another.</Warning>
} else if (status) {
return <Warning>This name is reserved for security purposes. Please try another.</Warning>
}
return null;
@ -304,7 +304,7 @@ class WarningBlock extends React.Component {
class LookupForm extends React.Component {
render() {
const { handleSubmit, values, handleChange, warningCanBeDisplayed } = this.props;
const { handleSubmit, values, handleChange, warningCanBeDisplayed, setFieldValue } = this.props;
return (
<Fragment>
@ -323,6 +323,7 @@ class LookupForm extends React.Component {
<MobileSearch
name="domainName"
type="search"
style={{ textTransform: 'lowercase' }}
placeholder='Search for available name'
value={values.domainName}
onChange={handleChange}
@ -341,10 +342,14 @@ class LookupForm extends React.Component {
}
}
const DomainNameStatus = Object.freeze({"Correct": 1, "InvalidName": 2, "ReservedName": 3});
const DomainNameStatus = Object.freeze({"Correct": 1, "InvalidName": 2, "ReservedName": 3, "TosViolation": 4});
const getDomainNameStatus = val => {
const value = val.toLowerCase().trim();
if (value !== val.trim()) return DomainNameStatus.TosViolation;
if (value.length < 4) return DomainNameStatus.TosViolation;
if (addressLikeUsername(value)) return DomainNameStatus.TosViolation;
if (/^([a-z0-9]+)$/.test(value)) {
if (ReservedUsernames.includes(value)) {
return DomainNameStatus.ReservedName;

View File

@ -1,7 +1,7 @@
import web3 from "Embark/web3"
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar';
import TestToken from 'Embark/contracts/TestToken';
import React from 'react';
import React, { Fragment } from 'react';
import {connect} from 'react-redux';
import Hidden from '@material-ui/core/Hidden';
import CircularProgress from '@material-ui/core/CircularProgress';
@ -11,6 +11,8 @@ import {hash} from 'eth-ens-namehash';
import {zeroAddress, zeroBytes32, formatPrice} from './utils';
import {getStatusContactCode, getSNTAllowance, getCurrentAccount} from '../../reducers/accounts';
import FieldGroup from '../standard/FieldGroup';
import Field from '../../ui/components/Field';
import MobileSearch from '../../ui/components/MobileSearch';
import LinearProgress from '@material-ui/core/LinearProgress';
import Terms from './terms';
import {generateXY} from '../../utils/ecdsa';
@ -25,14 +27,13 @@ const formRef = React.createRef();
const displayTerms = status => status === 'terms';
class InnerForm extends React.Component {
requestStatusContactCode = ({getStatusContactCode, setValues, values}) => {
getStatusContactCode((result) => {
setValues({...values, statusAddress: result});
});
};
onRegisterClick = ({values, setStatus}) => {
onRegisterClick = ({ values, setStatus, editAccount }) => {
if (editAccount) {
setStatus(null);
formRef.current.dispatchEvent(new Event('submit'));
} else {
setStatus("terms");
}
};
render() {
@ -49,7 +50,9 @@ class InnerForm extends React.Component {
domainPrice,
editAccount,
setStatus,
status
status,
statusContactCode,
requestStatusContactCode
} = this.props;
return (
@ -130,22 +133,46 @@ class InnerForm extends React.Component {
<Hidden mdUp>
{!editAccount ? <Fragment>
<DisplayBox displayType={YOUR_WALLET_ADDRESS}
text={values.address}/>
<DisplayBox displayType={YOUR_CONTACT_CODE}
text={values.statusAddress}
showBlueBox={!values.statusAddress}
onClick={() => this.requestStatusContactCode(this.props)}/>
text={statusContactCode}
showBlueBox={!statusContactCode}
onClick={() => requestStatusContactCode()}/>
</Fragment> :
<Fragment>
<Field label="Your Wallet Address">
<MobileSearch
name="address"
style={{ marginTop: '10px' }}
placeholder="Your wallet address"
value={values.address}
onChange={handleChange}
onClick={() => setFieldValue('address', '')}
required
wide />
</Field>
<Field label="Your contact code">
<MobileSearch
name="statusAddress"
style={{ marginTop: '10px' }}
placeholder="Enter Your Status Messenger Address Here"
value={values.statusAddress}
onChange={handleChange}
onClick={() => setFieldValue('statusAddress', '')}
wide />
</Field>
</Fragment>}
<div style={{display: 'flex', flexDirection: 'row-reverse', marginTop: '16px', marginBottom: '16px'}}>
{!isSubmitting ?
<ArrowButton onClick={(e) => {
this.onRegisterClick(this.props);
e.preventDefault();
}}>
<div>
{`${editAccount ? 'Save' : 'Register'}`}
{`${editAccount ? 'Update' : 'Register'}`}
</div>
</ArrowButton>
:
@ -202,7 +229,7 @@ const RegisterSubDomain = withFormik({
];
if (editAccount) {
if (address !== web3.eth.defaultAccount) funcsToSend.push(setAddr(node, resolveToAddr));
if (statusAddress && statusAddress !== props.statusContactCode) funcsToSend.push(setPubkey(node, args[3], args[4]));
if (statusAddress && statusAddress !== props.statusContactCode) funcsToSend.push(setPubkey(node, args[2], args[3]));
} else {
funcsToSend.push(
approveAndCall(UsernameRegistrar.address, domainPrice, register(...args).encodeABI())
@ -250,8 +277,8 @@ const mapStateToProps = state => ({
});
const mapDispatchToDisplayBoxProps = dispatch => ({
getStatusContactCode(callback) {
checkAndDispatchStatusContactCode(dispatch, callback);
requestStatusContactCode() {
checkAndDispatchStatusContactCode(dispatch);
},
});

View File

@ -0,0 +1,14 @@
export const addressLikeUsername = username => {
const length = username.length;
const firstIsZero = username[0] === "0";
const secondIsX = username[1].toLowerCase() === "x";
let isAddress = false;
if (length > 12 && firstIsZero && secondIsX) {
username.slice(2, 7).split("").forEach(letter => {
const code = letter.charCodeAt();
if ((code >= 48 && code <= 57) || (code >= 97 && code <= 102)) return isAddress = true;
isAddress = false;
})
}
return isAddress;
}

View File

@ -9,7 +9,7 @@
"buildDir": "dist/",
"config": "config/",
"versions": {
"web3": "1.0.0-beta",
"web3": "1.0.0-beta.34",
"solc": "0.4.24",
"ipfs-api": "17.2.4"
},

View File

@ -44,7 +44,7 @@
"reselect": "^3.0.1",
"styled-components": "^3.3.2",
"typeface-roboto": "0.0.54",
"web3-utils": "^1.0.0-beta.36"
"web3-utils": "^1.0.0-beta.34"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.0.0",