use std::sync::Arc; use crate::caps::{Capabilities, CapabilitiesError, PathTarget}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum SourceAccess { Execute, Read, } #[derive(Clone)] pub struct SourceAuthority { caps: Arc, access: SourceAccess, } impl SourceAuthority { pub fn execute(caps: Arc) -> Self { Self { caps, access: SourceAccess::Execute, } } pub fn read(caps: Arc) -> Self { Self { caps, access: SourceAccess::Read } } pub fn is_read(&self) -> bool { self.access == SourceAccess::Read } pub fn check_local(&self, target: &PathTarget) -> Result<(), CapabilitiesError> { match self.access { SourceAccess::Execute => self.caps.check_js_exec(target), SourceAccess::Read => self.caps.check_read(target), } } pub fn check_remote_module(&self, url: &url::Url) -> Result<(), CapabilitiesError> { match self.access { SourceAccess::Execute => self.caps.check_remote_exec(url), SourceAccess::Read => self.check_net_url(url), } } pub fn check_remote_package(&self, url: &url::Url) -> Result<(), CapabilitiesError> { match self.access { SourceAccess::Execute => self.caps.check_remote_acquire(url), SourceAccess::Read => self.check_net_url(url), } } fn check_net_url(&self, url: &url::Url) -> Result<(), CapabilitiesError> { let host = url .host_str() .ok_or_else(|| CapabilitiesError::NetUrlDenied(url.to_string()))?; let port = url .port_or_known_default() .ok_or_else(|| CapabilitiesError::NetUrlDenied(url.to_string()))?; self.caps.check_net(host, port) } /// Reauthorize an acquired artifact by its recorded final URL. No-op /// under Execute, which keeps requested-only redirect semantics. pub fn check_remote_final(&self, final_url: &str) -> Result<(), CapabilitiesError> { if self.is_read() { let url = url::Url::parse(final_url) .map_err(|_| CapabilitiesError::NetUrlDenied(final_url.to_owned()))?; self.check_net_url(&url) } else { Ok(()) } } pub fn unrestricted_local(&self) -> bool { match self.access { SourceAccess::Execute => self.caps.unrestricted_js_exec(), SourceAccess::Read => self.caps.unrestricted_read(), } } }