breakmancer 0.9.0

Drop a breakpoint into any shell.
Documentation
use std::{
    fs::File,
    io::{prelude::Write, BufReader},
};

use serde::{Deserialize, Serialize};

use crate::protocol::XWingKeypair;

pub struct DebugKeys {
    pub controller_keypair: XWingKeypair,
    pub breakpoint_keypair: XWingKeypair,
}

#[derive(Debug, Serialize, Deserialize)]
struct DebugKeysFile {
    controller_private: [u8; x_wing::DECAPSULATION_KEY_SIZE],
    breakpoint_private: [u8; x_wing::DECAPSULATION_KEY_SIZE],
}

fn read_debug_keys(path: &str) -> Option<DebugKeys> {
    let fd = File::open(path).ok()?;
    let reader = BufReader::new(fd);
    let raw: DebugKeysFile = serde_cbor::from_reader(reader).ok()?;
    Some(DebugKeys {
        controller_keypair: XWingKeypair::from_decaps(&x_wing::DecapsulationKey::from(
            raw.controller_private,
        )),
        breakpoint_keypair: XWingKeypair::from_decaps(&x_wing::DecapsulationKey::from(
            raw.breakpoint_private,
        )),
    })
}

fn create_debug_keys(path: &str) -> Result<DebugKeys, ()> {
    let controller_keypair = XWingKeypair::new();
    let breakpoint_keypair = XWingKeypair::new();

    let for_file = serde_cbor::to_vec(&DebugKeysFile {
        controller_private: *controller_keypair.private_key.as_bytes(),
        breakpoint_private: *breakpoint_keypair.private_key.as_bytes(),
    })
    .map_err(|_| ())?;
    let mut fd = File::create(path).map_err(|_| ())?;
    fd.write_all(&for_file).map_err(|_| ())?;

    Ok(DebugKeys {
        controller_keypair,
        breakpoint_keypair,
    })
}

// This is intended only for manual testing.
//
// To use this feature, set environment variable `BM_USE_DEBUG_KEYS`
// to a place where breakmancer can write a set of debugging keys to
// file. If controller and breakpoint are on the same machine, they can
// share keys without requiring the developer to copy public keys and
// shared secrets around.
pub(crate) fn get_debug_keys() -> Option<DebugKeys> {
    let path = std::env::var("BM_USE_DEBUG_KEYS").ok()?;
    match read_debug_keys(&path) {
        Some(keys) => {
            eprintln!("[WARNING] Using debug keys from disk.");
            Some(keys)
        }
        None => match create_debug_keys(&path) {
            Ok(keys) => {
                eprintln!("[WARNING] Using new debug keys (and saving to disk.)");
                Some(keys)
            }
            Err(err) => {
                eprintln!("[WARNING] Could not read or create new debug keys: {err:?}");
                None
            }
        },
    }
}