diff --git a/web/cashtab/src/components/SignVerifyMsg/SignVerifyMsg.js b/web/cashtab/src/components/SignVerifyMsg/SignVerifyMsg.js
index 1279e2205..8e2c4b382 100644
--- a/web/cashtab/src/components/SignVerifyMsg/SignVerifyMsg.js
+++ b/web/cashtab/src/components/SignVerifyMsg/SignVerifyMsg.js
@@ -1,487 +1,465 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState } from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { Form, Modal, Input } from 'antd';
import { WalletContext } from 'utils/context';
import {
TokenParamLabel,
MessageVerificationParamLabel,
WalletInfoCtn,
ZeroBalanceHeader,
SidePaddingCtn,
} from 'components/Common/Atoms';
import WalletLabel from 'components/Common/WalletLabel.js';
import BalanceHeader from 'components/Common/BalanceHeader';
import BalanceHeaderFiat from 'components/Common/BalanceHeaderFiat';
import {
errorNotification,
messageSignedNotification,
generalNotification,
} from 'components/Common/Notifications';
import { CustomCollapseCtn } from 'components/Common/StyledCollapse';
import {
AntdFormWrapper,
DestinationAddressSingleWithoutQRScan,
} from 'components/Common/EnhancedInputs';
const { TextArea } = Input;
import {
convertToEcashPrefix,
getWalletState,
getECPairFromWIF,
} from 'utils/cashMethods';
import CopyToClipboard from 'components/Common/CopyToClipboard';
import { ThemedCopySolid } from 'components/Common/CustomIcons';
import { SmartButton } from 'components/Common/PrimaryButton';
import { PlusSquareOutlined } from '@ant-design/icons';
import { currency, parseAddressForParams } from 'components/Common/Ticker.js';
import { isValidXecAddress, isValidEtokenAddress } from 'utils/validation';
import xecMessage from 'xecjs-message';
const Wrapper = styled.div`
.ant-collapse {
&:first-child {
margin-top: 30px;
}
}
`;
const SignMessageLabel = styled.div`
text-align: left;
color: ${props => props.theme.forms.text};
`;
const AddressCopyCtn = styled.div`
display: flex;
align-items: center;
gap: 0.5rem;
svg {
height: 30px;
width: 30px;
&:hover {
fill: ${props => props.theme.eCashBlue};
cursor: pointer;
}
}
`;
const VerifyMessageLabel = styled.div`
text-align: left;
color: ${props => props.theme.forms.text};
`;
const SignatureValidation = styled.div`
color: ${props => props.theme.encryptionRed};
`;
-const SignVerifyMsg = ({ jestBCH }) => {
+const SignVerifyMsg = () => {
const ContextValue = React.useContext(WalletContext);
- const { BCH, wallet, fiatPrice, cashtabSettings, changeCashtabSettings } =
+ const { wallet, fiatPrice, cashtabSettings, changeCashtabSettings } =
ContextValue;
const walletState = getWalletState(wallet);
const { balances } = walletState;
const [messageSignature, setMessageSignature] = useState('');
const [showConfirmMsgToSign, setShowConfirmMsgToSign] = useState(false);
const [msgToSign, setMsgToSign] = useState('');
const [sigCopySuccess, setSigCopySuccess] = useState('');
const [signMessageIsValid, setSignMessageIsValid] = useState(null);
const [showConfirmMsgToVerify, setShowConfirmMsgToVerify] = useState(false);
const [messageVerificationAddr, setMessageVerificationAddr] = useState('');
- const [bchObj, setBchObj] = useState(false);
const [messageVerificationSig, setMessageVerificationSig] = useState('');
const [messageVerificationMsg, setMessageVerificationMsg] = useState('');
const [messageVerificationMsgIsValid, setMessageVerificationMsgIsValid] =
useState(false);
const [messageVerificationAddrError, setMessageVerificationAddrError] =
useState(false);
const [messageVerificationAddrIsValid, setMessageVerificationAddrIsValid] =
useState(false);
const [messageVerificationSigIsValid, setMessageVerificationSigIsValid] =
useState(false);
const [messageVerificationSigError, setMessageVerificationSigError] =
useState(false);
const signMessageByPk = () => {
try {
- const messageSignature = bchObj.BitcoinCash.signMessageWithPrivKey(
- wallet.Path1899.fundingWif,
- msgToSign,
- );
- // Get local messageSignature
// First, get required params
const keyPair = getECPairFromWIF(wallet.Path1899.fundingWif);
// Reference https://github.com/Permissionless-Software-Foundation/bch-js/blob/master/src/bitcoincash.js#L161
const privKey = keyPair.d.toBuffer(32);
// Now you can get the local signature
- const localMessageSignature = xecMessage
+ const messageSignature = xecMessage
.sign(msgToSign, privKey, keyPair.compressed)
.toString('base64');
- // Compare to legacy method
- console.log(`legacy signature`, messageSignature);
- console.log(`local signature`, localMessageSignature);
-
- if (messageSignature === localMessageSignature) {
- console.log(`The signatures match`);
- }
setMessageSignature(messageSignature);
messageSignedNotification(messageSignature);
} catch (err) {
let message;
if (!err.error && !err.message) {
message = err.message || err.error || JSON.stringify(err);
}
errorNotification(err, message, 'Message Signing Error');
throw err;
}
// Hide the modal
setShowConfirmMsgToSign(false);
setSigCopySuccess('');
};
const handleSignMsgChange = e => {
const { value } = e.target;
// validation
if (value && value.length && value.length < 150) {
setMsgToSign(value);
setSignMessageIsValid(true);
} else {
setSignMessageIsValid(false);
}
};
const verifyMessageBySig = () => {
let verification;
try {
verification = xecMessage.verify(
messageVerificationMsg,
messageVerificationAddr,
messageVerificationSig,
);
} catch (err) {
errorNotification(
err,
'Error',
'Unable to execute signature verification',
);
}
if (verification) {
generalNotification('Signature successfully verified', 'Verified');
} else {
errorNotification(
'Error',
'Signature does not match address and message',
'Called from SignVerifyMsg.js on invalid message signing',
);
}
setShowConfirmMsgToVerify(false);
};
const handleOnSigCopy = () => {
if (messageSignature != '') {
setSigCopySuccess('Signature copied to clipboard');
}
};
const handleVerifyMsgChange = e => {
const { value } = e.target;
// validation
if (value && value.length && value.length < 150) {
setMessageVerificationMsgIsValid(true);
} else {
setMessageVerificationMsgIsValid(false);
}
setMessageVerificationMsg(value);
};
const handleVerifySigChange = e => {
const { value } = e.target;
// validation
if (value && value.length && value.length === 88) {
setMessageVerificationSigIsValid(true);
setMessageVerificationSigError(false);
} else {
setMessageVerificationSigIsValid(false);
setMessageVerificationSigError('Invalid signature');
}
setMessageVerificationSig(value);
};
const handleMessageVerificationAddrChange = e => {
const { value } = e.target;
let error = false;
let addressString = value;
// parse address for parameters
const addressInfo = parseAddressForParams(addressString);
// validate address
const isValid = isValidXecAddress(addressInfo.address);
const { address } = addressInfo;
// Is this valid address?
if (!isValid) {
error = `Invalid ${currency.ticker} address`;
// If valid address but token format
if (isValidEtokenAddress(address)) {
error = `eToken addresses are not supported for signature verifications`;
}
setMessageVerificationAddrIsValid(false);
} else {
setMessageVerificationAddrIsValid(true);
}
setMessageVerificationAddrError(error);
setMessageVerificationAddr(address);
};
- useEffect(() => {
- // jestBCH is only ever specified for unit tests, otherwise app will use getBCH();
- const activeBCH = jestBCH ? jestBCH : BCH;
-
- // set the BCH instance to state, for other functions to reference
- setBchObj(activeBCH);
- }, [BCH]);
-
return (
{!balances.totalBalance ? (
You currently have 0 {currency.ticker}
Deposit some funds to use this feature
) : (
<>
>
)}
{' '}
setShowConfirmMsgToSign(false)}
>
Message: {msgToSign}
Message:
Address:
{wallet &&
wallet.Path1899 &&
wallet.Path1899.cashAddress && (
)}
setShowConfirmMsgToSign(true)}
disabled={!signMessageIsValid}
>
Sign Message
Signature:
{sigCopySuccess}
setShowConfirmMsgToVerify(false)}
>
Message:
{' '}
{messageVerificationMsg}
Address:
{' '}
{messageVerificationAddr}
Signature:
{' '}
{messageVerificationSig}
Message:
Address:
handleMessageVerificationAddrChange(
e,
),
required: true,
}}
>
Signature:
setShowConfirmMsgToVerify(true)}
disabled={
!messageVerificationAddrIsValid ||
!messageVerificationSigIsValid ||
!messageVerificationMsgIsValid
}
>
Verify Message
);
};
SignVerifyMsg.propTypes = {
- jestBCH: PropTypes.object,
cashtabSettings: PropTypes.oneOfType([
PropTypes.shape({
fiatCurrency: PropTypes.string,
sendModal: PropTypes.bool,
autoCameraOn: PropTypes.bool,
hideMessagesFromUnknownSender: PropTypes.bool,
toggleShowHideBalance: PropTypes.bool,
}),
PropTypes.bool,
]),
changeCashtabSettings: PropTypes.func,
};
export default SignVerifyMsg;
diff --git a/web/cashtab/src/components/SignVerifyMsg/__tests__/SignVerifyMsg.test.js b/web/cashtab/src/components/SignVerifyMsg/__tests__/SignVerifyMsg.test.js
index 32f7346de..c6ce8ff9b 100644
--- a/web/cashtab/src/components/SignVerifyMsg/__tests__/SignVerifyMsg.test.js
+++ b/web/cashtab/src/components/SignVerifyMsg/__tests__/SignVerifyMsg.test.js
@@ -1,97 +1,92 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { ThemeProvider } from 'styled-components';
import { theme } from 'assets/styles/theme';
import {
walletWithoutBalancesMock,
walletWithBalancesMock,
walletWithBalancesAndTokensWithCorrectState,
} from '../../Home/__mocks__/walletAndBalancesMock';
import SignVerifyMsg from '../SignVerifyMsg';
-import BCHJS from '@psf/bch-js';
import { BrowserRouter as Router } from 'react-router-dom';
import { WalletContext } from 'utils/context';
beforeEach(() => {
// Mock method not implemented in JSDOM
// See reference at https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
});
test('Wallet without BCH balance', () => {
- const testBCH = new BCHJS();
const component = renderer.create(
-
+
,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
test('Wallet with BCH balances', () => {
- const testBCH = new BCHJS();
const component = renderer.create(
-
+
,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
test('Wallet with BCH balances and tokens and state field', () => {
- const testBCH = new BCHJS();
const component = renderer.create(
-
+
,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
test('Without wallet defined', () => {
const withoutWalletDefinedMock = {
wallet: {},
balances: { totalBalance: 0 },
loading: false,
};
- const testBCH = new BCHJS();
const component = renderer.create(
-
+
,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});