#[cfg(feature = "config_file")]
pub mod file;
pub mod overrides;
use crate::{
error::Result,
sandbox::{Sandbox, SandboxType},
};
use std::{
fmt::Debug,
fs::File,
io::{BufReader, BufWriter, Read, Write},
path::{Path, PathBuf},
};
#[derive(Debug)]
pub struct SandboxConfig {
pub allow_network_access: bool,
pub writable_dirs: Option<Vec<PathBuf>>,
pub override_home_dirs: Option<Vec<OverrideHomeDir>>,
pub passthrough_home_dirs: Option<Vec<PathBuf>>,
}
impl Default for SandboxConfig {
fn default() -> Self {
Self::new()
}
}
impl SandboxConfig {
pub const fn new() -> Self {
Self {
allow_network_access: false,
writable_dirs: None,
override_home_dirs: None,
passthrough_home_dirs: None,
}
}
pub const fn with_network_access(&mut self) -> &mut Self {
self.allow_network_access = true;
self
}
pub fn with_writable_dir(&mut self, dir: impl Into<PathBuf>) -> &mut Self {
self.writable_dirs.get_or_insert_default().push(dir.into());
self
}
pub fn with_override_home_dir(&mut self, override_home_dir: OverrideHomeDir) -> &mut Self {
self.override_home_dirs
.get_or_insert_default()
.push(override_home_dir);
self
}
pub fn with_passthrough_home_dir(
&mut self,
segments: impl IntoIterator<Item = impl AsRef<Path>>,
) -> &mut Self {
self.passthrough_home_dirs
.get_or_insert_default()
.push(PathBuf::from_iter(segments));
self
}
pub const fn build_sandbox(&mut self, sandbox_type: SandboxType) -> Sandbox {
Sandbox {
sandbox_type,
config: Self {
allow_network_access: self.allow_network_access,
writable_dirs: self.writable_dirs.take(),
override_home_dirs: self.override_home_dirs.take(),
passthrough_home_dirs: self.passthrough_home_dirs.take(),
},
}
}
pub(crate) fn needs_fake_home(&self) -> bool {
self.override_home_dirs
.as_ref()
.is_some_and(|v| !v.is_empty()) ||
self.passthrough_home_dirs
.as_ref()
.is_some_and(|v| !v.is_empty())
}
}
#[derive(Debug)]
pub struct OverrideHomeDir {
pub subpath: PathBuf,
pub overrides: Option<Vec<OverrideFile<Box<dyn Override>>>>,
}
impl OverrideHomeDir {
pub fn new(path_segments: impl IntoIterator<Item = impl AsRef<Path>>) -> Self {
Self {
subpath: PathBuf::from_iter(path_segments),
overrides: None,
}
}
pub fn with_override(
&mut self,
path: impl Into<PathBuf>,
behavior: impl Override + 'static,
) -> &mut Self {
self.overrides.get_or_insert_default().push(OverrideFile {
path: path.into(),
behavior: Box::new(behavior),
});
self
}
#[must_use]
pub fn take(&mut self) -> Self {
Self {
subpath: std::mem::take(&mut self.subpath),
overrides: self.overrides.take(),
}
}
}
#[derive(Debug)]
pub struct OverrideFile<T> {
pub path: PathBuf,
pub behavior: T,
}
#[derive(Debug)]
pub struct FileContents {
pub(crate) original: BufReader<File>,
pub(crate) output: BufWriter<File>,
}
impl FileContents {
pub fn read(&mut self) -> impl Read {
&mut self.original
}
pub fn write(&mut self) -> impl Write {
&mut self.output
}
}
pub trait Override: Debug {
fn apply(&self, contents: FileContents) -> Result<()>;
}