don't use this until i actually make it good
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118//! shared async bring-up for the debug cli (and, later, the gui runtime).//!//! assembles the moving parts into a usable whole://! device key -> EndpointRecord -> RepoClient (oauth) -> IwakuraNode//!//! the device key is the iroh endpoint's ed25519 secret key. it is persisted//! alongside the oauth sessions in `auth.jsonl`'s directory, as raw bytes in//! `device.key`, mode 0600. this key IS the iroh identity: whoever holds it//! can act as this endpoint until the endpoint record is removed from the//! repo.
use std::path::PathBuf;
use ed25519_dalek::SigningKey;use thiserror::Error;
use crate::auth::{self, flow, store::JsonlSessionStore};use crate::lexicon::{DidKey, EndpointRecord, IWAKURA_ALPN_STR};use crate::net::{IwakuraNode, VerifyFn};use crate::repo::RepoClient;
#[derive(Error, Debug)]pub enum Error { #[error("i/o error: {0}")] Io(#[from] std::io::Error), #[error("auth error: {0}")] Auth(#[from] flow::Error), #[error("session store error: {0}")] Store(#[from] auth::store::Error), #[error("endpoint record error: {0}")] Endpoint(#[from] crate::lexicon::EndpointError), #[error("node error: {0}")] Node(#[from] crate::net::NodeError),}
/// path to the persisted iroh device key.pub fn device_key_file() -> PathBuf { auth::config_dir().join("device.key")}
/// load the persisted device key, generating and saving a fresh one if absent.pub fn load_or_create_device_key() -> Result<SigningKey, Error> { let path = device_key_file(); match std::fs::read(&path) { Ok(bytes) => { let arr: [u8; 32] = bytes .try_into() .map_err(|_| Error::Io(std::io::Error::new(std::io::ErrorKind::InvalidData, "device.key must be 32 bytes")))?; Ok(SigningKey::from_bytes(&arr)) } Err(e) if e.kind() == std::io::ErrorKind::NotFound => { let key = SigningKey::generate(&mut rand::rngs::OsRng); if let Some(parent) = path.parent() { std::fs::create_dir_all(parent)?; } // write with restrictive permissions: this is a private key. #[cfg(unix)] { use std::os::unix::fs::OpenOptionsExt; let mut f = std::fs::OpenOptions::new() .write(true) .create_new(true) .mode(0o600) .open(&path)?; std::io::Write::write_all(&mut f, &key.to_bytes())?; } #[cfg(not(unix))] { std::fs::write(&path, key.to_bytes())?; } Ok(key) } Err(e) => Err(Error::Io(e)), }}
/// create the endpoint record authorizing `device_key` for account `iss`.pub fn make_endpoint_record(iss: &str, device_key: &SigningKey) -> Result<EndpointRecord, Error> { Ok(EndpointRecord::create(iss, device_key, vec![IWAKURA_ALPN_STR.to_string()], None)?)}
/// build a repo presence check closure over a `RepoClient`.////// the returned `VerifyFn` captures the client and, given a repo identifier/// and device, reports whether the endpoint record is present and valid./// `RepoClient` is cheap to share via `Arc`.pub fn presence_check(client: std::sync::Arc<RepoClient>) -> VerifyFn { Box::new(move |iss: String, device: DidKey| { let client = std::sync::Arc::clone(&client); Box::pin(async move { // surface the precise reason on failure, so a revoked record is // distinguishable from a signature/subject mismatch in the logs. match client.check_endpoint_presence(&iss, &device).await { Ok(crate::repo::Presence::Active) => Ok(true), Ok(other) => { tracing::debug!(?other, %iss, %device, "endpoint presence check: not active"); Ok(false) } Err(e) => Err(e.to_string()), } }) })}
/// open the persistent session store and build an oauth client over it.pub async fn oauth_client() -> Result<flow::DefaultOAuthClient, Error> { let store = JsonlSessionStore::open(auth::auth_file()).await?; Ok(flow::build_client(store)?)}
/// bring up the iroh node bound to `device_key`.////// the node's identity is the device key, so the endpoint record it presents/// in handshakes authorizes the endpoint actually connected.pub async fn node(device_key: &SigningKey) -> Result<IwakuraNode, Error> { Ok(IwakuraNode::bind(device_key).await?)}