diff --git a/app/actions/TrezorActions.js b/app/actions/TrezorActions.js
index edfe913fb7..0600a84780 100644
--- a/app/actions/TrezorActions.js
+++ b/app/actions/TrezorActions.js
@@ -4,12 +4,15 @@ import * as wallet from "wallet";
import * as selectors from "selectors";
import fs from "fs";
import { sprintf } from "sprintf-js";
-import { rawHashToHex, rawToHex, hexToRaw } from "helpers";
+import { rawHashToHex, rawToHex, hexToRaw, str2utf8hex, hex2b64 } from "helpers";
import { publishTransactionAttempt } from "./ControlActions";
import { model1_decred_homescreen } from "helpers/trezor";
import { EXTERNALREQUEST_TREZOR_BRIDGE } from "main_dev/externalRequests";
-import { SIGNTX_ATTEMPT, SIGNTX_FAILED, SIGNTX_SUCCESS } from "./ControlActions";
+import {
+ SIGNTX_ATTEMPT, SIGNTX_FAILED, SIGNTX_SUCCESS,
+ SIGNMESSAGE_ATTEMPT, SIGNMESSAGE_FAILED, SIGNMESSAGE_SUCCESS
+} from "./ControlActions";
const hardeningConstant = 0x80000000;
@@ -293,6 +296,44 @@ export const signTransactionAttemptTrezor = (rawUnsigTx, constructTxResponse) =>
}
};
+export const signMessageAttemptTrezor = (address, message) => async (dispatch, getState) => {
+
+ dispatch({ type: SIGNMESSAGE_ATTEMPT });
+
+ const device = selectors.trezorDevice(getState());
+ if (!device) {
+ dispatch({ error: "Device not connected", type: SIGNMESSAGE_FAILED });
+ return;
+ }
+
+ const chainParams = selectors.chainParams(getState());
+ const { grpc: { walletService } } = getState();
+
+ try {
+ const addrValidResp = await wallet.validateAddress(walletService, address);
+ if (!addrValidResp.getIsValid()) throw "Input has an invalid address " + address;
+ if (!addrValidResp.getIsMine()) throw "Trezor only supports signing with wallet addresses";
+ const addrIndex = addrValidResp.getIndex();
+ const addrBranch = addrValidResp.getIsInternal() ? 1 : 0;
+ const address_n = addressPath(addrIndex, addrBranch, WALLET_ACCOUNT,
+ chainParams.HDCoinType);
+
+ const signedMsg = await deviceRun(dispatch, getState, device, async session => {
+ await dispatch(checkTrezorIsDcrwallet(session));
+
+ return await session.signMessage(address_n, str2utf8hex(message),
+ chainParams.trezorCoinName, false);
+ });
+
+ const signature = hex2b64(signedMsg.message.signature);
+ dispatch({ getSignMessageSignature: signature, type: SIGNMESSAGE_SUCCESS });
+
+ } catch (error) {
+ dispatch({ error, type: SIGNMESSAGE_FAILED });
+ }
+
+};
+
// walletTxToBtcjsTx converts a tx decoded by the decred wallet (ie,
// returned from the decodeRawTransaction call) into a bitcoinjs-compatible
// transaction (to be used in trezor)
diff --git a/app/components/buttons/SignMessageButton.js b/app/components/buttons/SignMessageButton.js
index 62c9c96dda..7c672577f4 100644
--- a/app/components/buttons/SignMessageButton.js
+++ b/app/components/buttons/SignMessageButton.js
@@ -1,5 +1,5 @@
import { signMessagePage } from "connectors";
-import { PassphraseModalButton } from "./index";
+import { PassphraseModalButton, KeyBlueButton } from "./index";
import { FormattedMessage as T } from "react-intl";
@autobind
@@ -16,19 +16,39 @@ class SignMessageButton extends React.Component {
onSubmit && onSubmit();
}
+ async onAttemptSignMessageTrezor() {
+ const { address, message, disabled, signMessageAttemptTrezor, onSubmit } = this.props;
+ if (disabled || !signMessageAttemptTrezor) return;
+ await signMessageAttemptTrezor(address, message);
+ onSubmit && onSubmit();
+ }
+
render() {
- const { disabled, isSigningMessage, className } = this.props;
-
- return (
- }
- className={className}
- disabled={disabled}
- onSubmit={this.onAttemptSignMessage}
- loading={isSigningMessage}
- buttonLabel={}
- />
- );
+ const { disabled, isSigningMessage, className, isTrezor } = this.props;
+
+ if (isTrezor) {
+ return (
+
+
+
+ );
+ } else {
+ return (
+ }
+ className={className}
+ disabled={disabled}
+ onSubmit={this.onAttemptSignMessage}
+ loading={isSigningMessage}
+ buttonLabel={}
+ />
+ );
+ }
}
}
diff --git a/app/connectors/signMessagePage.js b/app/connectors/signMessagePage.js
index 83d8a8eda0..fc07f59c46 100644
--- a/app/connectors/signMessagePage.js
+++ b/app/connectors/signMessagePage.js
@@ -3,6 +3,7 @@ import { bindActionCreators } from "redux";
import { selectorMap } from "../fp";
import * as sel from "../selectors";
import * as ca from "../actions/ControlActions";
+import * as trza from "../actions/TrezorActions";
const mapStateToProps = selectorMap({
signMessageError: sel.signMessageError,
@@ -10,12 +11,14 @@ const mapStateToProps = selectorMap({
isSigningMessage: sel.isSigningMessage,
walletService: sel.walletService,
isSignMessageDisabled: sel.isSignMessageDisabled,
+ isTrezor: sel.isTrezor,
});
const mapDispatchToProps = dispatch => bindActionCreators({
signMessageAttempt: ca.signMessageAttempt,
validateAddress: ca.validateAddress,
signMessageCleanStore: ca.signMessageCleanStore,
+ signMessageAttemptTrezor: trza.signMessageAttemptTrezor,
}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps);
diff --git a/app/helpers/byteActions.js b/app/helpers/byteActions.js
index 44643c10aa..18192ffff1 100644
--- a/app/helpers/byteActions.js
+++ b/app/helpers/byteActions.js
@@ -38,3 +38,12 @@ export function hexReversedHashToArray(hexStr) {
res.reverse();
return res;
}
+
+// str2utf8hex converts a (js, utf-16) string into (utf-8 encoded) hex.
+export function str2utf8hex(str) {
+ return Buffer.from(str).toString("hex");
+}
+
+export function hex2b64(hex) {
+ return new Buffer(hex, "hex").toString("base64");
+}