Skip to content

Commit 56be35f

Browse files
authored
Merge pull request #214 from benthecarman/400-perm-files
Create secret files with private modes
2 parents 06c40b5 + a5d187e commit 56be35f

3 files changed

Lines changed: 59 additions & 11 deletions

File tree

ldk-server/src/main.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ mod util;
1414

1515
use std::collections::HashSet;
1616
use std::fs;
17-
use std::os::unix::fs::PermissionsExt;
1817
use std::path::{Path, PathBuf};
1918
use std::sync::Arc;
2019
use std::time::{Duration, SystemTime, UNIX_EPOCH};
@@ -56,6 +55,7 @@ use crate::util::metrics::Metrics;
5655
use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto};
5756
use crate::util::systemd;
5857
use crate::util::tls::get_or_generate_tls_config;
58+
use crate::util::write_new;
5959

6060
const API_KEY_FILE: &str = "api_key";
6161

@@ -834,12 +834,7 @@ fn load_or_generate_api_key(storage_dir: &Path) -> std::io::Result<String> {
834834
let mut key_bytes = [0u8; 32];
835835
getrandom::getrandom(&mut key_bytes).map_err(std::io::Error::other)?;
836836

837-
// Write the raw bytes to the file
838-
fs::write(&api_key_path, key_bytes)?;
839-
840-
// Set permissions to 0400 (read-only for owner)
841-
let permissions = fs::Permissions::from_mode(0o400);
842-
fs::set_permissions(&api_key_path, permissions)?;
837+
write_new(&api_key_path, &key_bytes, 0o400)?;
843838

844839
debug!("Generated new API key at {}", api_key_path.display());
845840
Ok(key_bytes.to_lower_hex_string())

ldk-server/src/util/mod.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,57 @@ pub(crate) mod metrics;
1313
pub(crate) mod proto_adapter;
1414
pub(crate) mod systemd;
1515
pub(crate) mod tls;
16+
17+
use std::fs::{self, OpenOptions};
18+
use std::io::{self, Write};
19+
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
20+
use std::path::Path;
21+
22+
pub(crate) fn write_new(path: &Path, contents: &[u8], mode: u32) -> io::Result<()> {
23+
let mut file = OpenOptions::new().create_new(true).write(true).mode(mode).open(path)?;
24+
file.write_all(contents)?;
25+
fs::set_permissions(path, fs::Permissions::from_mode(mode))?;
26+
file.sync_all()?;
27+
Ok(())
28+
}
29+
30+
#[cfg(test)]
31+
mod tests {
32+
use super::*;
33+
use std::path::PathBuf;
34+
35+
#[test]
36+
fn write_new_sets_requested_mode_and_contents() {
37+
let dir = test_dir("mode_and_contents");
38+
let path = dir.join("secret");
39+
40+
write_new(&path, b"secret-bytes", 0o400).unwrap();
41+
42+
assert_eq!(fs::read(&path).unwrap(), b"secret-bytes");
43+
assert_eq!(fs::metadata(&path).unwrap().permissions().mode() & 0o777, 0o400);
44+
45+
fs::remove_dir_all(dir).unwrap();
46+
}
47+
48+
#[test]
49+
fn write_new_does_not_replace_existing_file() {
50+
let dir = test_dir("existing_file");
51+
let path = dir.join("secret");
52+
fs::write(&path, b"original").unwrap();
53+
54+
let err = write_new(&path, b"replacement", 0o400).unwrap_err();
55+
56+
assert_eq!(err.kind(), io::ErrorKind::AlreadyExists);
57+
assert_eq!(fs::read(&path).unwrap(), b"original");
58+
59+
fs::remove_dir_all(dir).unwrap();
60+
}
61+
62+
fn test_dir(name: &str) -> PathBuf {
63+
let dir = std::env::temp_dir()
64+
.join(format!("ldk-server-secure-file-test-{name}-{}", std::process::id()));
65+
let _ = fs::remove_dir_all(&dir);
66+
fs::create_dir(&dir).unwrap();
67+
dir
68+
}
69+
}

ldk-server/src/util/tls.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
use std::fs;
1111
use std::net::IpAddr;
12-
use std::os::unix::fs::PermissionsExt;
12+
use std::path::Path;
1313

1414
use base64::Engine;
1515
use ring::rand::SystemRandom;
@@ -18,6 +18,7 @@ use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer};
1818
use tokio_rustls::rustls::ServerConfig;
1919

2020
use crate::util::config::TlsConfig;
21+
use crate::util::write_new;
2122

2223
// Issuer and Subject common name
2324
const ISSUER_NAME: &str = "localhost";
@@ -133,10 +134,8 @@ fn generate_self_signed_cert(
133134
let cert_pem = der_to_pem(&cert_der, PEM_CERT_BEGIN, PEM_CERT_END);
134135
let key_pem = der_to_pem(pkcs8_doc.as_ref(), PEM_KEY_BEGIN, PEM_KEY_END);
135136

136-
fs::write(key_path, &key_pem)
137+
write_new(Path::new(key_path), key_pem.as_bytes(), 0o400)
137138
.map_err(|e| format!("Failed to write TLS key to '{key_path}': {e}"))?;
138-
fs::set_permissions(key_path, fs::Permissions::from_mode(0o400))
139-
.map_err(|e| format!("Failed to set TLS key permissions for '{key_path}': {e}"))?;
140139
fs::write(cert_path, &cert_pem)
141140
.map_err(|e| format!("Failed to write TLS certificate to '{cert_path}': {e}"))?;
142141

0 commit comments

Comments
 (0)