Generate the TLS certificates in process

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
This commit is contained in:
irisandClaude Fable 5 committed 2026-08-25 04:36:54 -04:00
1 parent eeb2dde4ab
commit 65743b899d
8 files changed
+550 -175

No files matched your search

+8 -2
View File
@@ -12,7 +12,7 @@
//! holds only the metadata needed to list and respawn sessions.
use std::fs::File;
use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt};
use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt};
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
@@ -26,7 +26,13 @@ pub fn create_private_dir(dir: &Path) -> Result<()> {
.recursive(true)
.mode(0o700)
.create(dir)
.with_context(|| format!("create {}", dir.display()))
.with_context(|| format!("create {}", dir.display()))?;
// Set explicitly as well: `mode` applies only when the directory is
// created, so one that already existed -- made by hand, or by a
// version that didn't do this -- would otherwise keep whatever
// permissions it had while holding transcripts.
std::fs::set_permissions(dir, std::fs::Permissions::from_mode(0o700))
.with_context(|| format!("restrict {}", dir.display()))
}
/// Opens `path` for writing, creating it owner-readable only.