mod client;
mod service;
mod wire;
use std::fmt::Write as _;
use std::io::Read as _;
use std::net::TcpStream;
use std::time::Duration;
use anyhow::{Context as _, Result};
use zeroize::Zeroizing;
pub use client::{Endpoint, configured};
pub use service::Service;
pub use wire::Reply;
pub const SOCKET_ENV: &str = "MOAT_GUARD_SOCKET";
pub const TOKEN_ENV: &str = "MOAT_GUARD_TOKEN";
pub const MAX_PAYLOAD_BYTES: u64 = 1024 * 1024;
pub trait Stream: std::io::Read + std::io::Write {
fn set_timeouts(&self, limit: Duration) -> std::io::Result<()>;
}
impl Stream for &TcpStream {
fn set_timeouts(&self, limit: Duration) -> std::io::Result<()> {
self.set_read_timeout(Some(limit))?;
self.set_write_timeout(Some(limit))
}
}
impl Stream for TcpStream {
fn set_timeouts(&self, limit: Duration) -> std::io::Result<()> {
self.set_read_timeout(Some(limit))?;
self.set_write_timeout(Some(limit))
}
}
pub fn random_hex(bytes: usize) -> Result<Zeroizing<String>> {
let mut raw = Zeroizing::new(vec![0u8; bytes]);
std::fs::File::open("/dev/urandom")
.and_then(|mut random| random.read_exact(&mut raw))
.context("reading random bytes")?;
let mut out = Zeroizing::new(String::with_capacity(bytes * 2));
for byte in raw.iter() {
let _ = write!(out, "{byte:02x}");
}
Ok(out)
}
#[cfg(all(test, unix))]
mod tests;