1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-21 18:55:36 +02:00

fix: address 6 code-review findings

NixOS module (4 fixes):
- Remove RestrictNamespaces=true: Chromium (launched by single-file for
  web captures) needs Linux user namespaces; blocking them broke captures
- Escape TOML string values: labels/paths with quotes or backslashes
  would produce invalid archivr-server.toml and prevent startup
- Bracket IPv6 listen addresses: ::1:8080 is rejected by Rust's
  SocketAddr parser; [::1]:8080 is the correct form (RFC 2732)
- Add optional storePath per archive: covers archives initialised with
  a custom store path outside the default sibling store/ directory

Rust (1 fix):
- extract_client_ip loopback branch: take last XFF value not first.
  When a proxy appends to X-Forwarded-For an attacker controls the
  first entry; the last entry is always set by the trusted local proxy

Frontend (1 fix):
- Gate fetchArchives on authState === 'authenticated'. The empty-dep
  useEffect fired on mount (before login), hit 401, and never retried
  after login because authState was not in the dependency array
This commit is contained in:
TheGeneralist 2026-06-29 21:30:45 +02:00
parent 71e176cbd1
commit 9544e707ed
Signed by: thegeneralist01
SSH key fingerprint: SHA256:pp9qddbCNmVNoSjevdvQvM5z0DHN7LTa8qBMbcMq/R4
3 changed files with 35 additions and 11 deletions

View file

@ -174,13 +174,15 @@ fn extract_client_ip(req: &Request) -> IpAddr {
match peer_ip {
// Peer is a loopback address → the connection came from a local
// reverse proxy (nginx/caddy on the same host). Trust the first
// address in X-Forwarded-For as the real client IP.
// reverse proxy (nginx/caddy on the same host). Trust the last
// address in X-Forwarded-For as the real client IP — the last entry
// is always appended by the trusted proxy, even if the client sent a
// spoofed value earlier in the chain.
Some(peer) if peer.is_loopback() => req
.headers()
.get("x-forwarded-for")
.and_then(|v| v.to_str().ok())
.and_then(|s| s.split(',').next())
.and_then(|s| s.split(',').last())
.and_then(|s| s.trim().parse().ok())
.unwrap_or(peer),