Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 06add13

Browse files
committedOct 30, 2023
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 bde02d7 commit 06add13

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
@@ -27,3 +27,6 @@ jsonrpc = "0.13.0"
2727
# Used for deserialization of JSON.
2828
serde = "1"
2929
serde_json = "1"
30+
31+
[dev-dependencies]
32+
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};
@@ -197,19 +198,16 @@ pub enum Auth {
197198
impl Auth {
198199
/// Convert into the arguments that jsonrpc::Client needs.
199200
pub fn get_user_pass(self) -> Result<(Option<String>, Option<String>)> {
200-
use std::io::Read;
201201
match self {
202202
Auth::None => Ok((None, None)),
203203
Auth::UserPass(u, p) => Ok((Some(u), Some(p))),
204204
Auth::CookieFile(path) => {
205-
let mut file = File::open(path)?;
206-
let mut contents = String::new();
207-
file.read_to_string(&mut contents)?;
208-
let mut split = contents.splitn(2, ":");
209-
Ok((
210-
Some(split.next().ok_or(Error::InvalidCookieFile)?.into()),
211-
Some(split.next().ok_or(Error::InvalidCookieFile)?.into()),
212-
))
205+
let line = BufReader::new(File::open(path)?)
206+
.lines()
207+
.next()
208+
.ok_or(Error::InvalidCookieFile)??;
209+
let colon = line.find(':').ok_or(Error::InvalidCookieFile)?;
210+
Ok((Some(line[..colon].into()), Some(line[colon + 1..].into())))
213211
}
214212
}
215213
}
@@ -1357,4 +1355,34 @@ mod tests {
13571355
fn test_handle_defaults() {
13581356
test_handle_defaults_inner().unwrap();
13591357
}
1358+
1359+
#[test]
1360+
fn auth_cookie_file_ignores_newline() {
1361+
let tempdir = tempfile::tempdir().unwrap();
1362+
let path = tempdir.path().join("cookie");
1363+
std::fs::write(&path, "foo:bar\n").unwrap();
1364+
assert_eq!(
1365+
Auth::CookieFile(path).get_user_pass().unwrap(),
1366+
(Some("foo".into()), Some("bar".into())),
1367+
);
1368+
}
1369+
1370+
#[test]
1371+
fn auth_cookie_file_ignores_additional_lines() {
1372+
let tempdir = tempfile::tempdir().unwrap();
1373+
let path = tempdir.path().join("cookie");
1374+
std::fs::write(&path, "foo:bar\nbaz").unwrap();
1375+
assert_eq!(
1376+
Auth::CookieFile(path).get_user_pass().unwrap(),
1377+
(Some("foo".into()), Some("bar".into())),
1378+
);
1379+
}
1380+
1381+
#[test]
1382+
fn auth_cookie_file_fails_if_colon_isnt_present() {
1383+
let tempdir = tempfile::tempdir().unwrap();
1384+
let path = tempdir.path().join("cookie");
1385+
std::fs::write(&path, "foobar").unwrap();
1386+
assert!(matches!(Auth::CookieFile(path).get_user_pass(), Err(Error::InvalidCookieFile)));
1387+
}
13601388
}

0 commit comments

Comments
 (0)
Please sign in to comment.