zebra_rpc/server/
cookie.rs1use base64::{engine::general_purpose::STANDARD, Engine as _};
4use color_eyre::Result;
5use rand::RngCore;
6
7use std::{
8 fs::{remove_file, File},
9 io::Write,
10 path::Path,
11};
12
13#[cfg(unix)]
14use std::os::unix::fs::OpenOptionsExt;
15
16const FILE: &str = ".cookie";
18
19#[derive(Clone, Debug)]
21pub struct Cookie(String);
22
23impl Cookie {
24 pub fn authenticate(&self, passwd: String) -> bool {
26 *passwd == self.0
27 }
28}
29
30impl Default for Cookie {
31 fn default() -> Self {
32 let mut bytes = [0u8; 32];
33 rand::thread_rng().fill_bytes(&mut bytes);
34
35 Self(STANDARD.encode(bytes))
36 }
37}
38
39pub fn write_to_disk(cookie: &Cookie, dir: &Path) -> Result<()> {
44 std::fs::create_dir_all(dir)?;
45
46 let cookie_path = dir.join(FILE);
47
48 if cookie_path
49 .symlink_metadata()
50 .map(|m| m.file_type().is_symlink())
51 .unwrap_or(false)
52 {
53 return Err(color_eyre::eyre::eyre!(
54 "cookie path {cookie_path:?} is a symlink, refusing to write"
55 ));
56 }
57
58 let mut file = create_owner_only_file(&cookie_path)?;
59 file.write_all(format!("__cookie__:{}", cookie.0).as_bytes())?;
60
61 tracing::info!("RPC auth cookie written to disk");
62
63 Ok(())
64}
65
66fn create_owner_only_file(path: &Path) -> Result<File> {
72 let mut opts = std::fs::OpenOptions::new();
73 opts.write(true).create(true).truncate(true);
74
75 #[cfg(unix)]
76 opts.mode(0o600);
77
78 Ok(opts.open(path)?)
79}
80
81pub fn remove_from_disk(dir: &Path) -> Result<()> {
83 remove_file(dir.join(FILE))?;
84
85 tracing::info!("RPC auth cookie removed from disk");
86
87 Ok(())
88}