Skip to content

Commit f5512ae

Browse files
committed
Reproduce Bitcoin Core's handling of cookie files
Bitcoin Core uses a single call to std::getline to read the contents of cookie files, making it ignore newlines in the file, as well as ignore any lines after the first. This reproduces that behavior, so that all cookie files that work with Bitcoin Core should work with this library.
1 parent 7bd815f commit f5512ae

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

client/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@ jsonrpc = "0.14.0"
2828
serde = "1"
2929
serde_json = "1"
3030
bitcoin-private = "0.1.0"
31+
32+
[dev-dependencies]
33+
tempfile = "3.3.0"

client/src/client.rs

+37-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use std::collections::HashMap;
1212
use std::fs::File;
13+
use std::io::{BufRead, BufReader};
1314
use std::iter::FromIterator;
1415
use std::path::PathBuf;
1516
use std::{fmt, result};
@@ -201,19 +202,16 @@ pub enum Auth {
201202
impl Auth {
202203
/// Convert into the arguments that jsonrpc::Client needs.
203204
pub fn get_user_pass(self) -> Result<(Option<String>, Option<String>)> {
204-
use std::io::Read;
205205
match self {
206206
Auth::None => Ok((None, None)),
207207
Auth::UserPass(u, p) => Ok((Some(u), Some(p))),
208208
Auth::CookieFile(path) => {
209-
let mut file = File::open(path)?;
210-
let mut contents = String::new();
211-
file.read_to_string(&mut contents)?;
212-
let mut split = contents.splitn(2, ":");
213-
Ok((
214-
Some(split.next().ok_or(Error::InvalidCookieFile)?.into()),
215-
Some(split.next().ok_or(Error::InvalidCookieFile)?.into()),
216-
))
209+
let line = BufReader::new(File::open(path)?)
210+
.lines()
211+
.next()
212+
.ok_or(Error::InvalidCookieFile)??;
213+
let colon = line.find(':').ok_or(Error::InvalidCookieFile)?;
214+
Ok((Some(line[..colon].into()), Some(line[colon + 1..].into())))
217215
}
218216
}
219217
}
@@ -1429,4 +1427,34 @@ mod tests {
14291427
fn test_handle_defaults() {
14301428
test_handle_defaults_inner().unwrap();
14311429
}
1430+
1431+
#[test]
1432+
fn auth_cookie_file_ignores_newline() {
1433+
let tempdir = tempfile::tempdir().unwrap();
1434+
let path = tempdir.path().join("cookie");
1435+
std::fs::write(&path, "foo:bar\n").unwrap();
1436+
assert_eq!(
1437+
Auth::CookieFile(path).get_user_pass().unwrap(),
1438+
(Some("foo".into()), Some("bar".into())),
1439+
);
1440+
}
1441+
1442+
#[test]
1443+
fn auth_cookie_file_ignores_additional_lines() {
1444+
let tempdir = tempfile::tempdir().unwrap();
1445+
let path = tempdir.path().join("cookie");
1446+
std::fs::write(&path, "foo:bar\nbaz").unwrap();
1447+
assert_eq!(
1448+
Auth::CookieFile(path).get_user_pass().unwrap(),
1449+
(Some("foo".into()), Some("bar".into())),
1450+
);
1451+
}
1452+
1453+
#[test]
1454+
fn auth_cookie_file_fails_if_colon_isnt_present() {
1455+
let tempdir = tempfile::tempdir().unwrap();
1456+
let path = tempdir.path().join("cookie");
1457+
std::fs::write(&path, "foobar").unwrap();
1458+
assert!(matches!(Auth::CookieFile(path).get_user_pass(), Err(Error::InvalidCookieFile)));
1459+
}
14321460
}

0 commit comments

Comments
 (0)