diff --git a/web/cashtab/src/components/SignVerifyMsg/SignVerifyMsg.js b/web/cashtab/src/components/SignVerifyMsg/SignVerifyMsg.js index db6c553d2..f73fb91c3 100644 --- a/web/cashtab/src/components/SignVerifyMsg/SignVerifyMsg.js +++ b/web/cashtab/src/components/SignVerifyMsg/SignVerifyMsg.js @@ -1,486 +1,467 @@ import React, { useState, useEffect } 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 { - toLegacyCash, - convertToEcashPrefix, - getWalletState, -} from 'utils/cashMethods'; +import { convertToEcashPrefix, getWalletState } 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 ContextValue = React.useContext(WalletContext); const { BCH, 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 = async () => { try { const messageSignature = - await BCH.BitcoinCash.signMessageWithPrivKey( + await bchObj.BitcoinCash.signMessageWithPrivKey( wallet.Path1899.fundingWif, msgToSign, ); 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; - let newVerification; try { - verification = bchObj.BitcoinCash.verifyMessage( - toLegacyCash(messageVerificationAddr), - messageVerificationSig, - messageVerificationMsg, - ); - newVerification = xecMessage.verify( + verification = xecMessage.verify( messageVerificationMsg, messageVerificationAddr, messageVerificationSig, ); } catch (err) { errorNotification( err, 'Error', 'Unable to execute signature verification', ); } - if (verification === newVerification) { - console.log( - `Both signature verification methods return the same result`, - ); - } else { - console.log(`legacy verification method returned`, verification); - console.log(`new verification method returned`, newVerification); - } - 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 ( <Wrapper> <WalletInfoCtn> <WalletLabel name={wallet.name} cashtabSettings={cashtabSettings} changeCashtabSettings={changeCashtabSettings} ></WalletLabel> {!balances.totalBalance ? ( <ZeroBalanceHeader> You currently have 0 {currency.ticker} <br /> Deposit some funds to use this feature </ZeroBalanceHeader> ) : ( <> <BalanceHeader balance={balances.totalBalance} ticker={currency.ticker} cashtabSettings={cashtabSettings} /> <BalanceHeaderFiat balance={balances.totalBalance} settings={cashtabSettings} fiatPrice={fiatPrice} /> </> )} </WalletInfoCtn>{' '} <SidePaddingCtn> <Modal title={`Please review and confirm your message to be signed using this wallet.`} open={showConfirmMsgToSign} onOk={signMessageByPk} onCancel={() => setShowConfirmMsgToSign(false)} > <TokenParamLabel>Message:</TokenParamLabel> {msgToSign} <br /> </Modal> <CustomCollapseCtn panelHeader="Sign Message"> <AntdFormWrapper> <Form size="small" style={{ width: 'auto', }} > <Form.Item> <SignMessageLabel>Message:</SignMessageLabel> <TextArea name="signMessage" onChange={e => handleSignMsgChange(e)} showCount maxLength={150} /> </Form.Item> <Form.Item> <SignMessageLabel>Address:</SignMessageLabel> {wallet && wallet.Path1899 && wallet.Path1899.cashAddress && ( <AddressCopyCtn> <Input name="signMessageAddress" disabled={true} value={ wallet && wallet.Path1899 && wallet.Path1899.cashAddress ? convertToEcashPrefix( wallet.Path1899 .cashAddress, ) : '' } /> <CopyToClipboard data={convertToEcashPrefix( wallet.Path1899.cashAddress, )} optionalOnCopyNotification={{ title: 'Copied', msg: `${convertToEcashPrefix( wallet.Path1899 .cashAddress, )} copied to clipboard`, }} > <ThemedCopySolid /> </CopyToClipboard> </AddressCopyCtn> )} </Form.Item> <SmartButton onClick={() => setShowConfirmMsgToSign(true)} disabled={!signMessageIsValid} > <PlusSquareOutlined /> Sign Message </SmartButton> <CopyToClipboard data={messageSignature} optionalOnCopyNotification={{ title: 'Message signature copied to clipboard', msg: `${messageSignature}`, }} > <Form.Item> <SignMessageLabel> Signature: </SignMessageLabel> <TextArea name="signMessageSignature" placeholder="The signature will be generated upon signing of the message" readOnly={true} value={messageSignature} onClick={() => handleOnSigCopy()} /> </Form.Item> </CopyToClipboard> {sigCopySuccess} </Form> </AntdFormWrapper> </CustomCollapseCtn> <Modal title={`Please review and confirm your message, signature and address to be verified.`} open={showConfirmMsgToVerify} onOk={verifyMessageBySig} onCancel={() => setShowConfirmMsgToVerify(false)} > <MessageVerificationParamLabel> Message: </MessageVerificationParamLabel>{' '} {messageVerificationMsg} <br /> <MessageVerificationParamLabel> Address: </MessageVerificationParamLabel>{' '} {messageVerificationAddr} <br /> <MessageVerificationParamLabel> Signature: </MessageVerificationParamLabel>{' '} {messageVerificationSig} <br /> </Modal> <CustomCollapseCtn panelHeader="Verify Message"> <AntdFormWrapper> <Form size="small" style={{ width: 'auto', }} > <Form.Item> <VerifyMessageLabel> Message: </VerifyMessageLabel> <TextArea name="verifyMessage" onChange={e => handleVerifyMsgChange(e)} showCount maxLength={150} /> </Form.Item> <Form.Item> <VerifyMessageLabel> Address: </VerifyMessageLabel> <DestinationAddressSingleWithoutQRScan validateStatus={ messageVerificationAddrError ? 'error' : '' } help={ messageVerificationAddrError ? messageVerificationAddrError : '' } inputProps={{ placeholder: `${currency.ticker} Address`, name: 'address', onChange: e => handleMessageVerificationAddrChange( e, ), required: true, }} ></DestinationAddressSingleWithoutQRScan> </Form.Item> <Form.Item> <VerifyMessageLabel> Signature: </VerifyMessageLabel> <TextArea name="verifySignature" onChange={e => handleVerifySigChange(e)} showCount /> <SignatureValidation> {messageVerificationSigError} </SignatureValidation> </Form.Item> <SmartButton onClick={() => setShowConfirmMsgToVerify(true)} disabled={ !messageVerificationAddrIsValid || !messageVerificationSigIsValid || !messageVerificationMsgIsValid } > <PlusSquareOutlined /> Verify Message </SmartButton> </Form> </AntdFormWrapper> </CustomCollapseCtn> </SidePaddingCtn> </Wrapper> ); }; 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;