Archive remote_signer code (#2559)

## Proposed Changes

This PR deletes all `remote_signer` code from Lighthouse, for the following reasons:

* The `remote_signer` code is unused, and we have no plans to use it now that we're moving to supporting the Web3Signer APIs: #2522
* It represents a significant maintenance burden. The HTTP API tests have been prone to platform-specific failures, and breakages due to dependency upgrades, e.g. #2400.

Although the code is deleted it remains in the Git history should we ever want to recover it. For ease of reference:

- The last commit containing remote signer code: 5a3bcd2904
- The last Lighthouse version: v1.5.1
This commit is contained in:
Michael Sproul
2021-09-03 06:09:18 +00:00
parent d9910f96c5
commit f4aa1d8aea
50 changed files with 0 additions and 4958 deletions

View File

@@ -1,16 +0,0 @@
[package]
name = "remote_signer_consumer"
version = "0.2.0"
authors = ["Herman Junge <herman@sigmaprime.io>"]
edition = "2018"
[dev-dependencies]
rand = "0.7.3"
remote_signer_test = { path = "../../testing/remote_signer_test" }
[dependencies]
reqwest = { version = "0.11.0", features = ["json"] }
serde = { version = "1.0.116", features = ["derive"] }
tokio = { version = "1.10.0", features = ["time"] }
types = { path = "../../consensus/types" }
sensitive_url = { path = "../sensitive_url" }

View File

@@ -1,89 +0,0 @@
use crate::{
Error, RemoteSignerObject, RemoteSignerRequestBody, RemoteSignerResponseBodyError,
RemoteSignerResponseBodyOK,
};
use reqwest::StatusCode;
pub use reqwest::Url;
use sensitive_url::SensitiveUrl;
use types::{Domain, Fork, Hash256};
/// A wrapper around `reqwest::Client` which provides convenience methods
/// to interface with a BLS Remote Signer.
pub struct RemoteSignerHttpConsumer {
client: reqwest::Client,
server: SensitiveUrl,
}
impl RemoteSignerHttpConsumer {
pub fn from_components(server: SensitiveUrl, client: reqwest::Client) -> Self {
Self { client, server }
}
/// `POST /sign/:public-key`
///
/// # Arguments
///
/// * `public_key` - Goes within the url to identify the key we want to use as signer.
/// * `bls_domain` - BLS Signature domain. Supporting `BeaconProposer`, `BeaconAttester`,`Randao`.
/// * `data` - A `BeaconBlock`, `AttestationData`, or `Epoch`.
/// * `fork` - A `Fork` object containing previous and current versions.
/// * `genesis_validators_root` - A `Hash256` for domain separation and chain versioning.
///
/// It sends through the wire a serialized `RemoteSignerRequestBody`.
pub async fn sign<R: RemoteSignerObject>(
&self,
public_key: &str,
bls_domain: Domain,
data: R,
fork: Fork,
genesis_validators_root: Hash256,
) -> Result<String, Error> {
if public_key.is_empty() {
return Err(Error::InvalidParameter(
"Empty parameter public_key".to_string(),
));
}
let mut path = self.server.full.clone();
path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("sign")
.push(public_key);
let bls_domain = match bls_domain {
Domain::BeaconProposer => data.validate_object(bls_domain),
Domain::BeaconAttester => data.validate_object(bls_domain),
Domain::Randao => data.validate_object(bls_domain),
_ => Err(Error::InvalidParameter(format!(
"Unsupported BLS Domain: {:?}",
bls_domain
))),
}?;
let body = RemoteSignerRequestBody {
bls_domain,
data,
fork,
genesis_validators_root,
};
let response = self
.client
.post(path)
.json(&body)
.send()
.await
.map_err(Error::Reqwest)?;
match response.status() {
StatusCode::OK => match response.json::<RemoteSignerResponseBodyOK>().await {
Ok(resp_json) => Ok(resp_json.signature),
Err(e) => Err(Error::Reqwest(e)),
},
_ => match response.json::<RemoteSignerResponseBodyError>().await {
Ok(resp_json) => Err(Error::ServerMessage(resp_json.error)),
Err(e) => Err(Error::Reqwest(e)),
},
}
}
}

View File

@@ -1,213 +0,0 @@
//! Enables the [Lighthouse Ethereum 2.0 Client] to consume signatures from the
//! [BLS Remote Signer].
//!
//! ## About
//!
//! The lighthouse client needs to include this crate, and implement the
//! adequate bypasses and CLI flags needed to find the remote signer and perform
//! the HTTP requests.
//!
//! As defined by the [EIP-3030] specification, this crate will take the
//! received object data and parameters, and send them to the remote signer
//! for the production of a signing root hash and signature (the latter if the
//! signer has in storage the key identified at request).
//!
//! ## Usage
//!
//! ### RemoteSignerHttpConsumer
//!
//! Just provide an `Url` and a timeout
//!
//! ```
//! use remote_signer_consumer::RemoteSignerHttpConsumer;
//! use reqwest::ClientBuilder;
//! use sensitive_url::SensitiveUrl;
//! use tokio::time::Duration;
//!
//! let url = SensitiveUrl::parse("http://127.0.0.1:9000").unwrap();
//! let reqwest_client = ClientBuilder::new()
//! .timeout(Duration::from_secs(2))
//! .build()
//! .unwrap();
//!
//! let signer = RemoteSignerHttpConsumer::from_components(url, reqwest_client);
//!
//! ```
//!
//! ## sign API
//!
//! `POST /sign/:identifier`
//!
//! ### Arguments
//!
//! #### `public_key`
//!
//! Goes within the url to identify the key we want to use as signer.
//!
//! #### `bls_domain`
//!
//! [BLS Signature domain]. Supporting `BeaconProposer`, `BeaconAttester`,
//! `Randao`.
//!
//! #### `data`
//!
//! A `BeaconBlock`, `AttestationData`, or `Epoch`.
//!
//! #### `fork`
//!
//! A [`Fork`] object, containing previous and current versions.
//!
//! #### `genesis_validators_root`
//!
//! A [`Hash256`] for domain separation and chain versioning.
//!
//! ### Behavior
//!
//! Upon receiving and validating the parameters, the signer sends through the
//! wire a serialized `RemoteSignerRequestBody`. Receiving a `200` message with
//! the `signature` field inside a JSON payload, or an error.
//!
//! ## How it works
//!
//! The production of a _local_ signature (i.e. inside the Lighthouse client)
//! has slight variations among the kind of objects (block, attestation,
//! randao).
//!
//! To sign a message, the following procedures are needed:
//!
//! * Get the `fork_version` - From the objects `Fork` and `Epoch`.
//! * Compute the [`fork_data_root`] - From the `fork_version` and the
//! `genesis_validators_root`.
//! * Compute the [`domain`] - From the `fork_data_root` and the `bls_domain`.
//! * With the `domain`, the object (or `epoch` in the case of [`randao`])
//! can be merkelized into its [`signing_root`] to be signed.
//!
//! In short, to obtain a signature from the remote signer, we need to produce
//! (and serialize) the following objects:
//!
//! * `bls_domain`.
//! * `data` of the object, if this is a block proposal, an attestation, or an epoch.
//! * `epoch`, obtained from the object.
//! * `fork`.
//! * `genesis_validators_root`.
//!
//! And, of course, the identifier of the secret key, the `public_key`.
//!
//! ## Future Work
//!
//! ### EIP-3030
//!
//! Work is being done to [standardize the API of the remote signers].
//!
//! [`domain`]: https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#compute_domain
//! [`Epoch`]: https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
//! [`fork_data_root`]: https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#compute_fork_data_root
//! [`Fork`]: https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#fork
//! [`Hash256`]: https://docs.rs/ethereum-types/0.9.2/ethereum_types/struct.H256.html
//! [`randao`]: https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#randao
//! [`signing_root`]: https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#compute_signing_root
//! [BLS Remote Signer]: https://github.com/sigp/rust-bls-remote-signer
//! [BLS Signature domain]: https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#domain-types
//! [EIP-3030]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3030.md
//! [Lighthouse Ethereum 2.0 Client]: https://github.com/sigp/lighthouse
//! [standardize the API of the remote signers]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3030.md
mod http_client;
pub use http_client::RemoteSignerHttpConsumer;
pub use reqwest::Url;
use sensitive_url::SensitiveUrl;
use serde::{Deserialize, Serialize};
use types::{AttestationData, BeaconBlock, Domain, Epoch, EthSpec, Fork, Hash256, SignedRoot};
#[derive(Debug)]
pub enum Error {
/// The `reqwest` client raised an error.
Reqwest(reqwest::Error),
/// The server returned an error message where the body was able to be parsed.
ServerMessage(String),
/// The supplied URL is badly formatted. It should look something like `http://127.0.0.1:5052`.
InvalidUrl(SensitiveUrl),
/// The supplied parameter is invalid.
InvalidParameter(String),
}
#[derive(Serialize)]
struct RemoteSignerRequestBody<T> {
/// BLS Signature domain. Supporting `BeaconProposer`, `BeaconAttester`,`Randao`.
bls_domain: String,
/// A `BeaconBlock`, `AttestationData`, or `Epoch`.
data: T,
/// A `Fork` object containing previous and current versions.
fork: Fork,
/// A `Hash256` for domain separation and chain versioning.
genesis_validators_root: Hash256,
}
#[derive(Deserialize)]
struct RemoteSignerResponseBodyOK {
signature: String,
}
#[derive(Deserialize)]
struct RemoteSignerResponseBodyError {
error: String,
}
/// Allows the verification of the BeaconBlock and AttestationData objects
/// to be sent through the wire, against their BLS Domains.
pub trait RemoteSignerObject: SignedRoot + Serialize {
fn validate_object(&self, domain: Domain) -> Result<String, Error>;
fn get_epoch(&self) -> Epoch;
}
impl<E: EthSpec> RemoteSignerObject for BeaconBlock<E> {
fn validate_object(&self, domain: Domain) -> Result<String, Error> {
match domain {
Domain::BeaconProposer => Ok("beacon_proposer".to_string()),
_ => Err(Error::InvalidParameter(format!(
"Domain mismatch for the BeaconBlock object. Expected BeaconProposer, got {:?}",
domain
))),
}
}
fn get_epoch(&self) -> Epoch {
self.epoch()
}
}
impl RemoteSignerObject for AttestationData {
fn validate_object(&self, domain: Domain) -> Result<String, Error> {
match domain {
Domain::BeaconAttester => Ok("beacon_attester".to_string()),
_ => Err(Error::InvalidParameter(format!(
"Domain mismatch for the AttestationData object. Expected BeaconAttester, got {:?}",
domain
))),
}
}
fn get_epoch(&self) -> Epoch {
self.target.epoch
}
}
impl RemoteSignerObject for Epoch {
fn validate_object(&self, domain: Domain) -> Result<String, Error> {
match domain {
Domain::Randao => Ok("randao".to_string()),
_ => Err(Error::InvalidParameter(format!(
"Domain mismatch for the Epoch object. Expected Randao, got {:?}",
domain
))),
}
}
fn get_epoch(&self) -> Epoch {
*self
}
}

View File

@@ -1,181 +0,0 @@
mod message_preparation {
use remote_signer_consumer::Error;
use remote_signer_test::*;
use types::Domain;
#[test]
fn beacon_block_and_bls_domain_mismatch() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
macro_rules! test_case {
($f: expr, $bls_domain: expr, $msg: expr) => {
match do_sign_request(&test_client, get_input_data_and_set_domain($f, $bls_domain))
.unwrap_err()
{
Error::InvalidParameter(message) => assert_eq!(message, $msg),
e => panic!("{:?}", e),
}
};
}
test_case!(
get_input_data_block,
Domain::BeaconAttester,
"Domain mismatch for the BeaconBlock object. Expected BeaconProposer, got BeaconAttester"
);
test_case!(
get_input_data_block,
Domain::Randao,
"Domain mismatch for the BeaconBlock object. Expected BeaconProposer, got Randao"
);
test_case!(
get_input_data_attestation,
Domain::BeaconProposer,
"Domain mismatch for the AttestationData object. Expected BeaconAttester, got BeaconProposer"
);
test_case!(
get_input_data_attestation,
Domain::Randao,
"Domain mismatch for the AttestationData object. Expected BeaconAttester, got Randao"
);
test_case!(
get_input_data_randao,
Domain::BeaconProposer,
"Domain mismatch for the Epoch object. Expected Randao, got BeaconProposer"
);
test_case!(
get_input_data_randao,
Domain::BeaconAttester,
"Domain mismatch for the Epoch object. Expected Randao, got BeaconAttester"
);
test_signer.shutdown();
}
#[test]
fn empty_public_key_parameter() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
macro_rules! test_case {
($f: expr, $p: expr, $msg: expr) => {
match do_sign_request(&test_client, get_input_data_and_set_public_key($f, $p))
.unwrap_err()
{
Error::InvalidParameter(message) => assert_eq!(message, $msg),
e => panic!("{:?}", e),
}
};
}
test_case!(get_input_data_block, "", "Empty parameter public_key");
test_case!(get_input_data_attestation, "", "Empty parameter public_key");
test_case!(get_input_data_randao, "", "Empty parameter public_key");
test_signer.shutdown();
}
#[test]
fn invalid_public_key_param() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
macro_rules! test_case {
($f: expr, $p: expr, $msg: expr) => {
match do_sign_request(&test_client, get_input_data_and_set_public_key($f, $p))
.unwrap_err()
{
Error::ServerMessage(message) => assert_eq!(message, $msg),
e => panic!("{:?}", e),
}
};
}
test_case!(get_input_data_block, "/", "Invalid public key: %2F");
test_case!(get_input_data_attestation, "/", "Invalid public key: %2F");
test_case!(get_input_data_randao, "/", "Invalid public key: %2F");
test_case!(get_input_data_block, "//", "Invalid public key: %2F%2F");
test_case!(get_input_data_block, "///", "Invalid public key: %2F%2F%2F");
test_case!(
get_input_data_block,
"/?'or 1 = 1 --",
"Invalid public key: %2F%3F\'or%201%20=%201%20--"
);
test_signer.shutdown();
}
#[test]
fn unsupported_bls_domain() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_case = |bls_domain, msg| {
let mut test_input = get_input_data_block(0xc137);
test_input.bls_domain = bls_domain;
let signature = do_sign_request(&test_client, test_input);
match signature.unwrap_err() {
Error::InvalidParameter(message) => assert_eq!(message, msg),
e => panic!("{:?}", e),
}
};
test_case(Domain::Deposit, "Unsupported BLS Domain: Deposit");
test_case(
Domain::VoluntaryExit,
"Unsupported BLS Domain: VoluntaryExit",
);
test_case(
Domain::SelectionProof,
"Unsupported BLS Domain: SelectionProof",
);
test_case(
Domain::AggregateAndProof,
"Unsupported BLS Domain: AggregateAndProof",
);
test_signer.shutdown();
}
#[test]
fn invalid_public_key_param_additional_path_segments() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
macro_rules! test_case {
($f: expr, $p: expr, $msg: expr) => {
match do_sign_request(&test_client, get_input_data_and_set_public_key($f, $p))
.unwrap_err()
{
Error::ServerMessage(message) => assert_eq!(message, $msg),
e => panic!("{:?}", e),
}
};
}
test_case!(
get_input_data_block,
"this/receipt",
"Invalid public key: this%2Freceipt"
);
test_case!(
get_input_data_attestation,
"/this/receipt/please",
"Invalid public key: %2Fthis%2Freceipt%2Fplease"
);
test_case!(
get_input_data_randao,
"this/receipt/please?",
"Invalid public key: this%2Freceipt%2Fplease%3F"
);
test_case!(
get_input_data_block,
&format!("{}/valid/pk", PUBLIC_KEY_1),
format!("Invalid public key: {}%2Fvalid%2Fpk", PUBLIC_KEY_1)
);
test_signer.shutdown();
}
}

View File

@@ -1,168 +0,0 @@
mod mock {
use remote_signer_consumer::Error;
use remote_signer_test::*;
#[test]
fn timeout() {
let mock_server =
set_up_mock_server_with_timeout(200, "{\"signature\":\"irrelevant_value\"}", 2);
let test_client = set_up_test_consumer_with_timeout(&mock_server.url(""), 1);
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap_err();
match r {
Error::Reqwest(e) => {
let error_msg = e.to_string();
assert!(error_msg.contains("error sending request for url (http://127.0.0.1:"));
assert!(error_msg.contains("/sign/"));
assert!(error_msg.contains(PUBLIC_KEY_1));
assert!(error_msg.contains("): operation timed out"));
}
e => panic!("{:?}", e),
}
}
#[test]
fn no_json_in_ok_response() {
let mock_server = set_up_mock_server(200, "NO JSON");
let test_client = set_up_test_consumer(&mock_server.url(""));
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap_err();
match r {
Error::Reqwest(e) => {
let error_msg = e.to_string();
assert_eq!(
error_msg,
"error decoding response body: expected value at line 1 column 1"
);
}
e => panic!("{:?}", e),
}
}
#[test]
fn missing_signature_in_ok_json() {
let mock_server = set_up_mock_server(200, "{\"foo\":\"bar\"}");
let test_client = set_up_test_consumer(&mock_server.url(""));
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap_err();
match r {
Error::Reqwest(e) => {
let error_msg = e.to_string();
assert_eq!(
error_msg,
"error decoding response body: missing field `signature` at line 1 column 13"
);
}
e => panic!("{:?}", e),
}
}
#[test]
fn empty_signature_in_ok_json() {
let mock_server = set_up_mock_server(200, "{\"signature\":\"\"}");
let test_client = set_up_test_consumer(&mock_server.url(""));
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap();
assert_eq!(r, "");
}
#[test]
fn extra_fields_in_ok_json() {
let mock_server = set_up_mock_server(
200,
&format!(
"{{\"signature\":\"{}\", \"foo\":\"bar\", \"red\":\"green\"}}",
EXPECTED_SIGNATURE_1
),
);
let test_client = set_up_test_consumer(&mock_server.url(""));
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap();
assert_eq!(r, EXPECTED_SIGNATURE_1);
}
#[test]
fn no_json_in_error_response() {
let mock_server = set_up_mock_server(500, "NO JSON");
let test_client = set_up_test_consumer(&mock_server.url(""));
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap_err();
match r {
Error::Reqwest(e) => {
let error_msg = e.to_string();
assert_eq!(
error_msg,
"error decoding response body: expected value at line 1 column 1"
);
}
e => panic!("{:?}", e),
}
}
#[test]
fn missing_error_field_in_error_json() {
let mock_server = set_up_mock_server(500, "{\"foo\":\"bar\"}");
let test_client = set_up_test_consumer(&mock_server.url(""));
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap_err();
match r {
Error::Reqwest(e) => {
let error_msg = e.to_string();
assert_eq!(
error_msg,
"error decoding response body: missing field `error` at line 1 column 13"
);
}
e => panic!("{:?}", e),
}
}
#[test]
fn empty_error_field_in_error_json() {
let mock_server = set_up_mock_server(500, "{\"error\":\"\"}");
let test_client = set_up_test_consumer(&mock_server.url(""));
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap_err();
match r {
Error::ServerMessage(msg) => {
assert_eq!(msg, "");
}
e => panic!("{:?}", e),
}
}
#[test]
fn extra_fields_in_error_json() {
let mock_server = set_up_mock_server(
500,
"{\"error\":\"some_error_msg\", \"foo\":\"bar\", \"red\":\"green\"}",
);
let test_client = set_up_test_consumer(&mock_server.url(""));
let test_input = get_input_data_block(0xc137);
let r = do_sign_request(&test_client, test_input).unwrap_err();
match r {
Error::ServerMessage(msg) => {
assert_eq!(msg, "some_error_msg");
}
e => panic!("{:?}", e),
}
}
}

View File

@@ -1,242 +0,0 @@
mod post {
use remote_signer_consumer::{Error, RemoteSignerHttpConsumer};
use remote_signer_test::*;
use reqwest::ClientBuilder;
use sensitive_url::SensitiveUrl;
use tokio::time::Duration;
#[test]
fn server_unavailable() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
test_signer.shutdown();
let test_input = get_input_data_block(0xc137);
let signature = do_sign_request(&test_client, test_input);
match signature.unwrap_err() {
Error::Reqwest(e) => {
let error_msg = e.to_string();
let pubkey_string = PUBLIC_KEY_1.to_string();
let msgs = vec![
"error sending request for url",
&pubkey_string,
"error trying to connect",
"tcp connect error",
match cfg!(windows) {
true => "No connection could be made because the target machine actively refused it",
false => "Connection refused",
}
];
for msg in msgs.iter() {
assert!(
error_msg.contains(msg),
"{:?} should contain {:?}",
error_msg,
msg
);
}
}
e => panic!("{:?}", e),
}
}
#[test]
fn server_error() {
let (test_signer, tmp_dir) = set_up_api_test_signer_to_sign_message();
restrict_permissions(tmp_dir.path());
restrict_permissions(&tmp_dir.path().join(PUBLIC_KEY_1));
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_block(0xc137);
let signature = do_sign_request(&test_client, test_input);
unrestrict_permissions(tmp_dir.path());
unrestrict_permissions(&tmp_dir.path().join(PUBLIC_KEY_1));
match signature.unwrap_err() {
Error::ServerMessage(message) => assert_eq!(message, "Storage error: PermissionDenied"),
e => panic!("{:?}", e),
}
test_signer.shutdown();
}
#[test]
fn invalid_url() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let run_testcase = |u: &str| -> Result<String, String> {
let url = SensitiveUrl::parse(u).map_err(|e| format!("{:?}", e))?;
let reqwest_client = ClientBuilder::new()
.timeout(Duration::from_secs(12))
.build()
.unwrap();
let test_client = RemoteSignerHttpConsumer::from_components(url, reqwest_client);
let test_input = get_input_data_block(0xc137);
let signature = do_sign_request(&test_client, test_input);
signature.map_err(|e| match e {
Error::InvalidUrl(message) => format!("{:?}", message),
Error::Reqwest(re) => {
if re.is_builder() {
format!("[Reqwest - Builder] {:?}", re.url().unwrap())
} else if re.is_request() {
format!("[Reqwest - Request] {:?}", re.url().unwrap())
} else {
format!("[Reqwest] {:?}", re)
}
}
_ => format!("{:?}", e),
})
};
let testcase = |u: &str, msg: &str| assert_eq!(run_testcase(u).unwrap_err(), msg);
// url::parser::ParseError.
// These cases don't even make it to the step of building a RemoteSignerHttpConsumer.
testcase("", "ParseError(RelativeUrlWithoutBase)");
testcase("/4/8/15/16/23/42", "ParseError(RelativeUrlWithoutBase)");
testcase("localhost", "ParseError(RelativeUrlWithoutBase)");
testcase(":", "ParseError(RelativeUrlWithoutBase)");
testcase("0.0:0", "ParseError(RelativeUrlWithoutBase)");
testcase(":aa", "ParseError(RelativeUrlWithoutBase)");
testcase("0:", "ParseError(RelativeUrlWithoutBase)");
testcase("ftp://", "ParseError(EmptyHost)");
testcase("http://", "ParseError(EmptyHost)");
testcase("http://127.0.0.1:abcd", "ParseError(InvalidPort)");
testcase("http://280.0.0.1", "ParseError(InvalidIpv4Address)");
// `Error::InvalidUrl`.
// The RemoteSignerHttpConsumer is created, but fails at `path_segments_mut()`.
testcase("localhost:abcd", "InvalidUrl(\"URL cannot be a base.\")");
testcase("localhost:", "InvalidUrl(\"URL cannot be a base.\")");
// `Reqwest::Error` of the `Builder` kind.
// POST is not made.
testcase(
"unix:/run/foo.socket",
&format!(
"[Reqwest - Builder] Url {{ scheme: \"unix\", cannot_be_a_base: false, username: \"\", password: None, host: None, port: None, path: \"/run/foo.socket/sign/{}\", query: None, fragment: None }}",
PUBLIC_KEY_1
),
);
// `Reqwest::Error` of the `Request` kind.
testcase(
"http://127.0.0.1:0",
&format!(
"[Reqwest - Request] Url {{ scheme: \"http\", cannot_be_a_base: false, username: \"\", password: None, host: Some(Ipv4(127.0.0.1)), port: Some(0), path: \"/sign/{}\", query: None, fragment: None }}",
PUBLIC_KEY_1
),
);
test_signer.shutdown();
}
#[test]
fn wrong_url() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let run_testcase = |u: &str| -> Result<String, String> {
let url = SensitiveUrl::parse(u).unwrap();
let reqwest_client = ClientBuilder::new()
.timeout(Duration::from_secs(12))
.build()
.unwrap();
let test_client = RemoteSignerHttpConsumer::from_components(url, reqwest_client);
let test_input = get_input_data_block(0xc137);
let signature = do_sign_request(&test_client, test_input);
signature.map_err(|e| format!("{:?}", e))
};
let testcase = |u: &str, msgs: Vec<&str>| {
let r = run_testcase(u).unwrap_err();
for msg in msgs.iter() {
assert!(r.contains(msg), "{:?} should contain {:?}", r, msg);
}
};
testcase(
"http://error-dns",
vec![
"reqwest::Error",
"kind: Request",
&format!("/sign/{}", PUBLIC_KEY_1),
"hyper::Error(Connect, ConnectError",
"dns error",
match cfg!(windows) {
true => "No such host is known.",
false => "failed to lookup address information",
},
],
);
test_signer.shutdown();
}
#[test]
fn wrong_public_key() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let mut test_input = get_input_data_block(0xc137);
test_input.public_key = ABSENT_PUBLIC_KEY.to_string();
let signature = do_sign_request(&test_client, test_input);
match signature.unwrap_err() {
Error::ServerMessage(msg) => {
assert_eq!(msg, format!("Key not found: {}", ABSENT_PUBLIC_KEY))
}
e => panic!("{:?}", e),
}
}
#[test]
fn invalid_secret_key() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let mut test_input = get_input_data_block(0xc137);
test_input.public_key = PUBLIC_KEY_FOR_INVALID_SECRET_KEY.to_string();
let signature = do_sign_request(&test_client, test_input);
match signature.unwrap_err() {
Error::ServerMessage(msg) => assert_eq!(
msg,
format!(
"Invalid secret key: public_key: {}; Invalid hex character: W at index 0",
PUBLIC_KEY_FOR_INVALID_SECRET_KEY
)
),
e => panic!("{:?}", e),
}
}
#[test]
fn key_mismatch() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let mut test_input = get_input_data_block(0xc137);
test_input.public_key = MISMATCHED_PUBLIC_KEY.to_string();
let signature = do_sign_request(&test_client, test_input);
match signature.unwrap_err() {
Error::ServerMessage(msg) => {
assert_eq!(msg, format!("Key mismatch: {}", MISMATCHED_PUBLIC_KEY))
}
e => panic!("{:?}", e),
}
}
}

View File

@@ -1,49 +0,0 @@
mod sign_attestation {
use rand::Rng;
use remote_signer_test::*;
#[test]
fn sanity_check_deterministic() {
let test_input_local = get_input_local_signer_attestation(0xc137);
let local_signature = test_input_local.sign();
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_attestation(0xc137);
let remote_signature = do_sign_request(&test_client, test_input);
assert_eq!(local_signature, remote_signature.unwrap());
assert_eq!(local_signature, HAPPY_PATH_ATT_SIGNATURE_C137);
}
#[test]
fn sanity_check_random() {
let mut rng = rand::thread_rng();
let seed = rng.gen::<u64>() / 1024;
let test_input_local = get_input_local_signer_attestation(seed);
let local_signature = test_input_local.sign();
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_attestation(seed);
let remote_signature = do_sign_request(&test_client, test_input);
assert_eq!(local_signature, remote_signature.unwrap());
}
#[test]
fn happy_path() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_attestation(0xc137);
let signature = do_sign_request(&test_client, test_input);
assert_eq!(signature.unwrap(), HAPPY_PATH_ATT_SIGNATURE_C137);
test_signer.shutdown();
}
}

View File

@@ -1,49 +0,0 @@
mod sign_block {
use rand::Rng;
use remote_signer_test::*;
#[test]
fn sanity_check_deterministic() {
let test_input_local = get_input_local_signer_block(0xc137);
let local_signature = test_input_local.sign();
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_block(0xc137);
let remote_signature = do_sign_request(&test_client, test_input);
assert_eq!(local_signature, remote_signature.unwrap());
assert_eq!(local_signature, HAPPY_PATH_BLOCK_SIGNATURE_C137);
}
#[test]
fn sanity_check_random() {
let mut rng = rand::thread_rng();
let seed = rng.gen::<u64>() / 1024;
let test_input_local = get_input_local_signer_block(seed);
let local_signature = test_input_local.sign();
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_block(seed);
let remote_signature = do_sign_request(&test_client, test_input);
assert_eq!(local_signature, remote_signature.unwrap());
}
#[test]
fn happy_path() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_block(0xc137);
let signature = do_sign_request(&test_client, test_input);
assert_eq!(signature.unwrap(), HAPPY_PATH_BLOCK_SIGNATURE_C137);
test_signer.shutdown();
}
}

View File

@@ -1,50 +0,0 @@
mod sign_randao {
use rand::Rng;
use remote_signer_test::*;
#[test]
fn sanity_check_deterministic() {
let test_input_local = get_input_local_signer_randao(0xc137);
let local_signature = test_input_local.sign();
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_randao(0xc137);
let remote_signature = do_sign_request(&test_client, test_input);
assert_eq!(local_signature, remote_signature.unwrap());
assert_eq!(local_signature, HAPPY_PATH_RANDAO_SIGNATURE_C137);
}
#[test]
fn sanity_check_random() {
let mut rng = rand::thread_rng();
let seed = rng.gen::<u64>();
let test_input_local = get_input_local_signer_randao(seed);
let local_signature = test_input_local.sign();
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_randao(seed);
let remote_signature = do_sign_request(&test_client, test_input);
assert_eq!(local_signature, remote_signature.unwrap());
}
#[test]
fn happy_path() {
let (test_signer, _tmp_dir) = set_up_api_test_signer_to_sign_message();
let test_client = set_up_test_consumer(&test_signer.address);
let test_input = get_input_data_randao(0xc137);
let remote_signature = do_sign_request(&test_client, test_input);
assert_eq!(remote_signature.unwrap(), HAPPY_PATH_RANDAO_SIGNATURE_C137);
}
}