diff --git a/client/Cargo.toml b/client/Cargo.toml index 1728b77a..7b55d406 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -28,3 +28,6 @@ jsonrpc = "0.14.0" serde = "1" serde_json = "1" bitcoin-private = "0.1.0" + +[dev-dependencies] +tempfile = "3.3.0" diff --git a/client/src/client.rs b/client/src/client.rs index edb71e30..47c648c6 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -10,6 +10,7 @@ use std::collections::HashMap; use std::fs::File; +use std::io::{BufRead, BufReader}; use std::iter::FromIterator; use std::path::PathBuf; use std::{fmt, result}; @@ -201,19 +202,16 @@ pub enum Auth { impl Auth { /// Convert into the arguments that jsonrpc::Client needs. pub fn get_user_pass(self) -> Result<(Option, Option)> { - use std::io::Read; match self { Auth::None => Ok((None, None)), Auth::UserPass(u, p) => Ok((Some(u), Some(p))), Auth::CookieFile(path) => { - let mut file = File::open(path)?; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - let mut split = contents.splitn(2, ":"); - Ok(( - Some(split.next().ok_or(Error::InvalidCookieFile)?.into()), - Some(split.next().ok_or(Error::InvalidCookieFile)?.into()), - )) + let line = BufReader::new(File::open(path)?) + .lines() + .next() + .ok_or(Error::InvalidCookieFile)??; + let colon = line.find(':').ok_or(Error::InvalidCookieFile)?; + Ok((Some(line[..colon].into()), Some(line[colon + 1..].into()))) } } } @@ -1429,4 +1427,34 @@ mod tests { fn test_handle_defaults() { test_handle_defaults_inner().unwrap(); } + + #[test] + fn auth_cookie_file_ignores_newline() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("cookie"); + std::fs::write(&path, "foo:bar\n").unwrap(); + assert_eq!( + Auth::CookieFile(path).get_user_pass().unwrap(), + (Some("foo".into()), Some("bar".into())), + ); + } + + #[test] + fn auth_cookie_file_ignores_additional_lines() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("cookie"); + std::fs::write(&path, "foo:bar\nbaz").unwrap(); + assert_eq!( + Auth::CookieFile(path).get_user_pass().unwrap(), + (Some("foo".into()), Some("bar".into())), + ); + } + + #[test] + fn auth_cookie_file_fails_if_colon_isnt_present() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("cookie"); + std::fs::write(&path, "foobar").unwrap(); + assert!(matches!(Auth::CookieFile(path).get_user_pass(), Err(Error::InvalidCookieFile))); + } } diff --git a/contrib/test.sh b/contrib/test.sh index 0e9f243c..87c766d9 100755 --- a/contrib/test.sh +++ b/contrib/test.sh @@ -15,6 +15,7 @@ fi # Test pinned versions (these are from rust-bitcoin pinning for 1.48). if cargo --version | grep ${MSRV}; then + cargo update -p tempfile --precise 3.3.0 cargo update -p log --precise 0.4.18 cargo update -p serde_json --precise 1.0.99 cargo update -p serde --precise 1.0.156 @@ -36,4 +37,3 @@ else cargo test --verbose cargo build --verbose --examples fi -