use crate::capability::{
AccessMode as InternalAccessMode, CapabilitySet, IpcMode as InternalIpcMode,
NetworkMode as InternalNetworkMode, ProcessInfoMode as InternalProcessInfoMode,
SignalMode as InternalSignalMode,
};
use crate::manifest::{
AccessMode, CapabilityManifest, FsEntryType, IpcMode, NetworkMode, ProcessInfoMode, SignalMode,
};
use crate::{NonoError, Result};
impl TryFrom<&CapabilityManifest> for CapabilitySet {
type Error = NonoError;
fn try_from(manifest: &CapabilityManifest) -> Result<Self> {
manifest.validate()?;
let mut caps = CapabilitySet::new();
if let Some(ref fs) = manifest.filesystem {
for grant in &fs.grants {
let mode = convert_access_mode(grant.access);
let path = grant.path.as_str();
caps = match grant.type_ {
FsEntryType::File => caps.allow_file(path, mode)?,
FsEntryType::Directory => caps.allow_path(path, mode)?,
};
}
}
if let Some(ref net) = manifest.network {
caps = match net.mode {
NetworkMode::Blocked => caps.block_network(),
NetworkMode::Proxy => caps.set_network_mode(InternalNetworkMode::ProxyOnly {
port: 0,
bind_ports: vec![],
}),
NetworkMode::Unrestricted => caps.set_network_mode(InternalNetworkMode::AllowAll),
};
if let Some(ref ports) = net.ports {
for port in &ports.connect {
let p = u16::try_from(port.get()).map_err(|_| {
NonoError::ConfigParse(format!("port {} exceeds u16 range", port))
})?;
caps = caps.allow_tcp_connect(p);
}
for port in &ports.bind {
let p = u16::try_from(port.get()).map_err(|_| {
NonoError::ConfigParse(format!("port {} exceeds u16 range", port))
})?;
caps = caps.allow_tcp_bind(p);
}
for port in &ports.localhost {
let p = u16::try_from(port.get()).map_err(|_| {
NonoError::ConfigParse(format!("port {} exceeds u16 range", port))
})?;
caps = caps.allow_localhost_port(p);
}
}
}
if let Some(ref proc) = manifest.process {
caps = caps.set_signal_mode(convert_signal_mode(proc.signal_mode));
caps = caps.set_process_info_mode(convert_process_info_mode(proc.process_info_mode));
caps = caps.set_ipc_mode(convert_ipc_mode(proc.ipc_mode));
for cmd in &proc.allowed_commands {
caps = caps.allow_command(cmd.clone());
}
for cmd in &proc.blocked_commands {
caps = caps.block_command(cmd.clone());
}
}
Ok(caps)
}
}
fn convert_access_mode(mode: AccessMode) -> InternalAccessMode {
match mode {
AccessMode::Read => InternalAccessMode::Read,
AccessMode::Write => InternalAccessMode::Write,
AccessMode::Readwrite => InternalAccessMode::ReadWrite,
}
}
fn convert_signal_mode(mode: SignalMode) -> InternalSignalMode {
match mode {
SignalMode::Isolated => InternalSignalMode::Isolated,
SignalMode::AllowSameSandbox => InternalSignalMode::AllowSameSandbox,
SignalMode::AllowAll => InternalSignalMode::AllowAll,
}
}
fn convert_process_info_mode(mode: ProcessInfoMode) -> InternalProcessInfoMode {
match mode {
ProcessInfoMode::Isolated => InternalProcessInfoMode::Isolated,
ProcessInfoMode::AllowSameSandbox => InternalProcessInfoMode::AllowSameSandbox,
ProcessInfoMode::AllowAll => InternalProcessInfoMode::AllowAll,
}
}
fn convert_ipc_mode(mode: IpcMode) -> InternalIpcMode {
match mode {
IpcMode::SharedMemoryOnly => InternalIpcMode::SharedMemoryOnly,
IpcMode::Full => InternalIpcMode::Full,
}
}