Files
iroh-forward/src/key.rs
T
skoandClaude Opus 4.8 ec7c96b092 Initial commit: iroh-forward TCP-over-Iroh forwarder
TCP-Forwarding über das Iroh-Netz (QUIC), adressiert per Public Key statt IP
(Umsetzung von Option B aus recherche-vpn-vs-p2p-netzwerk.md).

- server: nimmt Iroh-Verbindungen an, leitet QUIC-Streams an lokalen Port weiter
- client: lauscht lokal auf TCP, öffnet pro Verbindung einen QUIC-Stream zum Peer
- keygen: erzeugt Key-Datei und gibt EndpointId aus (Vorab-Verteilung)
- Allowlist (--allow) erlaubter Client-EndpointIds
- QUIC-Multiplexing, Reconnect mit Backoff, n0-Default-Relays + DNS-Discovery

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 14:25:15 +00:00

64 lines
1.9 KiB
Rust

//! Laden/Erzeugen und Persistieren des Iroh-SecretKeys (Node-Identität).
use std::path::Path;
use anyhow::{Context, Result};
use data_encoding::HEXLOWER;
use iroh::SecretKey;
/// Lädt den SecretKey aus `path` oder erzeugt einen neuen und speichert ihn.
///
/// Der Key bestimmt die EndpointId (= Public Key = Adresse im Iroh-Netz). Persistenz
/// ist wichtig, damit der Serving Host nach einem Neustart unter derselben Adresse
/// erreichbar bleibt.
pub fn load_or_create_secret_key(path: &Path) -> Result<SecretKey> {
if path.exists() {
let hex = std::fs::read_to_string(path)
.with_context(|| format!("Key-Datei lesen: {}", path.display()))?;
let bytes = HEXLOWER
.decode(hex.trim().as_bytes())
.context("Key-Datei ist kein gültiges Hex")?;
let arr: [u8; 32] = bytes
.as_slice()
.try_into()
.context("Key-Datei hat nicht 32 Bytes")?;
Ok(SecretKey::from_bytes(&arr))
} else {
let secret_key = SecretKey::generate();
let hex = HEXLOWER.encode(&secret_key.to_bytes());
write_secret(path, &hex)
.with_context(|| format!("Key-Datei schreiben: {}", path.display()))?;
Ok(secret_key)
}
}
#[cfg(unix)]
fn write_secret(path: &Path, hex: &str) -> Result<()> {
use std::io::Write;
use std::os::unix::fs::OpenOptionsExt;
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() {
std::fs::create_dir_all(parent)?;
}
}
let mut f = std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.mode(0o600)
.open(path)?;
f.write_all(hex.as_bytes())?;
Ok(())
}
#[cfg(not(unix))]
fn write_secret(path: &Path, hex: &str) -> Result<()> {
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() {
std::fs::create_dir_all(parent)?;
}
}
std::fs::write(path, hex)?;
Ok(())
}