Add raw hash signing (#5423)
* add sign any * Add RPC signMessage call to JS API * Add signMessage to JSON RPC docs * PostSignTransaction -> EthSignMessage * fix doc typo * revert incorect naming
This commit is contained in:
parent
daf1495c4e
commit
52eae66c72
@ -522,6 +522,11 @@ export default class Parity {
|
||||
.then(outNumber);
|
||||
}
|
||||
|
||||
signMessage (address, password, messageHash) {
|
||||
return this._transport
|
||||
.execute('parity_signMessage', inAddress(address), password, inHex(messageHash));
|
||||
}
|
||||
|
||||
testPassword (account, password) {
|
||||
return this._transport
|
||||
.execute('parity_testPassword', inAddress(account), password);
|
||||
|
@ -1881,5 +1881,31 @@ export default {
|
||||
desc: 'Decrypted message.',
|
||||
example: withComment('0x68656c6c6f20776f726c64', 'hello world')
|
||||
}
|
||||
},
|
||||
|
||||
signMessage: {
|
||||
desc: 'Sign the hashed message bytes with the given account.',
|
||||
params: [
|
||||
{
|
||||
type: Address,
|
||||
desc: 'Account which signs the message.',
|
||||
example: '0xc171033d5cbff7175f29dfd3a63dda3d6f8f385e'
|
||||
},
|
||||
{
|
||||
type: String,
|
||||
desc: 'Passphrase to unlock the account.',
|
||||
example: 'password1'
|
||||
},
|
||||
{
|
||||
type: Data,
|
||||
desc: 'Hashed message.',
|
||||
example: '0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a'
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: Data,
|
||||
desc: 'Message signature.',
|
||||
example: '0x1d9e33a8cf8bfc089a172bca01da462f9e359c6cb1b0f29398bc884e4d18df4f78588aee4fb5cc067ca62d2abab995e0bba29527be6ac98105b0320020a2efaf00'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -474,7 +474,7 @@ pub fn execute<D: Dispatcher + 'static>(
|
||||
.map(ConfirmationResponse::SignTransaction)
|
||||
).boxed()
|
||||
},
|
||||
ConfirmationPayload::Signature(address, mut data) => {
|
||||
ConfirmationPayload::EthSignMessage(address, mut data) => {
|
||||
let mut message_data =
|
||||
format!("\x19Ethereum Signed Message:\n{}", data.len())
|
||||
.into_bytes();
|
||||
@ -574,8 +574,8 @@ pub fn from_rpc<D>(payload: RpcConfirmationPayload, default_account: Address, di
|
||||
RpcConfirmationPayload::Decrypt(RpcDecryptRequest { address, msg }) => {
|
||||
future::ok(ConfirmationPayload::Decrypt(address.into(), msg.into())).boxed()
|
||||
},
|
||||
RpcConfirmationPayload::Signature(RpcSignRequest { address, data }) => {
|
||||
future::ok(ConfirmationPayload::Signature(address.into(), data.into())).boxed()
|
||||
RpcConfirmationPayload::EthSignMessage(RpcSignRequest { address, data }) => {
|
||||
future::ok(ConfirmationPayload::EthSignMessage(address.into(), data.into())).boxed()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -113,8 +113,8 @@ pub enum ConfirmationPayload {
|
||||
SendTransaction(FilledTransactionRequest),
|
||||
/// Sign Transaction
|
||||
SignTransaction(FilledTransactionRequest),
|
||||
/// Sign request
|
||||
Signature(Address, Bytes),
|
||||
/// Sign a message with an Ethereum specific security prefix.
|
||||
EthSignMessage(Address, Bytes),
|
||||
/// Decrypt request
|
||||
Decrypt(Address, Bytes),
|
||||
}
|
||||
@ -124,7 +124,7 @@ impl ConfirmationPayload {
|
||||
match *self {
|
||||
ConfirmationPayload::SendTransaction(ref request) => request.from,
|
||||
ConfirmationPayload::SignTransaction(ref request) => request.from,
|
||||
ConfirmationPayload::Signature(ref address, _) => *address,
|
||||
ConfirmationPayload::EthSignMessage(ref address, _) => *address,
|
||||
ConfirmationPayload::Decrypt(ref address, _) => *address,
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! Account management (personal) rpc implementation
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::collections::BTreeMap;
|
||||
use util::{Address};
|
||||
use util::Address;
|
||||
|
||||
use ethkey::{Brain, Generator, Secret};
|
||||
use ethstore::KeyFile;
|
||||
@ -27,7 +27,7 @@ use jsonrpc_core::Error;
|
||||
use v1::helpers::errors;
|
||||
use v1::helpers::accounts::unwrap_provider;
|
||||
use v1::traits::ParityAccounts;
|
||||
use v1::types::{H160 as RpcH160, H256 as RpcH256, DappId, Derive, DeriveHierarchical, DeriveHash};
|
||||
use v1::types::{H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, DappId, Derive, DeriveHierarchical, DeriveHash};
|
||||
|
||||
/// Account management (personal) rpc implementation.
|
||||
pub struct ParityAccountsClient {
|
||||
@ -334,6 +334,17 @@ impl ParityAccounts for ParityAccountsClient {
|
||||
.map(Into::into)
|
||||
.map_err(|e| errors::account("Could not export account.", e))
|
||||
}
|
||||
|
||||
fn sign_message(&self, addr: RpcH160, password: String, message: RpcH256) -> Result<RpcH520, Error> {
|
||||
self.account_provider()?
|
||||
.sign(
|
||||
addr.into(),
|
||||
Some(password),
|
||||
message.into()
|
||||
)
|
||||
.map(Into::into)
|
||||
.map_err(|e| errors::account("Could not sign message.", e))
|
||||
}
|
||||
}
|
||||
|
||||
fn into_vec<A, B>(a: Vec<A>) -> Vec<B> where
|
||||
|
@ -140,7 +140,7 @@ impl<D: Dispatcher + 'static> ParitySigning for SigningQueueClient<D> {
|
||||
fn post_sign(&self, meta: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
|
||||
let pending = self.pending.clone();
|
||||
self.dispatch(
|
||||
RpcConfirmationPayload::Signature((address.clone(), data).into()),
|
||||
RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()),
|
||||
DefaultAccount::Provided(address.into()),
|
||||
meta.origin
|
||||
).map(move |result| match result {
|
||||
@ -216,7 +216,7 @@ impl<D: Dispatcher + 'static> EthSigning for SigningQueueClient<D> {
|
||||
|
||||
fn sign(&self, meta: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> {
|
||||
let res = self.dispatch(
|
||||
RpcConfirmationPayload::Signature((address.clone(), data).into()),
|
||||
RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()),
|
||||
address.into(),
|
||||
meta.origin,
|
||||
);
|
||||
|
@ -78,7 +78,7 @@ impl<D: Dispatcher + 'static> EthSigning for SigningUnsafeClient<D>
|
||||
type Metadata = Metadata;
|
||||
|
||||
fn sign(&self, _: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> {
|
||||
self.handle(RpcConfirmationPayload::Signature((address.clone(), data).into()), address.into())
|
||||
self.handle(RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()), address.into())
|
||||
.then(|res| match res {
|
||||
Ok(RpcConfirmationResponse::Signature(signature)) => Ok(signature),
|
||||
Err(e) => Err(e),
|
||||
|
@ -500,3 +500,20 @@ fn should_export_account() {
|
||||
println!("Response: {:?}", response);
|
||||
assert_eq!(result, Some(response.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_sign_message() {
|
||||
let tester = setup();
|
||||
let hash = tester.accounts
|
||||
.insert_account(
|
||||
"0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a".parse().unwrap(),
|
||||
"password1")
|
||||
.expect("account should be inserted ok");
|
||||
|
||||
assert_eq!(hash, "c171033d5cbff7175f29dfd3a63dda3d6f8f385e".parse().unwrap());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "parity_signMessage", "params": ["0xc171033d5cbff7175f29dfd3a63dda3d6f8f385e", "password1", "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"], "id": 3}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"0x1d9e33a8cf8bfc089a172bca01da462f9e359c6cb1b0f29398bc884e4d18df4f78588aee4fb5cc067ca62d2abab995e0bba29527be6ac98105b0320020a2efaf00","id":3}"#;
|
||||
let res = tester.io.handle_request_sync(&request);
|
||||
assert_eq!(res, Some(response.into()));
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ fn should_return_list_of_items_to_confirm() {
|
||||
nonce: None,
|
||||
condition: None,
|
||||
}), Origin::Dapps("http://parity.io".into())).unwrap();
|
||||
tester.signer.add_request(ConfirmationPayload::Signature(1.into(), vec![5].into()), Origin::Unknown).unwrap();
|
||||
tester.signer.add_request(ConfirmationPayload::EthSignMessage(1.into(), vec![5].into()), Origin::Unknown).unwrap();
|
||||
|
||||
// when
|
||||
let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#;
|
||||
@ -163,7 +163,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
||||
fn should_not_remove_sign_if_password_is_invalid() {
|
||||
// given
|
||||
let tester = signer_tester();
|
||||
tester.signer.add_request(ConfirmationPayload::Signature(0.into(), vec![5].into()), Origin::Unknown).unwrap();
|
||||
tester.signer.add_request(ConfirmationPayload::EthSignMessage(0.into(), vec![5].into()), Origin::Unknown).unwrap();
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
|
||||
// when
|
||||
|
@ -19,7 +19,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use ethstore::KeyFile;
|
||||
use v1::types::{H160, H256, DappId, DeriveHash, DeriveHierarchical};
|
||||
use v1::types::{H160, H256, H520, DappId, DeriveHash, DeriveHierarchical};
|
||||
|
||||
build_rpc_trait! {
|
||||
/// Personal Parity rpc interface.
|
||||
@ -180,5 +180,9 @@ build_rpc_trait! {
|
||||
/// Exports an account with given address if provided password matches.
|
||||
#[rpc(name = "parity_exportAccount")]
|
||||
fn export_account(&self, H160, String) -> Result<KeyFile, Error>;
|
||||
|
||||
/// Sign raw hash with the key corresponding to address and password.
|
||||
#[rpc(name = "parity_signMessage")]
|
||||
fn sign_message(&self, H160, String, H256) -> Result<H520, Error>;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ impl fmt::Display for ConfirmationPayload {
|
||||
match *self {
|
||||
ConfirmationPayload::SendTransaction(ref transaction) => write!(f, "{}", transaction),
|
||||
ConfirmationPayload::SignTransaction(ref transaction) => write!(f, "(Sign only) {}", transaction),
|
||||
ConfirmationPayload::Signature(ref sign) => write!(f, "{}", sign),
|
||||
ConfirmationPayload::EthSignMessage(ref sign) => write!(f, "{}", sign),
|
||||
ConfirmationPayload::Decrypt(ref decrypt) => write!(f, "{}", decrypt),
|
||||
}
|
||||
}
|
||||
@ -169,7 +169,7 @@ pub enum ConfirmationPayload {
|
||||
SignTransaction(TransactionRequest),
|
||||
/// Signature
|
||||
#[serde(rename="sign")]
|
||||
Signature(SignRequest),
|
||||
EthSignMessage(SignRequest),
|
||||
/// Decryption
|
||||
#[serde(rename="decrypt")]
|
||||
Decrypt(DecryptRequest),
|
||||
@ -180,7 +180,7 @@ impl From<helpers::ConfirmationPayload> for ConfirmationPayload {
|
||||
match c {
|
||||
helpers::ConfirmationPayload::SendTransaction(t) => ConfirmationPayload::SendTransaction(t.into()),
|
||||
helpers::ConfirmationPayload::SignTransaction(t) => ConfirmationPayload::SignTransaction(t.into()),
|
||||
helpers::ConfirmationPayload::Signature(address, data) => ConfirmationPayload::Signature(SignRequest {
|
||||
helpers::ConfirmationPayload::EthSignMessage(address, data) => ConfirmationPayload::EthSignMessage(SignRequest {
|
||||
address: address.into(),
|
||||
data: data.into(),
|
||||
}),
|
||||
@ -255,7 +255,7 @@ mod tests {
|
||||
// given
|
||||
let request = helpers::ConfirmationRequest {
|
||||
id: 15.into(),
|
||||
payload: helpers::ConfirmationPayload::Signature(1.into(), vec![5].into()),
|
||||
payload: helpers::ConfirmationPayload::EthSignMessage(1.into(), vec![5].into()),
|
||||
origin: Origin::Rpc("test service".into()),
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user