mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 10:11:44 +00:00
Merge branch 'unstable' of https://github.com/sigp/lighthouse into single_attestation
This commit is contained in:
@@ -8,18 +8,14 @@ use eth2_wallet::{
|
||||
};
|
||||
use filesystem::{create_with_600_perms, Error as FsError};
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs::{self, File};
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::from_utf8;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
str::FromStr,
|
||||
};
|
||||
use zeroize::Zeroize;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
pub mod validator_definitions;
|
||||
|
||||
@@ -69,8 +65,8 @@ pub fn read_password<P: AsRef<Path>>(path: P) -> Result<PlainText, io::Error> {
|
||||
fs::read(path).map(strip_off_newlines).map(Into::into)
|
||||
}
|
||||
|
||||
/// Reads a password file into a `ZeroizeString` struct, with new-lines removed.
|
||||
pub fn read_password_string<P: AsRef<Path>>(path: P) -> Result<ZeroizeString, String> {
|
||||
/// Reads a password file into a `Zeroizing<String>` struct, with new-lines removed.
|
||||
pub fn read_password_string<P: AsRef<Path>>(path: P) -> Result<Zeroizing<String>, String> {
|
||||
fs::read(path)
|
||||
.map_err(|e| format!("Error opening file: {:?}", e))
|
||||
.map(strip_off_newlines)
|
||||
@@ -112,8 +108,8 @@ pub fn random_password() -> PlainText {
|
||||
random_password_raw_string().into_bytes().into()
|
||||
}
|
||||
|
||||
/// Generates a random alphanumeric password of length `DEFAULT_PASSWORD_LEN` as `ZeroizeString`.
|
||||
pub fn random_password_string() -> ZeroizeString {
|
||||
/// Generates a random alphanumeric password of length `DEFAULT_PASSWORD_LEN` as `Zeroizing<String>`.
|
||||
pub fn random_password_string() -> Zeroizing<String> {
|
||||
random_password_raw_string().into()
|
||||
}
|
||||
|
||||
@@ -141,7 +137,7 @@ pub fn strip_off_newlines(mut bytes: Vec<u8>) -> Vec<u8> {
|
||||
}
|
||||
|
||||
/// Reads a password from TTY or stdin if `use_stdin == true`.
|
||||
pub fn read_password_from_user(use_stdin: bool) -> Result<ZeroizeString, String> {
|
||||
pub fn read_password_from_user(use_stdin: bool) -> Result<Zeroizing<String>, String> {
|
||||
let result = if use_stdin {
|
||||
rpassword::prompt_password_stderr("")
|
||||
.map_err(|e| format!("Error reading from stdin: {}", e))
|
||||
@@ -150,7 +146,7 @@ pub fn read_password_from_user(use_stdin: bool) -> Result<ZeroizeString, String>
|
||||
.map_err(|e| format!("Error reading from tty: {}", e))
|
||||
};
|
||||
|
||||
result.map(ZeroizeString::from)
|
||||
result.map(Zeroizing::from)
|
||||
}
|
||||
|
||||
/// Reads a mnemonic phrase from TTY or stdin if `use_stdin == true`.
|
||||
@@ -210,46 +206,6 @@ pub fn mnemonic_from_phrase(phrase: &str) -> Result<Mnemonic, String> {
|
||||
Mnemonic::from_phrase(phrase, Language::English).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Provides a new-type wrapper around `String` that is zeroized on `Drop`.
|
||||
///
|
||||
/// Useful for ensuring that password memory is zeroed-out on drop.
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Zeroize)]
|
||||
#[zeroize(drop)]
|
||||
#[serde(transparent)]
|
||||
pub struct ZeroizeString(String);
|
||||
|
||||
impl FromStr for ZeroizeString {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(s.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for ZeroizeString {
|
||||
fn from(s: String) -> Self {
|
||||
Self(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl ZeroizeString {
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Remove any number of newline or carriage returns from the end of a vector of bytes.
|
||||
pub fn without_newlines(&self) -> ZeroizeString {
|
||||
let stripped_string = self.0.trim_end_matches(['\r', '\n']).into();
|
||||
Self(stripped_string)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for ZeroizeString {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_mnemonic_from_cli(
|
||||
mnemonic_path: Option<PathBuf>,
|
||||
stdin_inputs: bool,
|
||||
@@ -294,54 +250,6 @@ pub fn read_mnemonic_from_cli(
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_zeroize_strip_off() {
|
||||
let expected = "hello world";
|
||||
|
||||
assert_eq!(
|
||||
ZeroizeString::from("hello world\n".to_string())
|
||||
.without_newlines()
|
||||
.as_str(),
|
||||
expected
|
||||
);
|
||||
assert_eq!(
|
||||
ZeroizeString::from("hello world\n\n\n\n".to_string())
|
||||
.without_newlines()
|
||||
.as_str(),
|
||||
expected
|
||||
);
|
||||
assert_eq!(
|
||||
ZeroizeString::from("hello world\r".to_string())
|
||||
.without_newlines()
|
||||
.as_str(),
|
||||
expected
|
||||
);
|
||||
assert_eq!(
|
||||
ZeroizeString::from("hello world\r\r\r\r\r".to_string())
|
||||
.without_newlines()
|
||||
.as_str(),
|
||||
expected
|
||||
);
|
||||
assert_eq!(
|
||||
ZeroizeString::from("hello world\r\n".to_string())
|
||||
.without_newlines()
|
||||
.as_str(),
|
||||
expected
|
||||
);
|
||||
assert_eq!(
|
||||
ZeroizeString::from("hello world\r\n\r\n".to_string())
|
||||
.without_newlines()
|
||||
.as_str(),
|
||||
expected
|
||||
);
|
||||
assert_eq!(
|
||||
ZeroizeString::from("hello world".to_string())
|
||||
.without_newlines()
|
||||
.as_str(),
|
||||
expected
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_off() {
|
||||
let expected = b"hello world".to_vec();
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
//! Serves as the source-of-truth of which validators this validator client should attempt (or not
|
||||
//! attempt) to load into the `crate::intialized_validators::InitializedValidators` struct.
|
||||
|
||||
use crate::{
|
||||
default_keystore_password_path, read_password_string, write_file_via_temporary, ZeroizeString,
|
||||
};
|
||||
use crate::{default_keystore_password_path, read_password_string, write_file_via_temporary};
|
||||
use directory::ensure_dir_exists;
|
||||
use eth2_keystore::Keystore;
|
||||
use regex::Regex;
|
||||
@@ -17,6 +15,7 @@ use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use types::{graffiti::GraffitiString, Address, PublicKey};
|
||||
use validator_dir::VOTING_KEYSTORE_FILE;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
/// The file name for the serialized `ValidatorDefinitions` struct.
|
||||
pub const CONFIG_FILENAME: &str = "validator_definitions.yml";
|
||||
@@ -52,7 +51,7 @@ pub enum Error {
|
||||
/// Defines how a password for a validator keystore will be persisted.
|
||||
pub enum PasswordStorage {
|
||||
/// Store the password in the `validator_definitions.yml` file.
|
||||
ValidatorDefinitions(ZeroizeString),
|
||||
ValidatorDefinitions(Zeroizing<String>),
|
||||
/// Store the password in a separate, dedicated file (likely in the "secrets" directory).
|
||||
File(PathBuf),
|
||||
/// Don't store the password at all.
|
||||
@@ -93,7 +92,7 @@ pub enum SigningDefinition {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
voting_keystore_password_path: Option<PathBuf>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
voting_keystore_password: Option<ZeroizeString>,
|
||||
voting_keystore_password: Option<Zeroizing<String>>,
|
||||
},
|
||||
/// A validator that defers to a Web3Signer HTTP server for signing.
|
||||
///
|
||||
@@ -107,7 +106,7 @@ impl SigningDefinition {
|
||||
matches!(self, SigningDefinition::LocalKeystore { .. })
|
||||
}
|
||||
|
||||
pub fn voting_keystore_password(&self) -> Result<Option<ZeroizeString>, Error> {
|
||||
pub fn voting_keystore_password(&self) -> Result<Option<Zeroizing<String>>, Error> {
|
||||
match self {
|
||||
SigningDefinition::LocalKeystore {
|
||||
voting_keystore_password: Some(password),
|
||||
|
||||
@@ -16,10 +16,7 @@ lighthouse_network = { workspace = true }
|
||||
proto_array = { workspace = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
eth2_keystore = { workspace = true }
|
||||
libsecp256k1 = { workspace = true }
|
||||
ring = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
account_utils = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use super::types::*;
|
||||
use crate::Error;
|
||||
use account_utils::ZeroizeString;
|
||||
use reqwest::{
|
||||
header::{HeaderMap, HeaderValue},
|
||||
IntoUrl,
|
||||
@@ -14,6 +13,7 @@ use std::path::Path;
|
||||
pub use reqwest;
|
||||
pub use reqwest::{Response, StatusCode, Url};
|
||||
use types::graffiti::GraffitiString;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
/// A wrapper around `reqwest::Client` which provides convenience methods for interfacing with a
|
||||
/// Lighthouse Validator Client HTTP server (`validator_client/src/http_api`).
|
||||
@@ -21,7 +21,7 @@ use types::graffiti::GraffitiString;
|
||||
pub struct ValidatorClientHttpClient {
|
||||
client: reqwest::Client,
|
||||
server: SensitiveUrl,
|
||||
api_token: Option<ZeroizeString>,
|
||||
api_token: Option<Zeroizing<String>>,
|
||||
authorization_header: AuthorizationHeader,
|
||||
}
|
||||
|
||||
@@ -79,18 +79,18 @@ impl ValidatorClientHttpClient {
|
||||
}
|
||||
|
||||
/// Get a reference to this client's API token, if any.
|
||||
pub fn api_token(&self) -> Option<&ZeroizeString> {
|
||||
pub fn api_token(&self) -> Option<&Zeroizing<String>> {
|
||||
self.api_token.as_ref()
|
||||
}
|
||||
|
||||
/// Read an API token from the specified `path`, stripping any trailing whitespace.
|
||||
pub fn load_api_token_from_file(path: &Path) -> Result<ZeroizeString, Error> {
|
||||
pub fn load_api_token_from_file(path: &Path) -> Result<Zeroizing<String>, Error> {
|
||||
let token = fs::read_to_string(path).map_err(|e| Error::TokenReadError(path.into(), e))?;
|
||||
Ok(ZeroizeString::from(token.trim_end().to_string()))
|
||||
Ok(token.trim_end().to_string().into())
|
||||
}
|
||||
|
||||
/// Add an authentication token to use when making requests.
|
||||
pub fn add_auth_token(&mut self, token: ZeroizeString) -> Result<(), Error> {
|
||||
pub fn add_auth_token(&mut self, token: Zeroizing<String>) -> Result<(), Error> {
|
||||
self.api_token = Some(token);
|
||||
self.authorization_header = AuthorizationHeader::Bearer;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use account_utils::ZeroizeString;
|
||||
use eth2_keystore::Keystore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use types::{Address, Graffiti, PublicKeyBytes};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
pub use slashing_protection::interchange::Interchange;
|
||||
|
||||
@@ -41,7 +41,7 @@ pub struct SingleKeystoreResponse {
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ImportKeystoresRequest {
|
||||
pub keystores: Vec<KeystoreJsonStr>,
|
||||
pub passwords: Vec<ZeroizeString>,
|
||||
pub passwords: Vec<Zeroizing<String>>,
|
||||
pub slashing_protection: Option<InterchangeJsonStr>,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use account_utils::ZeroizeString;
|
||||
pub use crate::lighthouse::Health;
|
||||
pub use crate::lighthouse_vc::std_types::*;
|
||||
pub use crate::types::{GenericResponse, VersionData};
|
||||
use eth2_keystore::Keystore;
|
||||
use graffiti::GraffitiString;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub use crate::lighthouse::Health;
|
||||
pub use crate::lighthouse_vc::std_types::*;
|
||||
pub use crate::types::{GenericResponse, VersionData};
|
||||
pub use types::*;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ValidatorData {
|
||||
@@ -44,7 +43,7 @@ pub struct ValidatorRequest {
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct CreateValidatorsMnemonicRequest {
|
||||
pub mnemonic: ZeroizeString,
|
||||
pub mnemonic: Zeroizing<String>,
|
||||
#[serde(with = "serde_utils::quoted_u32")]
|
||||
pub key_derivation_path_offset: u32,
|
||||
pub validators: Vec<ValidatorRequest>,
|
||||
@@ -74,7 +73,7 @@ pub struct CreatedValidator {
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PostValidatorsResponseData {
|
||||
pub mnemonic: ZeroizeString,
|
||||
pub mnemonic: Zeroizing<String>,
|
||||
pub validators: Vec<CreatedValidator>,
|
||||
}
|
||||
|
||||
@@ -102,7 +101,7 @@ pub struct ValidatorPatchRequest {
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct KeystoreValidatorsPostRequest {
|
||||
pub password: ZeroizeString,
|
||||
pub password: Zeroizing<String>,
|
||||
pub enable: bool,
|
||||
pub keystore: Keystore,
|
||||
#[serde(default)]
|
||||
@@ -191,7 +190,7 @@ pub struct SingleExportKeystoresResponse {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub validating_keystore: Option<KeystoreJsonStr>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub validating_keystore_password: Option<ZeroizeString>,
|
||||
pub validating_keystore_password: Option<Zeroizing<String>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
||||
Reference in New Issue
Block a user