lighthouse/common/remote_signer_consumer/tests/post.rs
ethDreamer ba55e140ae Enable Compatibility with Windows (#2333)
## Issue Addressed

Windows incompatibility.

## Proposed Changes

On windows, lighthouse needs to default to STDIN as tty doesn't exist. Also Windows uses ACLs for file permissions. So to mirror chmod 600, we will remove every entry in a file's ACL and add only a single SID that is an alias for the file owner.

Beyond that, there were several changes made to different unit tests because windows has slightly different error messages as well as frustrating nuances around killing a process :/

## Additional Info

Tested on my Windows VM and it appears to work, also compiled & tested on Linux with these changes. Permissions look correct on both platforms now. Just waiting for my validator to activate on Prater so I can test running full validator client on windows.

Co-authored-by: ethDreamer <37123614+ethDreamer@users.noreply.github.com>
Co-authored-by: Michael Sproul <micsproul@gmail.com>
2021-05-19 23:05:16 +00:00

243 lines
8.8 KiB
Rust

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\", 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\", 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),
}
}
}