Skip to content

Commit

Permalink
Set up claim message signing and feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
ikem-legend committed Feb 27, 2024
1 parent cb48cb8 commit d057c8a
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 22 deletions.
1 change: 1 addition & 0 deletions libs/wcm/constants/permissions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const SIGNING_METHODS = {
SIGN_TRANSACTION: { key: 'sign_transaction', title: 'Signature request' },
SIGN_MESSAGE: { key: 'sign_message', title: 'Sign message' },
SIGN_CLAIM_MESSAGE: { key: 'sign_claim_message', title: 'Sign claim message' },
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
"socket.io-client": "4.7.0",
"stream-browserify": "3.0.0",
"swiper": "8.4.2",
"tweetnacl": "1.0.3",
"usb": "2.9.0",
"yup": "0.32.11"
},
Expand Down
2 changes: 1 addition & 1 deletion setup/react/app/MainRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const MainRouter = ({ history }) => {
if (event.name === EVENTS.SESSION_REQUEST) {
const method = event.meta?.params?.request?.method;

if (method === 'sign_message') {
if (method === 'sign_message' || method === 'sign_claim_message') {
showRequestModal('requestSignMessageDialog', event);
} else {
showRequestModal('requestView', event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,31 @@ import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import { useCurrentAccount } from '@account/hooks';
import { useDispatch } from 'react-redux';
import { signMessage } from '@message/store/action';
import { signMessage, signClaimMessage } from '@message/store/action';
import CopyToClipboard from '@common/components/copyToClipboard';
import { PrimaryButton } from '@theme/buttons';
import styles from './RequestSignMessageConfirmation.css';

export function RequestSignMessageConfirmation({ nextStep, address, message }) {
export function RequestSignMessageConfirmation({ nextStep, address, message, portalMessage }) {
const { t } = useTranslation();
const [currentAccount] = useCurrentAccount();
const dispatch = useDispatch();

/* istanbul ignore next */
const onClick = () => {
nextStep({
message,
actionFunction: (formProps, _, privateKey) =>
dispatch(signMessage({ message, nextStep, privateKey, currentAccount })),
});
if (message) {
nextStep({
message,
actionFunction: (formProps, _, privateKey) =>
dispatch(signMessage({ message, nextStep, privateKey, currentAccount })),
});
} else {
nextStep({
message: portalMessage,
actionFunction: (formProps, _, privateKey) =>
dispatch(signClaimMessage({ portalMessage, nextStep, privateKey, currentAccount })),
});
}
};

return (
Expand All @@ -39,7 +47,7 @@ export function RequestSignMessageConfirmation({ nextStep, address, message }) {
}}
/>
<p className={styles.label}>{t('Message')}</p>
<div className={styles.messageBox}>{message}</div>
<div className={styles.messageBox}>{message ?? portalMessage}</div>
<PrimaryButton className={classNames(styles.btnContinue, 'continue-btn')} onClick={onClick}>
{t('Continue')}
</PrimaryButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import SignedMessage from '@message/components/signedMessage';
import { RequestSignMessageConfirmation } from '@blockchainApplication/connection/components/RequestSignMessageDialog/RequestSignMessageConfirmation';
import { USER_REJECT_ERROR } from '@libs/wcm/utils/jsonRPCFormat';
import styles from './RequestSignMessageDialog.css';
import RequestSummary from '../RequestSummary';
import RequestSummary, { getTitle } from '../RequestSummary';

// eslint-disable-next-line max-statements
const RequestSignMessageDialog = () => {
Expand All @@ -31,7 +31,8 @@ const RequestSignMessageDialog = () => {

const { peer, requiredNamespaces } = sessionRequest || {};
const event = events?.find((e) => e.name === EVENTS.SESSION_REQUEST);
const { message, address } = event?.meta?.params?.request?.params || {};
const { method, params: { message, address, portalMessage } = {} } =
event?.meta?.params?.request || {};
const { icons, name, url } = peer?.metadata || {};

/* istanbul ignore next */
Expand Down Expand Up @@ -73,7 +74,10 @@ const RequestSignMessageDialog = () => {
{!isPasswordStep && !isErrorView && (
<BlockchainAppDetailsHeader
className={styles.blockchainAppDetailsHeaderProp}
headerText={multiStepPosition === 2 ? t('Signed message') : t('Sign message')}
headerText={
// eslint-disable-next-line no-nested-ternary
isPasswordStep ? t('Signed message') : method ? getTitle(method, t) : 'Sign message'
}
application={{
data: {
name,
Expand All @@ -93,7 +97,7 @@ const RequestSignMessageDialog = () => {
})}
onChange={onMultiStepChange}
>
<RequestSummary history={history} message={message} />
<RequestSummary history={history} message={message} portalMessage={portalMessage} />
<RequestSignMessageConfirmation message={message} address={address} />
<TxSignatureCollector
type="message"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import { toTransactionJSON } from '@transaction/utils/encoding';
import { useBlockchainApplicationMeta } from '@blockchainApplication/manage/hooks/queries/useBlockchainApplicationMeta';
import { convertFromBaseDenom } from '@token/fungible/utils/helpers';
import { joinModuleAndCommand } from '@transaction/utils/moduleCommand';
import { signMessage } from '@message/store/action';
import { signMessage, signClaimMessage } from '@message/store/action';
import { addSearchParamsToUrl, removeSearchParamsFromUrl } from 'src/utils/searchParams';
import { sizeOfString } from 'src/utils/helpers';
import { validator } from '@liskhq/lisk-client';
import { useSession } from '@libs/wcm/hooks/useSession';
import { useEvents } from '@libs/wcm/hooks/useEvents';
Expand All @@ -36,12 +37,12 @@ import { ReactComponent as SwitchIcon } from '../../../../../../setup/react/asse
import EmptyState from './EmptyState';
import styles from './requestSummary.css';

const getTitle = (key, t) =>
export const getTitle = (key, t) =>
Object.values(SIGNING_METHODS).find((item) => item.key === key)?.title ?? t('Method not found.');
const defaultToken = { symbol: 'LSK' };

// eslint-disable-next-line max-statements
const RequestSummary = ({ nextStep, history, message }) => {
const RequestSummary = ({ nextStep, history, message, portalMessage }) => {
const { t } = useTranslation();
const { getAccountByAddress, accounts } = useAccounts();
const [currentAccount, setCurrentAccount] = useCurrentAccount();
Expand Down Expand Up @@ -86,6 +87,12 @@ const RequestSummary = ({ nextStep, history, message }) => {
actionFunction: (formProps, _, privateKey) =>
reduxDispatch(signMessage({ message, nextStep, privateKey, currentAccount })),
});
} else if (portalMessage) {
nextStep({
portalMessage,
actionFunction: (formProps, _, privateKey) =>
reduxDispatch(signClaimMessage({ portalMessage, nextStep, privateKey, currentAccount })),
});
} else {
const moduleCommand = joinModuleAndCommand(transaction);
const transactionJSON = toTransactionJSON(transaction, request?.request?.params.schema);
Expand All @@ -110,6 +117,7 @@ const RequestSummary = ({ nextStep, history, message }) => {
});
}
};

const rejectHandler = async () => {
await respond({ payload: USER_REJECT_ERROR });
removeSearchParamsFromUrl(history, ['modal', 'status', 'name', 'action']);
Expand Down Expand Up @@ -144,14 +152,19 @@ const RequestSummary = ({ nextStep, history, message }) => {
const { payload, schema, address: publicKey } = request.request.params;
let transactionObj;

if (!message) {
// Validate portal message
if (portalMessage && sizeOfString(portalMessage) === 84) {
setErrorMessage('');
} else if (portalMessage && sizeOfString(portalMessage) !== 84) {
setErrorMessage('Claim message of invalid size received.');
} else if (!message) {
validator.validator.validateSchema(schema);
transactionObj = decodeTransaction(Buffer.from(payload, 'hex'), schema);
validator.validator.validate(schema, transactionObj.params);
setTransaction(transactionObj);
}

const senderPublicKey = !message ? transactionObj.senderPublicKey : publicKey;
const senderPublicKey =
!message && !portalMessage ? transactionObj.senderPublicKey : publicKey;
const address = extractAddressFromPublicKey(senderPublicKey);
const account = getAccountByAddress(address);
setSenderAccount({
Expand Down Expand Up @@ -203,7 +216,7 @@ const RequestSummary = ({ nextStep, history, message }) => {

return (
<div className={`${styles.wrapper}`}>
{!message && (
{!message && !portalMessage && (
<BlockchainAppDetailsHeader
headerText={getTitle(request?.request?.method, t)}
application={application}
Expand Down
2 changes: 1 addition & 1 deletion src/modules/message/components/signedMessage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const SignedMessage = ({ signature, error, onPrev, reset }) => {
return (
<Success
t={t}
signature={signature}
signature={typeof signature === 'string' ? signature : JSON.stringify(signature, null, '\t')}
copied={copied}
copy={copy}
history={history}
Expand Down
23 changes: 22 additions & 1 deletion src/modules/message/store/action.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { to } from 'await-to-js';
import { cryptography } from '@liskhq/lisk-client';
import { signMessageUsingHW } from '@wallet/utils/signMessage';
import { signMessageWithPrivateKey } from '../utils/signMessageWithPrivateKey';
import {
signMessageWithPrivateKey,
signClaimMessageWithPrivateKey,
} from '../utils/signMessageWithPrivateKey';

export const getUnsignedNonProtocolMessage = (message) =>
Buffer.concat([
Expand Down Expand Up @@ -39,3 +42,21 @@ export const signMessage =

return nextStep({ signature, message });
};

export const signClaimMessage =
({ nextStep, portalMessage, privateKey, currentAccount }) =>
async () => {
const signature = signClaimMessageWithPrivateKey({
message: portalMessage,
privateKey,
});
const portalSignature = {
data: {
pubKey: currentAccount.metadata.pubkey,
r: `0x${signature.substring(0, 64)}`,
s: `0x${signature.substring(64)}`,
},
};

return nextStep({ signature: portalSignature, portalMessage });
};
9 changes: 9 additions & 0 deletions src/modules/message/utils/signMessageWithPrivateKey.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { cryptography } from '@liskhq/lisk-client';
import { sign } from 'tweetnacl';

export const signMessageWithPrivateKey = ({ message, privateKey }) => {
const result = cryptography.ed.signAndPrintMessage(message, Buffer.from(privateKey, 'hex'));

return result;
};

export const signClaimMessageWithPrivateKey = ({ message, privateKey }) => {
const result = Buffer.from(
sign.detached(Buffer.from(message.substring(2), 'hex'), Buffer.from(privateKey, 'hex'))
).toString('hex');

return result;
};

0 comments on commit d057c8a

Please sign in to comment.