gen-dev-cert.sh is gone. The server ensures its own certificates on start, which removes a setup step to remember, a dependency on whatever openssl was installed, and a second place for the "which addresses?" answer to live -- the leaf now covers every local IPv4 plus loopback and the emulator's host alias, so nobody maintains a hardcoded IP. The split that mattered in the script is kept and now enforced by tests: the CA is generated once and left alone, because the app pins it and replacing it strands every installed copy; the leaf is cheap and reissued every start, so covering a new address is a restart. Both are written owner-only into a directory outside the repo. Two things the tests caught. DirBuilder's mode applies only when the directory is created, so a directory that already existed kept whatever permissions it had while holding a private key -- the mode is now set explicitly, in the session directories too. And loading the leaf into the real RustlsConfig needs the crypto provider installed, which main does but tests don't. Verified end to end: deleted the certs, started the server, watched it generate a CA and warn that installed apps now pin the wrong one, rebuilt the APK against the new CA, and reinstalled -- the emulator connects over a certificate that never existed as a pasted constant. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017xn8nHw1tw1R6PtiY1eEtw
55 lines
2.2 KiB
TOML
55 lines
2.2 KiB
TOML
[package]
|
|
name = "ai-server"
|
|
version = "0.1.0"
|
|
edition = "2024"
|
|
|
|
[[bin]]
|
|
name = "ai-server"
|
|
path = "src/main.rs"
|
|
|
|
[dependencies]
|
|
axum = { version = "0.8", features = ["json", "multipart"] }
|
|
axum-server = { version = "0.8", features = ["tls-rustls"] }
|
|
tokio = { version = "1", features = ["rt-multi-thread", "macros", "net", "sync", "time", "process", "io-util"] }
|
|
tokio-stream = "0.1"
|
|
tracing = "0.1"
|
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
clap = { version = "4", features = ["derive"] }
|
|
anyhow = "1"
|
|
thiserror = "2"
|
|
# Token auth: hash for storage, constant-time compare for verification,
|
|
# CSPRNG-backed generation, base64url for the enrollment string.
|
|
sha2 = "0.11"
|
|
subtle = "2"
|
|
rand = "0.10"
|
|
base64 = "0.23"
|
|
# Renders the enrollment QR straight to the terminal; no image output needed.
|
|
qrcode = { version = "0.14", default-features = false }
|
|
# The wg0-bound listener needs the interface's address; the stdlib has no
|
|
# getifaddrs. This is the smallest crate that wraps just that.
|
|
if-addrs = "0.15"
|
|
# Generates this server's TLS certificates on first start, replacing a
|
|
# setup script that shelled out to whatever openssl happened to be
|
|
# installed. In process means one place decides the extensions, the file
|
|
# modes, and which addresses the leaf covers. x509-parser so the issuer is
|
|
# read back from the CA actually on disk: reconstructing it from the same
|
|
# parameters would work only as long as nothing ever changed them, and a
|
|
# mismatched issuer name yields a chain that fails to validate rather than
|
|
# anything that looks wrong at generation time.
|
|
rcgen = { version = "0.14", features = ["pem", "x509-parser"] }
|
|
# Outbound HTTPS for the usage endpoint. A small blocking client fits an
|
|
# every-few-minutes poll better than pulling in reqwest's tower stack;
|
|
# rustls-backed like the rest of the TLS here.
|
|
ureq = "3"
|
|
# Direct dependency only to pick the process-level CryptoProvider in main:
|
|
# ureq pulls rustls-with-ring, axum-server rustls-with-aws-lc-rs, and with
|
|
# both in the graph rustls refuses to auto-select one.
|
|
rustls = "0.23"
|
|
|
|
[dev-dependencies]
|
|
tempfile = "3"
|
|
# ServiceExt::oneshot, to drive the auth middleware without a socket.
|
|
tower = { version = "0.5", features = ["util"] }
|