[verified] fix(hs): redact onion in publish logs; cache 0700
All checks were successful
ci / test (pull_request) Successful in 3m0s
All checks were successful
ci / test (pull_request) Successful in 3m0s
wait_until_published now logs HsId via safelog, not the locator. Store and client_config mkdir Arti cache/state 0700. Arti dangerously_trust_everyone stays on storage only.
This commit is contained in:
parent
bfd28fce6b
commit
424002c0f5
6 changed files with 56 additions and 8 deletions
24
src/hs.rs
24
src/hs.rs
|
|
@ -1,5 +1,6 @@
|
|||
//! In-process Arti onion-service helpers (no C-tor).
|
||||
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
|
|
@ -8,7 +9,7 @@ use arti_client::{TorClient, TorClientConfig};
|
|||
use futures::StreamExt;
|
||||
use safelog::DisplayRedacted;
|
||||
use tor_hsservice::status::State;
|
||||
use tor_hsservice::{HsNickname, OnionServiceConfig, RunningOnionService};
|
||||
use tor_hsservice::{HsId, HsNickname, OnionServiceConfig, RunningOnionService};
|
||||
use tor_rtcompat::PreferredRuntime;
|
||||
|
||||
pub const HS_PORT: u16 = 80;
|
||||
|
|
@ -28,9 +29,24 @@ const PROBE_TIMEOUT: Duration = Duration::from_secs(12);
|
|||
|
||||
pub type Client = Arc<TorClient<PreferredRuntime>>;
|
||||
|
||||
fn mkdir_700(path: &std::path::Path) {
|
||||
std::fs::create_dir_all(path).expect("mkdir");
|
||||
let mut perms = std::fs::metadata(path).expect("metadata").permissions();
|
||||
perms.set_mode(0o700);
|
||||
std::fs::set_permissions(path, perms).expect("chmod 0700");
|
||||
}
|
||||
|
||||
/// Status/probe log label: safelog-redacted v3 onion, never the locator.
|
||||
pub fn log_label(onion: &str) -> String {
|
||||
match onion.parse::<HsId>() {
|
||||
Ok(id) => id.display_redacted().to_string(),
|
||||
Err(_) => safelog::sensitive(onion).to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn client_config(state_dir: &std::path::Path, cache_dir: &std::path::Path) -> TorClientConfig {
|
||||
std::fs::create_dir_all(state_dir).expect("state dir");
|
||||
std::fs::create_dir_all(cache_dir).expect("cache dir");
|
||||
mkdir_700(state_dir);
|
||||
mkdir_700(cache_dir);
|
||||
let mut builder = TorClientConfigBuilder::from_directories(state_dir, cache_dir);
|
||||
builder.storage().permissions().dangerously_trust_everyone();
|
||||
builder
|
||||
|
|
@ -84,8 +100,8 @@ pub async fn wait_until_published(
|
|||
client: &Client,
|
||||
svc: &RunningOnionService,
|
||||
onion: &str,
|
||||
label: &str,
|
||||
) -> Result<(), String> {
|
||||
let label = log_label(onion);
|
||||
let deadline = Instant::now() + PUBLISH_WAIT;
|
||||
let mut events = svc.status_events();
|
||||
let mut next_probe = Instant::now() + PROBE_EVERY;
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ impl Node {
|
|||
_svc: Arc::clone(&svc),
|
||||
rend,
|
||||
});
|
||||
hs::wait_until_published(&node.client, &svc, &onion, &onion).await?;
|
||||
hs::wait_until_published(&node.client, &svc, &onion).await?;
|
||||
node.store
|
||||
.lock()
|
||||
.map_err(|e| e.to_string())?
|
||||
|
|
@ -444,7 +444,7 @@ impl Node {
|
|||
_svc: Arc::clone(&svc),
|
||||
rend,
|
||||
});
|
||||
hs::wait_until_published(&self.client, &svc, &onion, &onion).await?;
|
||||
hs::wait_until_published(&self.client, &svc, &onion).await?;
|
||||
{
|
||||
let store = self.store.lock().map_err(|e| e.to_string())?;
|
||||
store.set_onion(&onion).map_err(|e| e.to_string())?;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ impl Store {
|
|||
}
|
||||
mkdir_700(home)?;
|
||||
mkdir_700(&home.join("arti"))?;
|
||||
mkdir_700(&home.join("cache"))?;
|
||||
let db_path = home.join("onionwire.db");
|
||||
let conn = Connection::open(&db_path)?;
|
||||
let journal: String = conn.query_row("PRAGMA journal_mode = WAL", [], |row| row.get(0))?;
|
||||
|
|
|
|||
28
tests/hs.rs
28
tests/hs.rs
|
|
@ -1,5 +1,6 @@
|
|||
//! HS publish wait and CBT floor — 180s fail-closed cuts a working HsDir upload.
|
||||
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::time::Duration;
|
||||
|
||||
use onionwire::hs;
|
||||
|
|
@ -67,3 +68,30 @@ fn broken_or_shutdown_never_ready() {
|
|||
assert!(!hs::hs_is_ready(State::Broken, true));
|
||||
assert!(!hs::hs_is_ready(State::Shutdown, true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hs_log_label_is_not_the_full_v3_onion() {
|
||||
// Public v3 address; checksum is valid so HsId::from_str works.
|
||||
let onion = "facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion";
|
||||
let label = hs::log_label(onion);
|
||||
assert_ne!(label, onion, "status/probe logs must not use the locator");
|
||||
assert!(
|
||||
!label.contains("facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd"),
|
||||
"log label leaked the onion body: {label}"
|
||||
);
|
||||
assert!(
|
||||
label.contains('…') || label.contains("[scrubbed]"),
|
||||
"expected safelog redaction, got {label}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client_config_mkdirs_state_and_cache_0700() {
|
||||
let root = tempfile::tempdir().expect("tempdir");
|
||||
let state = root.path().join("arti");
|
||||
let cache = root.path().join("cache");
|
||||
let _cfg = hs::client_config(&state, &cache);
|
||||
let mode = |p: &std::path::Path| std::fs::metadata(p).unwrap().permissions().mode() & 0o777;
|
||||
assert_eq!(mode(&state), 0o700);
|
||||
assert_eq!(mode(&cache), 0o700);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,11 +55,14 @@ fn first_run_creates_0700_dirs_and_self_row() {
|
|||
let store = Store::open().expect("open");
|
||||
|
||||
let arti = home.path().join("arti");
|
||||
let cache = home.path().join("cache");
|
||||
let db = home.path().join("onionwire.db");
|
||||
assert!(arti.is_dir(), "arti dir");
|
||||
assert!(cache.is_dir(), "cache dir");
|
||||
assert!(db.is_file(), "onionwire.db");
|
||||
assert_eq!(mode(home.path()), 0o700);
|
||||
assert_eq!(mode(&arti), 0o700);
|
||||
assert_eq!(mode(&cache), 0o700);
|
||||
|
||||
let me = store.self_identity().expect("self");
|
||||
assert_eq!(me.identity_pk.len(), 32);
|
||||
|
|
|
|||
|
|
@ -124,10 +124,10 @@ async fn two_node_byte_pipe_restart_and_dormant() {
|
|||
eprintln!("bob onion={bob_onion}");
|
||||
assert_ne!(alice_onion, bob_onion, "separate HS identities");
|
||||
|
||||
hs::wait_until_published(&alice, &alice_svc, &alice_onion, "alice")
|
||||
hs::wait_until_published(&alice, &alice_svc, &alice_onion)
|
||||
.await
|
||||
.expect("alice publish");
|
||||
hs::wait_until_published(&bob, &bob_svc, &bob_onion, "bob")
|
||||
hs::wait_until_published(&bob, &bob_svc, &bob_onion)
|
||||
.await
|
||||
.expect("bob publish");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue