mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 20:38:55 +00:00
refactor(permissions): split up Descriptor into Allow, Deny, and Query (#25508)
This makes the permission system more versatile.
This commit is contained in:
parent
e0b9c745c1
commit
62e952559f
@ -32,7 +32,6 @@ use deno_core::normalize_path;
|
||||
use deno_core::resolve_url_or_path;
|
||||
use deno_core::url::Url;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_permissions::parse_sys_kind;
|
||||
use deno_runtime::deno_permissions::PermissionsOptions;
|
||||
use log::debug;
|
||||
@ -661,107 +660,25 @@ impl PermissionFlags {
|
||||
|| self.deny_write.is_some()
|
||||
}
|
||||
|
||||
pub fn to_options(
|
||||
&self,
|
||||
// will be None when `deno compile` can't resolve the cwd
|
||||
initial_cwd: Option<&Path>,
|
||||
) -> Result<PermissionsOptions, AnyError> {
|
||||
fn convert_option_str_to_path_buf(
|
||||
flag: &Option<Vec<String>>,
|
||||
initial_cwd: Option<&Path>,
|
||||
) -> Result<Option<Vec<PathBuf>>, AnyError> {
|
||||
let Some(paths) = &flag else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let mut new_paths = Vec::with_capacity(paths.len());
|
||||
for path in paths {
|
||||
if let Some(initial_cwd) = initial_cwd {
|
||||
new_paths.push(initial_cwd.join(path))
|
||||
} else {
|
||||
let path = PathBuf::from(path);
|
||||
if path.is_absolute() {
|
||||
new_paths.push(path);
|
||||
} else {
|
||||
bail!("Could not resolve relative permission path '{}' when current working directory could not be resolved.", path.display())
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(new_paths))
|
||||
}
|
||||
|
||||
fn resolve_allow_run(
|
||||
allow_run: &[String],
|
||||
) -> Result<Vec<PathBuf>, AnyError> {
|
||||
let mut new_allow_run = Vec::with_capacity(allow_run.len());
|
||||
for command_name in allow_run {
|
||||
if command_name.is_empty() {
|
||||
bail!("Empty command name not allowed in --allow-run=...")
|
||||
}
|
||||
let command_path_result = which::which(command_name);
|
||||
match command_path_result {
|
||||
Ok(command_path) => new_allow_run.push(command_path),
|
||||
Err(err) => {
|
||||
log::info!(
|
||||
"{} Failed to resolve '{}' for allow-run: {}",
|
||||
colors::gray("Info"),
|
||||
command_name,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(new_allow_run)
|
||||
}
|
||||
|
||||
let mut deny_write =
|
||||
convert_option_str_to_path_buf(&self.deny_write, initial_cwd)?;
|
||||
let allow_run = self
|
||||
.allow_run
|
||||
.as_ref()
|
||||
.and_then(|raw_allow_run| match resolve_allow_run(raw_allow_run) {
|
||||
Ok(resolved_allow_run) => {
|
||||
if resolved_allow_run.is_empty() && !raw_allow_run.is_empty() {
|
||||
None // convert to no permissions if now empty
|
||||
} else {
|
||||
Some(Ok(resolved_allow_run))
|
||||
}
|
||||
}
|
||||
Err(err) => Some(Err(err)),
|
||||
})
|
||||
.transpose()?;
|
||||
// add the allow_run list to deno_write
|
||||
if let Some(allow_run_vec) = &allow_run {
|
||||
if !allow_run_vec.is_empty() {
|
||||
let deno_write = deny_write.get_or_insert_with(Vec::new);
|
||||
deno_write.extend(allow_run_vec.iter().cloned());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PermissionsOptions {
|
||||
pub fn to_options(&self) -> PermissionsOptions {
|
||||
PermissionsOptions {
|
||||
allow_all: self.allow_all,
|
||||
allow_env: self.allow_env.clone(),
|
||||
deny_env: self.deny_env.clone(),
|
||||
allow_net: self.allow_net.clone(),
|
||||
deny_net: self.deny_net.clone(),
|
||||
allow_ffi: convert_option_str_to_path_buf(&self.allow_ffi, initial_cwd)?,
|
||||
deny_ffi: convert_option_str_to_path_buf(&self.deny_ffi, initial_cwd)?,
|
||||
allow_read: convert_option_str_to_path_buf(
|
||||
&self.allow_read,
|
||||
initial_cwd,
|
||||
)?,
|
||||
deny_read: convert_option_str_to_path_buf(&self.deny_read, initial_cwd)?,
|
||||
allow_run,
|
||||
allow_ffi: self.allow_ffi.clone(),
|
||||
deny_ffi: self.deny_ffi.clone(),
|
||||
allow_read: self.allow_read.clone(),
|
||||
deny_read: self.deny_read.clone(),
|
||||
allow_run: self.allow_run.clone(),
|
||||
deny_run: self.deny_run.clone(),
|
||||
allow_sys: self.allow_sys.clone(),
|
||||
deny_sys: self.deny_sys.clone(),
|
||||
allow_write: convert_option_str_to_path_buf(
|
||||
&self.allow_write,
|
||||
initial_cwd,
|
||||
)?,
|
||||
deny_write,
|
||||
allow_write: self.allow_write.clone(),
|
||||
deny_write: self.deny_write.clone(),
|
||||
prompt: !resolve_no_prompt(self),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::url::Url;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
|
||||
@ -17,7 +16,7 @@ pub async fn resolve_import_map_value_from_specifier(
|
||||
Ok(serde_json::from_str(&data_url_text)?)
|
||||
} else {
|
||||
let file = file_fetcher
|
||||
.fetch(specifier, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(specifier)
|
||||
.await?
|
||||
.into_text_decoded()?;
|
||||
Ok(serde_json::from_str(&file.source)?)
|
||||
|
@ -27,7 +27,6 @@ use deno_npm::npm_rc::NpmRc;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use import_map::resolve_import_map_value_from_specifier;
|
||||
|
||||
@ -1082,7 +1081,7 @@ impl CliOptions {
|
||||
let specifier = specifier.clone();
|
||||
async move {
|
||||
let file = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&specifier)
|
||||
.await?
|
||||
.into_text_decoded()?;
|
||||
Ok(file.source.to_string())
|
||||
@ -1501,8 +1500,8 @@ impl CliOptions {
|
||||
&self.flags.permissions
|
||||
}
|
||||
|
||||
pub fn permissions_options(&self) -> Result<PermissionsOptions, AnyError> {
|
||||
self.flags.permissions.to_options(Some(&self.initial_cwd))
|
||||
pub fn permissions_options(&self) -> PermissionsOptions {
|
||||
self.flags.permissions.to_options()
|
||||
}
|
||||
|
||||
pub fn reload_flag(&self) -> bool {
|
||||
|
8
cli/cache/mod.rs
vendored
8
cli/cache/mod.rs
vendored
@ -4,6 +4,7 @@ use crate::args::CacheSetting;
|
||||
use crate::errors::get_error_class_name;
|
||||
use crate::file_fetcher::FetchNoFollowOptions;
|
||||
use crate::file_fetcher::FetchOptions;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::file_fetcher::FileOrRedirect;
|
||||
use crate::npm::CliNpmResolver;
|
||||
@ -18,7 +19,6 @@ use deno_graph::source::CacheInfo;
|
||||
use deno_graph::source::LoadFuture;
|
||||
use deno_graph::source::LoadResponse;
|
||||
use deno_graph::source::Loader;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
@ -112,7 +112,7 @@ pub struct FetchCacher {
|
||||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
permissions: PermissionsContainer,
|
||||
permissions: FetchPermissionsOption,
|
||||
cache_info_enabled: bool,
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ impl FetchCacher {
|
||||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
permissions: PermissionsContainer,
|
||||
permissions: FetchPermissionsOption,
|
||||
) -> Self {
|
||||
Self {
|
||||
file_fetcher,
|
||||
@ -230,7 +230,7 @@ impl Loader for FetchCacher {
|
||||
.fetch_no_follow_with_options(FetchNoFollowOptions {
|
||||
fetch_options: FetchOptions {
|
||||
specifier: &specifier,
|
||||
permissions: &permissions,
|
||||
permissions: permissions.as_ref(),
|
||||
maybe_accept: None,
|
||||
maybe_cache_setting: maybe_cache_setting.as_ref(),
|
||||
},
|
||||
|
@ -65,10 +65,13 @@ use deno_core::FeatureChecker;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::DenoFsNodeResolverEnv;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
use deno_runtime::deno_web::BlobStore;
|
||||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use log::warn;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use once_cell::sync::OnceCell;
|
||||
@ -181,6 +184,7 @@ struct CliFactoryServices {
|
||||
node_code_translator: Deferred<Arc<CliNodeCodeTranslator>>,
|
||||
node_resolver: Deferred<Arc<NodeResolver>>,
|
||||
npm_resolver: Deferred<Arc<dyn CliNpmResolver>>,
|
||||
permission_desc_parser: Deferred<Arc<RuntimePermissionDescriptorParser>>,
|
||||
sloppy_imports_resolver: Deferred<Option<Arc<SloppyImportsResolver>>>,
|
||||
text_only_progress_bar: Deferred<ProgressBar>,
|
||||
type_checker: Deferred<Arc<TypeChecker>>,
|
||||
@ -708,6 +712,15 @@ impl CliFactory {
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn permission_desc_parser(
|
||||
&self,
|
||||
) -> Result<&Arc<RuntimePermissionDescriptorParser>, AnyError> {
|
||||
self.services.permission_desc_parser.get_or_try_init(|| {
|
||||
let fs = self.fs().clone();
|
||||
Ok(Arc::new(RuntimePermissionDescriptorParser::new(fs)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn feature_checker(&self) -> Result<&Arc<FeatureChecker>, AnyError> {
|
||||
self.services.feature_checker.get_or_try_init(|| {
|
||||
let cli_options = self.cli_options()?;
|
||||
@ -739,6 +752,17 @@ impl CliFactory {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_permissions_container(
|
||||
&self,
|
||||
) -> Result<PermissionsContainer, AnyError> {
|
||||
let desc_parser = self.permission_desc_parser()?.clone();
|
||||
let permissions = Permissions::from_options(
|
||||
desc_parser.as_ref(),
|
||||
&self.cli_options()?.permissions_options(),
|
||||
)?;
|
||||
Ok(PermissionsContainer::new(desc_parser, permissions))
|
||||
}
|
||||
|
||||
pub async fn create_cli_main_worker_factory(
|
||||
&self,
|
||||
) -> Result<CliMainWorkerFactory, AnyError> {
|
||||
@ -754,11 +778,17 @@ impl CliFactory {
|
||||
};
|
||||
|
||||
Ok(CliMainWorkerFactory::new(
|
||||
StorageKeyResolver::from_options(cli_options),
|
||||
cli_options.sub_command().clone(),
|
||||
npm_resolver.clone(),
|
||||
node_resolver.clone(),
|
||||
self.blob_store().clone(),
|
||||
if cli_options.code_cache_enabled() {
|
||||
Some(self.code_cache()?.clone())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
self.feature_checker()?.clone(),
|
||||
self.fs().clone(),
|
||||
maybe_file_watcher_communicator,
|
||||
self.maybe_inspector_server()?.clone(),
|
||||
cli_options.maybe_lockfile().cloned(),
|
||||
Box::new(CliModuleLoaderFactory::new(
|
||||
cli_options,
|
||||
if cli_options.code_cache_enabled() {
|
||||
@ -779,17 +809,12 @@ impl CliFactory {
|
||||
self.parsed_source_cache().clone(),
|
||||
self.resolver().await?.clone(),
|
||||
)),
|
||||
node_resolver.clone(),
|
||||
npm_resolver.clone(),
|
||||
self.permission_desc_parser()?.clone(),
|
||||
self.root_cert_store_provider().clone(),
|
||||
self.fs().clone(),
|
||||
maybe_file_watcher_communicator,
|
||||
self.maybe_inspector_server()?.clone(),
|
||||
cli_options.maybe_lockfile().cloned(),
|
||||
self.feature_checker()?.clone(),
|
||||
if cli_options.code_cache_enabled() {
|
||||
Some(self.code_cache()?.clone())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
StorageKeyResolver::from_options(cli_options),
|
||||
cli_options.sub_command().clone(),
|
||||
self.create_cli_main_worker_options()?,
|
||||
))
|
||||
}
|
||||
|
@ -161,9 +161,38 @@ fn get_validated_scheme(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum FetchPermissionsOptionRef<'a> {
|
||||
AllowAll,
|
||||
Container(&'a PermissionsContainer),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FetchPermissionsOption {
|
||||
AllowAll,
|
||||
Container(PermissionsContainer),
|
||||
}
|
||||
|
||||
impl FetchPermissionsOption {
|
||||
pub fn as_ref(&self) -> FetchPermissionsOptionRef {
|
||||
match self {
|
||||
FetchPermissionsOption::AllowAll => FetchPermissionsOptionRef::AllowAll,
|
||||
FetchPermissionsOption::Container(container) => {
|
||||
FetchPermissionsOptionRef::Container(container)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PermissionsContainer> for FetchPermissionsOption {
|
||||
fn from(value: PermissionsContainer) -> Self {
|
||||
Self::Container(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FetchOptions<'a> {
|
||||
pub specifier: &'a ModuleSpecifier,
|
||||
pub permissions: &'a PermissionsContainer,
|
||||
pub permissions: FetchPermissionsOptionRef<'a>,
|
||||
pub maybe_accept: Option<&'a str>,
|
||||
pub maybe_cache_setting: Option<&'a CacheSetting>,
|
||||
}
|
||||
@ -515,11 +544,33 @@ impl FileFetcher {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub async fn fetch_bypass_permissions(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<File, AnyError> {
|
||||
self
|
||||
.fetch_inner(specifier, FetchPermissionsOptionRef::AllowAll)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Fetch a source file and asynchronously return it.
|
||||
#[allow(dead_code)] // todo(25469): undo when merging
|
||||
#[inline(always)]
|
||||
pub async fn fetch(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
permissions: &PermissionsContainer,
|
||||
) -> Result<File, AnyError> {
|
||||
self
|
||||
.fetch_inner(specifier, FetchPermissionsOptionRef::Container(permissions))
|
||||
.await
|
||||
}
|
||||
|
||||
async fn fetch_inner(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
permissions: FetchPermissionsOptionRef<'_>,
|
||||
) -> Result<File, AnyError> {
|
||||
self
|
||||
.fetch_with_options(FetchOptions {
|
||||
@ -583,7 +634,14 @@ impl FileFetcher {
|
||||
specifier
|
||||
);
|
||||
let scheme = get_validated_scheme(specifier)?;
|
||||
options.permissions.check_specifier(specifier)?;
|
||||
match options.permissions {
|
||||
FetchPermissionsOptionRef::AllowAll => {
|
||||
// allow
|
||||
}
|
||||
FetchPermissionsOptionRef::Container(permissions) => {
|
||||
permissions.check_specifier(specifier)?;
|
||||
}
|
||||
}
|
||||
if let Some(file) = self.memory_files.get(specifier) {
|
||||
Ok(FileOrRedirect::File(file))
|
||||
} else if scheme == "file" {
|
||||
@ -684,9 +742,7 @@ mod tests {
|
||||
|
||||
async fn test_fetch(specifier: &ModuleSpecifier) -> (File, FileFetcher) {
|
||||
let (file_fetcher, _) = setup(CacheSetting::ReloadAll, None);
|
||||
let result = file_fetcher
|
||||
.fetch(specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(specifier).await;
|
||||
assert!(result.is_ok());
|
||||
(result.unwrap(), file_fetcher)
|
||||
}
|
||||
@ -700,7 +756,7 @@ mod tests {
|
||||
.fetch_with_options_and_max_redirect(
|
||||
FetchOptions {
|
||||
specifier,
|
||||
permissions: &PermissionsContainer::allow_all(),
|
||||
permissions: FetchPermissionsOptionRef::AllowAll,
|
||||
maybe_accept: None,
|
||||
maybe_cache_setting: Some(&file_fetcher.cache_setting),
|
||||
},
|
||||
@ -796,9 +852,7 @@ mod tests {
|
||||
};
|
||||
file_fetcher.insert_memory_files(file.clone());
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let result_file = result.unwrap();
|
||||
assert_eq!(result_file, file);
|
||||
@ -809,9 +863,7 @@ mod tests {
|
||||
let (file_fetcher, _) = setup(CacheSetting::Use, None);
|
||||
let specifier = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap().into_text_decoded().unwrap();
|
||||
assert_eq!(
|
||||
@ -840,9 +892,7 @@ mod tests {
|
||||
None,
|
||||
);
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap().into_text_decoded().unwrap();
|
||||
assert_eq!(
|
||||
@ -862,9 +912,7 @@ mod tests {
|
||||
let specifier =
|
||||
ModuleSpecifier::parse("http://localhost:4545/subdir/mod2.ts").unwrap();
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap().into_text_decoded().unwrap();
|
||||
assert_eq!(
|
||||
@ -882,9 +930,7 @@ mod tests {
|
||||
.set(&specifier, headers.clone(), file.source.as_bytes())
|
||||
.unwrap();
|
||||
|
||||
let result = file_fetcher_01
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher_01.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap().into_text_decoded().unwrap();
|
||||
assert_eq!(
|
||||
@ -908,9 +954,7 @@ mod tests {
|
||||
.set(&specifier, headers.clone(), file.source.as_bytes())
|
||||
.unwrap();
|
||||
|
||||
let result = file_fetcher_02
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher_02.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap().into_text_decoded().unwrap();
|
||||
assert_eq!(
|
||||
@ -933,9 +977,7 @@ mod tests {
|
||||
Default::default(),
|
||||
None,
|
||||
);
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap().into_text_decoded().unwrap();
|
||||
assert_eq!(
|
||||
@ -966,9 +1008,7 @@ mod tests {
|
||||
None,
|
||||
);
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let cache_key =
|
||||
file_fetcher.http_cache.cache_item_key(&specifier).unwrap();
|
||||
@ -1002,9 +1042,7 @@ mod tests {
|
||||
Default::default(),
|
||||
None,
|
||||
);
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let cache_key =
|
||||
@ -1041,9 +1079,7 @@ mod tests {
|
||||
resolve_url("http://localhost:4545/subdir/redirects/redirect1.js")
|
||||
.unwrap();
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap();
|
||||
assert_eq!(file.specifier, redirected_specifier);
|
||||
@ -1082,9 +1118,7 @@ mod tests {
|
||||
resolve_url("http://localhost:4545/subdir/redirects/redirect1.js")
|
||||
.unwrap();
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap();
|
||||
assert_eq!(file.specifier, redirected_02_specifier);
|
||||
@ -1142,9 +1176,7 @@ mod tests {
|
||||
None,
|
||||
);
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let cache_key = file_fetcher
|
||||
@ -1182,7 +1214,7 @@ mod tests {
|
||||
None,
|
||||
);
|
||||
let result = file_fetcher
|
||||
.fetch(&redirected_specifier, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&redirected_specifier)
|
||||
.await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
@ -1223,7 +1255,7 @@ mod tests {
|
||||
.fetch_with_options_and_max_redirect(
|
||||
FetchOptions {
|
||||
specifier: &specifier,
|
||||
permissions: &PermissionsContainer::allow_all(),
|
||||
permissions: FetchPermissionsOptionRef::AllowAll,
|
||||
maybe_accept: None,
|
||||
maybe_cache_setting: Some(&file_fetcher.cache_setting),
|
||||
},
|
||||
@ -1236,7 +1268,7 @@ mod tests {
|
||||
.fetch_with_options_and_max_redirect(
|
||||
FetchOptions {
|
||||
specifier: &specifier,
|
||||
permissions: &PermissionsContainer::allow_all(),
|
||||
permissions: FetchPermissionsOptionRef::AllowAll,
|
||||
maybe_accept: None,
|
||||
maybe_cache_setting: Some(&file_fetcher.cache_setting),
|
||||
},
|
||||
@ -1264,9 +1296,7 @@ mod tests {
|
||||
resolve_url("http://localhost:4550/subdir/redirects/redirect1.js")
|
||||
.unwrap();
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap();
|
||||
assert_eq!(file.specifier, redirected_specifier);
|
||||
@ -1310,9 +1340,7 @@ mod tests {
|
||||
let specifier =
|
||||
resolve_url("http://localhost:4545/run/002_hello.ts").unwrap();
|
||||
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err();
|
||||
assert_eq!(get_custom_error_class(&err), Some("NoRemote"));
|
||||
@ -1343,22 +1371,16 @@ mod tests {
|
||||
let specifier =
|
||||
resolve_url("http://localhost:4545/run/002_hello.ts").unwrap();
|
||||
|
||||
let result = file_fetcher_01
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher_01.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err();
|
||||
assert_eq!(err.to_string(), "Specifier not found in cache: \"http://localhost:4545/run/002_hello.ts\", --cached-only is specified.");
|
||||
assert_eq!(get_custom_error_class(&err), Some("NotCached"));
|
||||
|
||||
let result = file_fetcher_02
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher_02.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let result = file_fetcher_01
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher_01.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
@ -1368,17 +1390,13 @@ mod tests {
|
||||
let fixture_path = temp_dir.path().join("mod.ts");
|
||||
let specifier = ModuleSpecifier::from_file_path(&fixture_path).unwrap();
|
||||
fs::write(fixture_path.clone(), r#"console.log("hello deno");"#).unwrap();
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap().into_text_decoded().unwrap();
|
||||
assert_eq!(&*file.source, r#"console.log("hello deno");"#);
|
||||
|
||||
fs::write(fixture_path, r#"console.log("goodbye deno");"#).unwrap();
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap().into_text_decoded().unwrap();
|
||||
assert_eq!(&*file.source, r#"console.log("goodbye deno");"#);
|
||||
@ -1392,18 +1410,14 @@ mod tests {
|
||||
setup(CacheSetting::RespectHeaders, Some(temp_dir.clone()));
|
||||
let specifier =
|
||||
ModuleSpecifier::parse("http://localhost:4545/dynamic").unwrap();
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap();
|
||||
let first = file.source;
|
||||
|
||||
let (file_fetcher, _) =
|
||||
setup(CacheSetting::RespectHeaders, Some(temp_dir.clone()));
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap();
|
||||
let second = file.source;
|
||||
@ -1419,18 +1433,14 @@ mod tests {
|
||||
setup(CacheSetting::RespectHeaders, Some(temp_dir.clone()));
|
||||
let specifier =
|
||||
ModuleSpecifier::parse("http://localhost:4545/dynamic_cache").unwrap();
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap();
|
||||
let first = file.source;
|
||||
|
||||
let (file_fetcher, _) =
|
||||
setup(CacheSetting::RespectHeaders, Some(temp_dir.clone()));
|
||||
let result = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await;
|
||||
let result = file_fetcher.fetch_bypass_permissions(&specifier).await;
|
||||
assert!(result.is_ok());
|
||||
let file = result.unwrap();
|
||||
let second = file.source;
|
||||
|
@ -9,9 +9,9 @@ use deno_core::error::AnyError;
|
||||
use deno_core::parking_lot::RwLock;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
|
||||
use crate::args::CliOptions;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::module_loader::ModuleLoadPreparer;
|
||||
use crate::util::fs::collect_specifiers;
|
||||
use crate::util::path::is_script_ext;
|
||||
@ -75,7 +75,7 @@ impl MainModuleGraphContainer {
|
||||
specifiers,
|
||||
false,
|
||||
self.cli_options.ts_type_lib_window(),
|
||||
PermissionsContainer::allow_all(),
|
||||
FetchPermissionsOption::AllowAll,
|
||||
)
|
||||
.await?;
|
||||
graph_permit.commit();
|
||||
|
@ -11,6 +11,7 @@ use crate::cache::ModuleInfoCache;
|
||||
use crate::cache::ParsedSourceCache;
|
||||
use crate::colors;
|
||||
use crate::errors::get_error_class_name;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
@ -41,7 +42,6 @@ use deno_graph::ResolutionError;
|
||||
use deno_graph::SpecifierError;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::jsr::JsrDepPackageReq;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
@ -670,12 +670,12 @@ impl ModuleGraphBuilder {
|
||||
|
||||
/// Creates the default loader used for creating a graph.
|
||||
pub fn create_graph_loader(&self) -> cache::FetchCacher {
|
||||
self.create_fetch_cacher(PermissionsContainer::allow_all())
|
||||
self.create_fetch_cacher(FetchPermissionsOption::AllowAll)
|
||||
}
|
||||
|
||||
pub fn create_fetch_cacher(
|
||||
&self,
|
||||
permissions: PermissionsContainer,
|
||||
permissions: FetchPermissionsOption,
|
||||
) -> cache::FetchCacher {
|
||||
cache::FetchCacher::new(
|
||||
self.file_fetcher.clone(),
|
||||
|
11
cli/jsr.rs
11
cli/jsr.rs
@ -6,7 +6,6 @@ use dashmap::DashMap;
|
||||
use deno_core::serde_json;
|
||||
use deno_graph::packages::JsrPackageInfo;
|
||||
use deno_graph::packages::JsrPackageVersionInfo;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use std::sync::Arc;
|
||||
@ -68,10 +67,7 @@ impl JsrFetchResolver {
|
||||
let file_fetcher = self.file_fetcher.clone();
|
||||
// spawn due to the lsp's `Send` requirement
|
||||
let file = deno_core::unsync::spawn(async move {
|
||||
file_fetcher
|
||||
.fetch(&meta_url, &PermissionsContainer::allow_all())
|
||||
.await
|
||||
.ok()
|
||||
file_fetcher.fetch_bypass_permissions(&meta_url).await.ok()
|
||||
})
|
||||
.await
|
||||
.ok()??;
|
||||
@ -96,10 +92,7 @@ impl JsrFetchResolver {
|
||||
let file_fetcher = self.file_fetcher.clone();
|
||||
// spawn due to the lsp's `Send` requirement
|
||||
let file = deno_core::unsync::spawn(async move {
|
||||
file_fetcher
|
||||
.fetch(&meta_url, &PermissionsContainer::allow_all())
|
||||
.await
|
||||
.ok()
|
||||
file_fetcher.fetch_bypass_permissions(&meta_url).await.ok()
|
||||
})
|
||||
.await
|
||||
.ok()??;
|
||||
|
@ -37,7 +37,6 @@ use deno_lint::linter::LintConfig as DenoLintConfig;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_package_json::PackageJsonCache;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use indexmap::IndexSet;
|
||||
use lsp_types::ClientCapabilities;
|
||||
@ -1509,17 +1508,16 @@ impl ConfigData {
|
||||
ConfigWatchedFileType::ImportMap,
|
||||
);
|
||||
// spawn due to the lsp's `Send` requirement
|
||||
let fetch_result = deno_core::unsync::spawn({
|
||||
let file_fetcher = file_fetcher.cloned().unwrap();
|
||||
let import_map_url = import_map_url.clone();
|
||||
async move {
|
||||
file_fetcher
|
||||
.fetch(&import_map_url, &PermissionsContainer::allow_all())
|
||||
.await
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let fetch_result =
|
||||
deno_core::unsync::spawn({
|
||||
let file_fetcher = file_fetcher.cloned().unwrap();
|
||||
let import_map_url = import_map_url.clone();
|
||||
async move {
|
||||
file_fetcher.fetch_bypass_permissions(&import_map_url).await
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let value_result = fetch_result.and_then(|f| {
|
||||
serde_json::from_slice::<Value>(&f.source).map_err(|e| e.into())
|
||||
@ -1558,7 +1556,7 @@ impl ConfigData {
|
||||
let file_fetcher = file_fetcher.clone().unwrap();
|
||||
async move {
|
||||
let file = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&specifier)
|
||||
.await?
|
||||
.into_text_decoded()?;
|
||||
Ok(file.source.to_string())
|
||||
|
@ -14,7 +14,6 @@ use deno_graph::packages::JsrPackageInfo;
|
||||
use deno_graph::packages::JsrPackageInfoVersion;
|
||||
use deno_graph::packages::JsrPackageVersionInfo;
|
||||
use deno_graph::ModuleSpecifier;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
@ -311,7 +310,7 @@ impl PackageSearchApi for CliJsrSearchApi {
|
||||
// spawn due to the lsp's `Send` requirement
|
||||
let file = deno_core::unsync::spawn(async move {
|
||||
file_fetcher
|
||||
.fetch(&search_url, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&search_url)
|
||||
.await?
|
||||
.into_text_decoded()
|
||||
})
|
||||
|
@ -4,7 +4,6 @@ use dashmap::DashMap;
|
||||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
use serde::Deserialize;
|
||||
@ -55,7 +54,7 @@ impl PackageSearchApi for CliNpmSearchApi {
|
||||
let file_fetcher = self.file_fetcher.clone();
|
||||
let file = deno_core::unsync::spawn(async move {
|
||||
file_fetcher
|
||||
.fetch(&search_url, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&search_url)
|
||||
.await?
|
||||
.into_text_decoded()
|
||||
})
|
||||
|
@ -16,6 +16,7 @@ use crate::args::CacheSetting;
|
||||
use crate::cache::GlobalHttpCache;
|
||||
use crate::cache::HttpCache;
|
||||
use crate::file_fetcher::FetchOptions;
|
||||
use crate::file_fetcher::FetchPermissionsOptionRef;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::http_util::HttpClientProvider;
|
||||
|
||||
@ -30,7 +31,6 @@ use deno_core::url::Position;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::Dependency;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use log::error;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::borrow::Cow;
|
||||
@ -481,7 +481,7 @@ impl ModuleRegistry {
|
||||
file_fetcher
|
||||
.fetch_with_options(FetchOptions {
|
||||
specifier: &specifier,
|
||||
permissions: &PermissionsContainer::allow_all(),
|
||||
permissions: FetchPermissionsOptionRef::AllowAll,
|
||||
maybe_accept: Some("application/vnd.deno.reg.v2+json, application/vnd.deno.reg.v1+json;q=0.9, application/json;q=0.8"),
|
||||
maybe_cache_setting: None,
|
||||
})
|
||||
@ -584,7 +584,7 @@ impl ModuleRegistry {
|
||||
let file = deno_core::unsync::spawn({
|
||||
async move {
|
||||
file_fetcher
|
||||
.fetch(&endpoint, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&endpoint)
|
||||
.await
|
||||
.ok()?
|
||||
.into_text_decoded()
|
||||
@ -983,7 +983,7 @@ impl ModuleRegistry {
|
||||
// spawn due to the lsp's `Send` requirement
|
||||
let file = deno_core::unsync::spawn(async move {
|
||||
file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&specifier)
|
||||
.await
|
||||
.ok()?
|
||||
.into_text_decoded()
|
||||
@ -1049,7 +1049,7 @@ impl ModuleRegistry {
|
||||
let specifier = specifier.clone();
|
||||
async move {
|
||||
file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&specifier)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!(
|
||||
@ -1095,7 +1095,7 @@ impl ModuleRegistry {
|
||||
let specifier = specifier.clone();
|
||||
async move {
|
||||
file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.fetch_bypass_permissions(&specifier)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!(
|
||||
|
@ -31,6 +31,7 @@ use deno_core::unsync::spawn;
|
||||
use deno_core::unsync::spawn_blocking;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::tokio_util::create_and_run_current_thread;
|
||||
use indexmap::IndexMap;
|
||||
use std::borrow::Cow;
|
||||
@ -227,8 +228,11 @@ impl TestRun {
|
||||
// Various test files should not share the same permissions in terms of
|
||||
// `PermissionsContainer` - otherwise granting/revoking permissions in one
|
||||
// file would have impact on other files, which is undesirable.
|
||||
let permissions =
|
||||
Permissions::from_options(&cli_options.permissions_options()?)?;
|
||||
let permission_desc_parser = factory.permission_desc_parser()?.clone();
|
||||
let permissions = Permissions::from_options(
|
||||
permission_desc_parser.as_ref(),
|
||||
&cli_options.permissions_options(),
|
||||
)?;
|
||||
let main_graph_container = factory.main_module_graph_container().await?;
|
||||
test::check_specifiers(
|
||||
factory.file_fetcher()?,
|
||||
@ -276,7 +280,10 @@ impl TestRun {
|
||||
let join_handles = queue.into_iter().map(move |specifier| {
|
||||
let specifier = specifier.clone();
|
||||
let worker_factory = worker_factory.clone();
|
||||
let permissions = permissions.clone();
|
||||
let permissions_container = PermissionsContainer::new(
|
||||
permission_desc_parser.clone(),
|
||||
permissions.clone(),
|
||||
);
|
||||
let worker_sender = test_event_sender_factory.worker();
|
||||
let fail_fast_tracker = fail_fast_tracker.clone();
|
||||
let lsp_filter = self.filters.get(&specifier);
|
||||
@ -305,7 +312,7 @@ impl TestRun {
|
||||
// channel.
|
||||
create_and_run_current_thread(test::test_specifier(
|
||||
worker_factory,
|
||||
permissions,
|
||||
permissions_container,
|
||||
specifier,
|
||||
worker_sender,
|
||||
fail_fast_tracker,
|
||||
|
@ -104,7 +104,7 @@ impl ModuleLoadPreparer {
|
||||
roots: &[ModuleSpecifier],
|
||||
is_dynamic: bool,
|
||||
lib: TsTypeLib,
|
||||
permissions: PermissionsContainer,
|
||||
permissions: crate::file_fetcher::FetchPermissionsOption,
|
||||
) -> Result<(), AnyError> {
|
||||
log::debug!("Preparing module load.");
|
||||
let _pb_clear_guard = self.progress_bar.clear_guard();
|
||||
@ -762,7 +762,7 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
|
||||
&[specifier],
|
||||
is_dynamic,
|
||||
lib,
|
||||
root_permissions,
|
||||
root_permissions.into(),
|
||||
)
|
||||
.await?;
|
||||
update_permit.commit();
|
||||
|
@ -280,7 +280,7 @@ impl NodeRequireResolver for ByonmCliNpmResolver {
|
||||
.components()
|
||||
.any(|c| c.as_os_str().to_ascii_lowercase() == "node_modules")
|
||||
{
|
||||
permissions.check_read(path)?;
|
||||
_ = permissions.check_read_path(path)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -127,7 +127,8 @@ impl RegistryReadPermissionChecker {
|
||||
}
|
||||
}
|
||||
|
||||
permissions.check_read(path)
|
||||
_ = permissions.check_read_path(path)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,6 @@ use deno_core::serde_json;
|
||||
use deno_npm::registry::NpmPackageInfo;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
use deno_runtime::deno_node::NpmProcessStateProvider;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::NpmResolver;
|
||||
@ -152,10 +151,7 @@ impl NpmFetchResolver {
|
||||
let file_fetcher = self.file_fetcher.clone();
|
||||
// spawn due to the lsp's `Send` requirement
|
||||
let file = deno_core::unsync::spawn(async move {
|
||||
file_fetcher
|
||||
.fetch(&info_url, &PermissionsContainer::allow_all())
|
||||
.await
|
||||
.ok()
|
||||
file_fetcher.fetch_bypass_permissions(&info_url).await.ok()
|
||||
})
|
||||
.await
|
||||
.ok()??;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::time;
|
||||
|
||||
use deno_core::error::generic_error;
|
||||
@ -13,6 +14,7 @@ use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_runtime::deno_permissions::create_child_permissions;
|
||||
use deno_runtime::deno_permissions::ChildPermissionsArg;
|
||||
use deno_runtime::deno_permissions::PermissionDescriptorParser;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use uuid::Uuid;
|
||||
@ -59,11 +61,18 @@ pub fn op_pledge_test_permissions(
|
||||
#[serde] args: ChildPermissionsArg,
|
||||
) -> Result<Uuid, AnyError> {
|
||||
let token = Uuid::new_v4();
|
||||
let permission_desc_parser = state
|
||||
.borrow::<Arc<dyn PermissionDescriptorParser>>()
|
||||
.clone();
|
||||
let parent_permissions = state.borrow_mut::<PermissionsContainer>();
|
||||
let worker_permissions = {
|
||||
let mut parent_permissions = parent_permissions.0.lock();
|
||||
let perms = create_child_permissions(&mut parent_permissions, args)?;
|
||||
PermissionsContainer::new(perms)
|
||||
let mut parent_permissions = parent_permissions.inner.lock();
|
||||
let perms = create_child_permissions(
|
||||
permission_desc_parser.as_ref(),
|
||||
&mut parent_permissions,
|
||||
args,
|
||||
)?;
|
||||
PermissionsContainer::new(permission_desc_parser, perms)
|
||||
};
|
||||
let parent_permissions = parent_permissions.clone();
|
||||
|
||||
@ -74,7 +83,7 @@ pub fn op_pledge_test_permissions(
|
||||
state.put::<PermissionsHolder>(PermissionsHolder(token, parent_permissions));
|
||||
|
||||
// NOTE: This call overrides current permission set for the worker
|
||||
state.put(worker_permissions.0.clone());
|
||||
state.put(worker_permissions.inner.clone());
|
||||
state.put::<PermissionsContainer>(worker_permissions);
|
||||
|
||||
Ok(token)
|
||||
@ -91,7 +100,7 @@ pub fn op_restore_test_permissions(
|
||||
}
|
||||
|
||||
let permissions = permissions_holder.1;
|
||||
state.put(permissions.0.clone());
|
||||
state.put(permissions.inner.clone());
|
||||
state.put::<PermissionsContainer>(permissions);
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -18,9 +18,11 @@ use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_runtime::deno_permissions::create_child_permissions;
|
||||
use deno_runtime::deno_permissions::ChildPermissionsArg;
|
||||
use deno_runtime::deno_permissions::PermissionDescriptorParser;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
deno_core::extension!(deno_test,
|
||||
@ -54,11 +56,18 @@ pub fn op_pledge_test_permissions(
|
||||
#[serde] args: ChildPermissionsArg,
|
||||
) -> Result<Uuid, AnyError> {
|
||||
let token = Uuid::new_v4();
|
||||
let permission_desc_parser = state
|
||||
.borrow::<Arc<dyn PermissionDescriptorParser>>()
|
||||
.clone();
|
||||
let parent_permissions = state.borrow_mut::<PermissionsContainer>();
|
||||
let worker_permissions = {
|
||||
let mut parent_permissions = parent_permissions.0.lock();
|
||||
let perms = create_child_permissions(&mut parent_permissions, args)?;
|
||||
PermissionsContainer::new(perms)
|
||||
let mut parent_permissions = parent_permissions.inner.lock();
|
||||
let perms = create_child_permissions(
|
||||
permission_desc_parser.as_ref(),
|
||||
&mut parent_permissions,
|
||||
args,
|
||||
)?;
|
||||
PermissionsContainer::new(permission_desc_parser, perms)
|
||||
};
|
||||
let parent_permissions = parent_permissions.clone();
|
||||
|
||||
@ -68,7 +77,7 @@ pub fn op_pledge_test_permissions(
|
||||
state.put::<PermissionsHolder>(PermissionsHolder(token, parent_permissions));
|
||||
|
||||
// NOTE: This call overrides current permission set for the worker
|
||||
state.put(worker_permissions.0.clone());
|
||||
state.put(worker_permissions.inner.clone());
|
||||
state.put::<PermissionsContainer>(worker_permissions);
|
||||
|
||||
Ok(token)
|
||||
@ -85,7 +94,7 @@ pub fn op_restore_test_permissions(
|
||||
}
|
||||
|
||||
let permissions = permissions_holder.1;
|
||||
state.put(permissions.0.clone());
|
||||
state.put(permissions.inner.clone());
|
||||
state.put::<PermissionsContainer>(permissions);
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -32,6 +32,8 @@ use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
use deno_runtime::deno_web::BlobStore;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use deno_runtime::WorkerLogLevel;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
@ -449,7 +451,6 @@ pub async fn run(
|
||||
let current_exe_path = std::env::current_exe().unwrap();
|
||||
let current_exe_name =
|
||||
current_exe_path.file_name().unwrap().to_string_lossy();
|
||||
let maybe_cwd = std::env::current_dir().ok();
|
||||
let deno_dir_provider = Arc::new(DenoDirProvider::new(None));
|
||||
let root_cert_store_provider = Arc::new(StandaloneRootCertStoreProvider {
|
||||
ca_stores: metadata.ca_stores,
|
||||
@ -660,8 +661,7 @@ pub async fn run(
|
||||
};
|
||||
|
||||
let permissions = {
|
||||
let mut permissions =
|
||||
metadata.permissions.to_options(maybe_cwd.as_deref())?;
|
||||
let mut permissions = metadata.permissions.to_options();
|
||||
// if running with an npm vfs, grant read access to it
|
||||
if let Some(vfs_root) = maybe_vfs_root {
|
||||
match &mut permissions.allow_read {
|
||||
@ -669,15 +669,20 @@ pub async fn run(
|
||||
// do nothing, already granted
|
||||
}
|
||||
Some(vec) => {
|
||||
vec.push(vfs_root);
|
||||
vec.push(vfs_root.to_string_lossy().to_string());
|
||||
}
|
||||
None => {
|
||||
permissions.allow_read = Some(vec![vfs_root]);
|
||||
permissions.allow_read =
|
||||
Some(vec![vfs_root.to_string_lossy().to_string()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PermissionsContainer::new(Permissions::from_options(&permissions)?)
|
||||
let desc_parser =
|
||||
Arc::new(RuntimePermissionDescriptorParser::new(fs.clone()));
|
||||
let permissions =
|
||||
Permissions::from_options(desc_parser.as_ref(), &permissions)?;
|
||||
PermissionsContainer::new(desc_parser, permissions)
|
||||
};
|
||||
let feature_checker = Arc::new({
|
||||
let mut checker = FeatureChecker::default();
|
||||
@ -689,21 +694,24 @@ pub async fn run(
|
||||
}
|
||||
checker
|
||||
});
|
||||
let permission_desc_parser =
|
||||
Arc::new(RuntimePermissionDescriptorParser::new(fs.clone()));
|
||||
let worker_factory = CliMainWorkerFactory::new(
|
||||
StorageKeyResolver::empty(),
|
||||
crate::args::DenoSubcommand::Run(Default::default()),
|
||||
npm_resolver,
|
||||
node_resolver,
|
||||
Default::default(),
|
||||
Box::new(module_loader_factory),
|
||||
root_cert_store_provider,
|
||||
Arc::new(BlobStore::default()),
|
||||
// Code cache is not supported for standalone binary yet.
|
||||
None,
|
||||
feature_checker,
|
||||
fs,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
feature_checker,
|
||||
// Code cache is not supported for standalone binary yet.
|
||||
None,
|
||||
Box::new(module_loader_factory),
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
permission_desc_parser,
|
||||
root_cert_store_provider,
|
||||
StorageKeyResolver::empty(),
|
||||
crate::args::DenoSubcommand::Run(Default::default()),
|
||||
CliMainWorkerOptions {
|
||||
argv: metadata.argv,
|
||||
log_level: WorkerLogLevel::Info,
|
||||
|
@ -30,6 +30,7 @@ use deno_core::ModuleSpecifier;
|
||||
use deno_core::PollEventLoopOptions;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use deno_runtime::tokio_util::create_and_run_current_thread;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use indexmap::IndexMap;
|
||||
@ -144,14 +145,14 @@ fn create_reporter(
|
||||
/// Run a single specifier as an executable bench module.
|
||||
async fn bench_specifier(
|
||||
worker_factory: Arc<CliMainWorkerFactory>,
|
||||
permissions: Permissions,
|
||||
permissions_container: PermissionsContainer,
|
||||
specifier: ModuleSpecifier,
|
||||
sender: UnboundedSender<BenchEvent>,
|
||||
filter: TestFilter,
|
||||
) -> Result<(), AnyError> {
|
||||
match bench_specifier_inner(
|
||||
worker_factory,
|
||||
permissions,
|
||||
permissions_container,
|
||||
specifier.clone(),
|
||||
&sender,
|
||||
filter,
|
||||
@ -176,7 +177,7 @@ async fn bench_specifier(
|
||||
/// Run a single specifier as an executable bench module.
|
||||
async fn bench_specifier_inner(
|
||||
worker_factory: Arc<CliMainWorkerFactory>,
|
||||
permissions: Permissions,
|
||||
permissions_container: PermissionsContainer,
|
||||
specifier: ModuleSpecifier,
|
||||
sender: &UnboundedSender<BenchEvent>,
|
||||
filter: TestFilter,
|
||||
@ -185,7 +186,7 @@ async fn bench_specifier_inner(
|
||||
.create_custom_worker(
|
||||
WorkerExecutionMode::Bench,
|
||||
specifier.clone(),
|
||||
PermissionsContainer::new(permissions),
|
||||
permissions_container,
|
||||
vec![ops::bench::deno_bench::init_ops(sender.clone())],
|
||||
Default::default(),
|
||||
)
|
||||
@ -264,6 +265,7 @@ async fn bench_specifier_inner(
|
||||
async fn bench_specifiers(
|
||||
worker_factory: Arc<CliMainWorkerFactory>,
|
||||
permissions: &Permissions,
|
||||
permissions_desc_parser: &Arc<RuntimePermissionDescriptorParser>,
|
||||
specifiers: Vec<ModuleSpecifier>,
|
||||
options: BenchSpecifierOptions,
|
||||
) -> Result<(), AnyError> {
|
||||
@ -273,13 +275,16 @@ async fn bench_specifiers(
|
||||
|
||||
let join_handles = specifiers.into_iter().map(move |specifier| {
|
||||
let worker_factory = worker_factory.clone();
|
||||
let permissions = permissions.clone();
|
||||
let permissions_container = PermissionsContainer::new(
|
||||
permissions_desc_parser.clone(),
|
||||
permissions.clone(),
|
||||
);
|
||||
let sender = sender.clone();
|
||||
let options = option_for_handles.clone();
|
||||
spawn_blocking(move || {
|
||||
let future = bench_specifier(
|
||||
worker_factory,
|
||||
permissions,
|
||||
permissions_container,
|
||||
specifier,
|
||||
sender,
|
||||
options.filter,
|
||||
@ -410,8 +415,11 @@ pub async fn run_benchmarks(
|
||||
// Various bench files should not share the same permissions in terms of
|
||||
// `PermissionsContainer` - otherwise granting/revoking permissions in one
|
||||
// file would have impact on other files, which is undesirable.
|
||||
let permissions =
|
||||
Permissions::from_options(&cli_options.permissions_options()?)?;
|
||||
let permission_desc_parser = factory.permission_desc_parser()?.clone();
|
||||
let permissions = Permissions::from_options(
|
||||
permission_desc_parser.as_ref(),
|
||||
&cli_options.permissions_options(),
|
||||
)?;
|
||||
|
||||
let members_with_bench_options =
|
||||
cli_options.resolve_bench_options_for_members(&bench_flags)?;
|
||||
@ -446,6 +454,7 @@ pub async fn run_benchmarks(
|
||||
bench_specifiers(
|
||||
worker_factory,
|
||||
&permissions,
|
||||
&permission_desc_parser,
|
||||
specifiers,
|
||||
BenchSpecifierOptions {
|
||||
filter: TestFilter::from_flag(&workspace_bench_options.filter),
|
||||
@ -519,8 +528,11 @@ pub async fn run_benchmarks_with_watch(
|
||||
// Various bench files should not share the same permissions in terms of
|
||||
// `PermissionsContainer` - otherwise granting/revoking permissions in one
|
||||
// file would have impact on other files, which is undesirable.
|
||||
let permissions =
|
||||
Permissions::from_options(&cli_options.permissions_options()?)?;
|
||||
let permission_desc_parser = factory.permission_desc_parser()?.clone();
|
||||
let permissions = Permissions::from_options(
|
||||
permission_desc_parser.as_ref(),
|
||||
&cli_options.permissions_options(),
|
||||
)?;
|
||||
|
||||
let graph = module_graph_creator
|
||||
.create_graph(graph_kind, collected_bench_modules.clone())
|
||||
@ -568,6 +580,7 @@ pub async fn run_benchmarks_with_watch(
|
||||
bench_specifiers(
|
||||
worker_factory,
|
||||
&permissions,
|
||||
&permission_desc_parser,
|
||||
specifiers,
|
||||
BenchSpecifierOptions {
|
||||
filter: TestFilter::from_flag(&workspace_bench_options.filter),
|
||||
|
@ -25,7 +25,6 @@ use deno_core::serde_json::json;
|
||||
use deno_core::url::Url;
|
||||
use deno_runtime::deno_io::Stdio;
|
||||
use deno_runtime::deno_io::StdioPipe;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use deno_terminal::colors;
|
||||
@ -65,7 +64,8 @@ pub async fn kernel(
|
||||
resolve_url_or_path("./$deno$jupyter.ts", cli_options.initial_cwd())
|
||||
.unwrap();
|
||||
// TODO(bartlomieju): should we run with all permissions?
|
||||
let permissions = PermissionsContainer::new(Permissions::allow_all());
|
||||
let permissions =
|
||||
PermissionsContainer::allow_all(factory.permission_desc_parser()?.clone());
|
||||
let npm_resolver = factory.npm_resolver().await?.clone();
|
||||
let resolver = factory.resolver().await?.clone();
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
|
@ -106,7 +106,7 @@ pub async fn cache_top_level_deps(
|
||||
&roots,
|
||||
false,
|
||||
deno_config::deno_json::TsTypeLib::DenoWorker,
|
||||
deno_runtime::deno_permissions::PermissionsContainer::allow_all(),
|
||||
crate::file_fetcher::FetchPermissionsOption::AllowAll,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
@ -16,8 +16,6 @@ use deno_core::error::AnyError;
|
||||
use deno_core::futures::StreamExt;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::unsync::spawn_blocking;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use rustyline::error::ReadlineError;
|
||||
|
||||
@ -151,9 +149,7 @@ async fn read_eval_file(
|
||||
let specifier =
|
||||
deno_core::resolve_url_or_path(eval_file, cli_options.initial_cwd())?;
|
||||
|
||||
let file = file_fetcher
|
||||
.fetch(&specifier, &PermissionsContainer::allow_all())
|
||||
.await?;
|
||||
let file = file_fetcher.fetch_bypass_permissions(&specifier).await?;
|
||||
|
||||
Ok(file.into_text_decoded()?.source)
|
||||
}
|
||||
@ -166,9 +162,7 @@ pub async fn run(
|
||||
let factory = CliFactory::from_flags(flags);
|
||||
let cli_options = factory.cli_options()?;
|
||||
let main_module = cli_options.resolve_main_module()?;
|
||||
let permissions = PermissionsContainer::new(Permissions::from_options(
|
||||
&cli_options.permissions_options()?,
|
||||
)?);
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let npm_resolver = factory.npm_resolver().await?.clone();
|
||||
let resolver = factory.resolver().await?.clone();
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
|
@ -5,8 +5,6 @@ use std::sync::Arc;
|
||||
|
||||
use deno_config::deno_json::NodeModulesDirMode;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
|
||||
use crate::args::EvalFlags;
|
||||
@ -62,9 +60,7 @@ pub async fn run_script(
|
||||
|
||||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let permissions = PermissionsContainer::new(Permissions::from_options(
|
||||
&cli_options.permissions_options()?,
|
||||
)?);
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(mode, main_module, permissions)
|
||||
@ -83,9 +79,7 @@ pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
||||
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let permissions = PermissionsContainer::new(Permissions::from_options(
|
||||
&cli_options.permissions_options()?,
|
||||
)?);
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let mut source = Vec::new();
|
||||
std::io::stdin().read_to_end(&mut source)?;
|
||||
// Save a fake file into file fetcher cache
|
||||
@ -131,9 +125,7 @@ async fn run_with_watch(
|
||||
|
||||
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
||||
|
||||
let permissions = PermissionsContainer::new(Permissions::from_options(
|
||||
&cli_options.permissions_options()?,
|
||||
)?);
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let mut worker = factory
|
||||
.create_cli_main_worker_factory()
|
||||
.await?
|
||||
@ -181,9 +173,7 @@ pub async fn eval_command(
|
||||
source: source_code.into_bytes().into(),
|
||||
});
|
||||
|
||||
let permissions = PermissionsContainer::new(Permissions::from_options(
|
||||
&cli_options.permissions_options()?,
|
||||
)?);
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(WorkerExecutionMode::Eval, main_module, permissions)
|
||||
|
@ -5,7 +5,6 @@ use std::sync::Arc;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::TryFutureExt;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
|
||||
use super::run::check_permission_before_script;
|
||||
@ -45,9 +44,7 @@ pub async fn serve(
|
||||
|
||||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let permissions = PermissionsContainer::new(Permissions::from_options(
|
||||
&cli_options.permissions_options()?,
|
||||
)?);
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
|
||||
do_serve(
|
||||
@ -175,9 +172,7 @@ async fn serve_with_watch(
|
||||
|
||||
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
||||
|
||||
let permissions = PermissionsContainer::new(Permissions::from_options(
|
||||
&cli_options.permissions_options()?,
|
||||
)?);
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
|
||||
do_serve(worker_factory, main_module, permissions, worker_count, hmr)
|
||||
|
@ -56,6 +56,7 @@ use deno_runtime::deno_io::StdioPipe;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::fmt_errors::format_js_error;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use deno_runtime::tokio_util::create_and_run_current_thread;
|
||||
use deno_runtime::worker::MainWorker;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
@ -595,7 +596,7 @@ fn get_test_reporter(options: &TestSpecifiersOptions) -> Box<dyn TestReporter> {
|
||||
async fn configure_main_worker(
|
||||
worker_factory: Arc<CliMainWorkerFactory>,
|
||||
specifier: &Url,
|
||||
permissions: Permissions,
|
||||
permissions_container: PermissionsContainer,
|
||||
worker_sender: TestEventWorkerSender,
|
||||
options: &TestSpecifierOptions,
|
||||
) -> Result<(Option<Box<dyn CoverageCollector>>, MainWorker), anyhow::Error> {
|
||||
@ -603,7 +604,7 @@ async fn configure_main_worker(
|
||||
.create_custom_worker(
|
||||
WorkerExecutionMode::Test,
|
||||
specifier.clone(),
|
||||
PermissionsContainer::new(permissions),
|
||||
permissions_container,
|
||||
vec![ops::testing::deno_test::init_ops(worker_sender.sender)],
|
||||
Stdio {
|
||||
stdin: StdioPipe::inherit(),
|
||||
@ -646,7 +647,7 @@ async fn configure_main_worker(
|
||||
/// both.
|
||||
pub async fn test_specifier(
|
||||
worker_factory: Arc<CliMainWorkerFactory>,
|
||||
permissions: Permissions,
|
||||
permissions_container: PermissionsContainer,
|
||||
specifier: ModuleSpecifier,
|
||||
worker_sender: TestEventWorkerSender,
|
||||
fail_fast_tracker: FailFastTracker,
|
||||
@ -658,7 +659,7 @@ pub async fn test_specifier(
|
||||
let (coverage_collector, mut worker) = configure_main_worker(
|
||||
worker_factory,
|
||||
&specifier,
|
||||
permissions,
|
||||
permissions_container,
|
||||
worker_sender,
|
||||
&options,
|
||||
)
|
||||
@ -1327,9 +1328,8 @@ async fn fetch_inline_files(
|
||||
) -> Result<Vec<File>, AnyError> {
|
||||
let mut files = Vec::new();
|
||||
for specifier in specifiers {
|
||||
let fetch_permissions = PermissionsContainer::allow_all();
|
||||
let file = file_fetcher
|
||||
.fetch(&specifier, &fetch_permissions)
|
||||
.fetch_bypass_permissions(&specifier)
|
||||
.await?
|
||||
.into_text_decoded()?;
|
||||
|
||||
@ -1407,6 +1407,7 @@ static HAS_TEST_RUN_SIGINT_HANDLER: AtomicBool = AtomicBool::new(false);
|
||||
async fn test_specifiers(
|
||||
worker_factory: Arc<CliMainWorkerFactory>,
|
||||
permissions: &Permissions,
|
||||
permission_desc_parser: &Arc<RuntimePermissionDescriptorParser>,
|
||||
specifiers: Vec<ModuleSpecifier>,
|
||||
options: TestSpecifiersOptions,
|
||||
) -> Result<(), AnyError> {
|
||||
@ -1434,14 +1435,17 @@ async fn test_specifiers(
|
||||
|
||||
let join_handles = specifiers.into_iter().map(move |specifier| {
|
||||
let worker_factory = worker_factory.clone();
|
||||
let permissions = permissions.clone();
|
||||
let permissions_container = PermissionsContainer::new(
|
||||
permission_desc_parser.clone(),
|
||||
permissions.clone(),
|
||||
);
|
||||
let worker_sender = test_event_sender_factory.worker();
|
||||
let fail_fast_tracker = fail_fast_tracker.clone();
|
||||
let specifier_options = options.specifier.clone();
|
||||
spawn_blocking(move || {
|
||||
create_and_run_current_thread(test_specifier(
|
||||
worker_factory,
|
||||
permissions,
|
||||
permissions_container,
|
||||
specifier,
|
||||
worker_sender,
|
||||
fail_fast_tracker,
|
||||
@ -1739,9 +1743,7 @@ async fn fetch_specifiers_with_test_mode(
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (specifier, mode) in &mut specifiers_with_mode {
|
||||
let file = file_fetcher
|
||||
.fetch(specifier, &PermissionsContainer::allow_all())
|
||||
.await?;
|
||||
let file = file_fetcher.fetch_bypass_permissions(specifier).await?;
|
||||
|
||||
let (media_type, _) = file.resolve_media_type_and_charset();
|
||||
if matches!(media_type, MediaType::Unknown | MediaType::Dts) {
|
||||
@ -1764,8 +1766,11 @@ pub async fn run_tests(
|
||||
// Various test files should not share the same permissions in terms of
|
||||
// `PermissionsContainer` - otherwise granting/revoking permissions in one
|
||||
// file would have impact on other files, which is undesirable.
|
||||
let permissions =
|
||||
Permissions::from_options(&cli_options.permissions_options()?)?;
|
||||
let permission_desc_parser = factory.permission_desc_parser()?;
|
||||
let permissions = Permissions::from_options(
|
||||
permission_desc_parser.as_ref(),
|
||||
&cli_options.permissions_options(),
|
||||
)?;
|
||||
let log_level = cli_options.log_level();
|
||||
|
||||
let members_with_test_options =
|
||||
@ -1802,6 +1807,7 @@ pub async fn run_tests(
|
||||
test_specifiers(
|
||||
worker_factory,
|
||||
&permissions,
|
||||
permission_desc_parser,
|
||||
specifiers_with_mode
|
||||
.into_iter()
|
||||
.filter_map(|(s, m)| match m {
|
||||
@ -1914,8 +1920,11 @@ pub async fn run_tests_with_watch(
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let permissions =
|
||||
Permissions::from_options(&cli_options.permissions_options()?)?;
|
||||
let permission_desc_parser = factory.permission_desc_parser()?;
|
||||
let permissions = Permissions::from_options(
|
||||
permission_desc_parser.as_ref(),
|
||||
&cli_options.permissions_options(),
|
||||
)?;
|
||||
let graph = module_graph_creator
|
||||
.create_graph(graph_kind, test_modules)
|
||||
.await?;
|
||||
@ -1969,6 +1978,7 @@ pub async fn run_tests_with_watch(
|
||||
test_specifiers(
|
||||
worker_factory,
|
||||
&permissions,
|
||||
permission_desc_parser,
|
||||
specifiers_with_mode
|
||||
.into_iter()
|
||||
.filter_map(|(s, m)| match m {
|
||||
|
@ -30,6 +30,7 @@ use deno_runtime::deno_web::BlobStore;
|
||||
use deno_runtime::fmt_errors::format_js_error;
|
||||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use deno_runtime::ops::worker_host::CreateWebWorkerCb;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use deno_runtime::web_worker::WebWorker;
|
||||
use deno_runtime::web_worker::WebWorkerOptions;
|
||||
use deno_runtime::worker::MainWorker;
|
||||
@ -121,23 +122,24 @@ pub struct CliMainWorkerOptions {
|
||||
}
|
||||
|
||||
struct SharedWorkerState {
|
||||
options: CliMainWorkerOptions,
|
||||
subcommand: DenoSubcommand,
|
||||
storage_key_resolver: StorageKeyResolver,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
blob_store: Arc<BlobStore>,
|
||||
broadcast_channel: InMemoryBroadcastChannel,
|
||||
shared_array_buffer_store: SharedArrayBufferStore,
|
||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||
compiled_wasm_module_store: CompiledWasmModuleStore,
|
||||
module_loader_factory: Box<dyn ModuleLoaderFactory>,
|
||||
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
|
||||
feature_checker: Arc<FeatureChecker>,
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
maybe_file_watcher_communicator: Option<Arc<WatcherCommunicator>>,
|
||||
maybe_inspector_server: Option<Arc<InspectorServer>>,
|
||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||
feature_checker: Arc<FeatureChecker>,
|
||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||
module_loader_factory: Box<dyn ModuleLoaderFactory>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
permission_desc_parser: Arc<RuntimePermissionDescriptorParser>,
|
||||
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
|
||||
shared_array_buffer_store: SharedArrayBufferStore,
|
||||
storage_key_resolver: StorageKeyResolver,
|
||||
options: CliMainWorkerOptions,
|
||||
subcommand: DenoSubcommand,
|
||||
}
|
||||
|
||||
impl SharedWorkerState {
|
||||
@ -418,40 +420,42 @@ pub struct CliMainWorkerFactory {
|
||||
impl CliMainWorkerFactory {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
storage_key_resolver: StorageKeyResolver,
|
||||
subcommand: DenoSubcommand,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
blob_store: Arc<BlobStore>,
|
||||
module_loader_factory: Box<dyn ModuleLoaderFactory>,
|
||||
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
|
||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||
feature_checker: Arc<FeatureChecker>,
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
maybe_file_watcher_communicator: Option<Arc<WatcherCommunicator>>,
|
||||
maybe_inspector_server: Option<Arc<InspectorServer>>,
|
||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||
feature_checker: Arc<FeatureChecker>,
|
||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||
module_loader_factory: Box<dyn ModuleLoaderFactory>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
permission_parser: Arc<RuntimePermissionDescriptorParser>,
|
||||
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
|
||||
storage_key_resolver: StorageKeyResolver,
|
||||
subcommand: DenoSubcommand,
|
||||
options: CliMainWorkerOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
shared: Arc::new(SharedWorkerState {
|
||||
options,
|
||||
subcommand,
|
||||
storage_key_resolver,
|
||||
npm_resolver,
|
||||
node_resolver,
|
||||
blob_store,
|
||||
broadcast_channel: Default::default(),
|
||||
shared_array_buffer_store: Default::default(),
|
||||
code_cache,
|
||||
compiled_wasm_module_store: Default::default(),
|
||||
module_loader_factory,
|
||||
root_cert_store_provider,
|
||||
feature_checker,
|
||||
fs,
|
||||
maybe_file_watcher_communicator,
|
||||
maybe_inspector_server,
|
||||
maybe_lockfile,
|
||||
feature_checker,
|
||||
code_cache,
|
||||
module_loader_factory,
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
permission_desc_parser: permission_parser,
|
||||
root_cert_store_provider,
|
||||
shared_array_buffer_store: Default::default(),
|
||||
storage_key_resolver,
|
||||
options,
|
||||
subcommand,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -525,9 +529,13 @@ impl CliMainWorkerFactory {
|
||||
(main_module, false)
|
||||
};
|
||||
|
||||
let ModuleLoaderAndSourceMapGetter { module_loader } = shared
|
||||
.module_loader_factory
|
||||
.create_for_main(PermissionsContainer::allow_all(), permissions.clone());
|
||||
let ModuleLoaderAndSourceMapGetter { module_loader } =
|
||||
shared.module_loader_factory.create_for_main(
|
||||
PermissionsContainer::allow_all(
|
||||
self.shared.permission_desc_parser.clone(),
|
||||
),
|
||||
permissions.clone(),
|
||||
);
|
||||
let maybe_inspector_server = shared.maybe_inspector_server.clone();
|
||||
|
||||
let create_web_worker_cb =
|
||||
@ -619,6 +627,7 @@ impl CliMainWorkerFactory {
|
||||
),
|
||||
stdio,
|
||||
feature_checker,
|
||||
permission_desc_parser: shared.permission_desc_parser.clone(),
|
||||
skip_op_registration: shared.options.skip_op_registration,
|
||||
v8_code_cache: shared.code_cache.clone(),
|
||||
};
|
||||
@ -809,6 +818,7 @@ fn create_web_worker_callback(
|
||||
stdio: stdio.clone(),
|
||||
cache_storage_dir,
|
||||
feature_checker,
|
||||
permission_desc_parser: shared.permission_desc_parser.clone(),
|
||||
strace_ops: shared.options.strace_ops.clone(),
|
||||
close_on_idle: args.close_on_idle,
|
||||
maybe_worker_metadata: args.maybe_worker_metadata,
|
||||
@ -830,13 +840,16 @@ fn create_web_worker_callback(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use deno_core::resolve_path;
|
||||
use deno_fs::RealFs;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
|
||||
fn create_test_worker() -> MainWorker {
|
||||
let main_module =
|
||||
resolve_path("./hello.js", &std::env::current_dir().unwrap()).unwrap();
|
||||
let permissions =
|
||||
PermissionsContainer::new(Permissions::none_without_prompt());
|
||||
let permissions = PermissionsContainer::new(
|
||||
Arc::new(RuntimePermissionDescriptorParser::new(Arc::new(RealFs))),
|
||||
Permissions::none_without_prompt(),
|
||||
);
|
||||
|
||||
let options = WorkerOptions {
|
||||
startup_snapshot: crate::js::deno_isolate_init(),
|
||||
|
@ -299,10 +299,15 @@ impl Drop for ResourceToBodyAdapter {
|
||||
pub trait FetchPermissions {
|
||||
fn check_net_url(
|
||||
&mut self,
|
||||
_url: &Url,
|
||||
url: &Url,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_read(&mut self, _p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_read<'a>(
|
||||
&mut self,
|
||||
p: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
}
|
||||
|
||||
impl FetchPermissions for deno_permissions::PermissionsContainer {
|
||||
@ -316,12 +321,16 @@ impl FetchPermissions for deno_permissions::PermissionsContainer {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_read(
|
||||
fn check_read<'a>(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_read(self, path, api_name)
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_read_path(
|
||||
self,
|
||||
path,
|
||||
Some(api_name),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -359,7 +368,11 @@ where
|
||||
type_error("NetworkError when attempting to fetch resource")
|
||||
})?;
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_read(&path, "fetch()")?;
|
||||
let path = permissions.check_read(&path, "fetch()")?;
|
||||
let url = match path {
|
||||
Cow::Owned(path) => Url::from_file_path(path).unwrap(),
|
||||
Cow::Borrowed(_) => url,
|
||||
};
|
||||
|
||||
if method != Method::GET {
|
||||
return Err(type_error(format!(
|
||||
|
@ -287,7 +287,7 @@ where
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
};
|
||||
|
||||
let symbol = PtrSymbol::new(pointer, &def)?;
|
||||
@ -384,7 +384,7 @@ where
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
};
|
||||
|
||||
let symbol = PtrSymbol::new(pointer, &def)?;
|
||||
|
@ -557,7 +557,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
let thread_id: u32 = LOCAL_THREAD_ID.with(|s| {
|
||||
let value = *s.borrow();
|
||||
|
@ -19,7 +19,6 @@ use serde_value::ValueDeserializer;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::c_void;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct DynamicLibraryResource {
|
||||
@ -121,15 +120,13 @@ pub fn op_ffi_load<'scope, FP>(
|
||||
where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let path = args.path;
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(Some(&PathBuf::from(&path)))?;
|
||||
let path = permissions.check_partial_with_path(&args.path)?;
|
||||
|
||||
let lib = Library::open(&path).map_err(|e| {
|
||||
dlopen2::Error::OpeningLibraryError(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format_error(e, path),
|
||||
format_error(e, &path),
|
||||
))
|
||||
})?;
|
||||
let mut resource = DynamicLibraryResource {
|
||||
@ -290,7 +287,10 @@ fn sync_fn_impl<'s>(
|
||||
|
||||
// `path` is only used on Windows.
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) fn format_error(e: dlopen2::Error, path: String) -> String {
|
||||
pub(crate) fn format_error(
|
||||
e: dlopen2::Error,
|
||||
path: &std::path::Path,
|
||||
) -> String {
|
||||
match e {
|
||||
#[cfg(target_os = "windows")]
|
||||
// This calls FormatMessageW with library path
|
||||
@ -300,7 +300,6 @@ pub(crate) fn format_error(e: dlopen2::Error, path: String) -> String {
|
||||
//
|
||||
// https://github.com/denoland/deno/issues/11632
|
||||
dlopen2::Error::OpeningLibraryError(e) => {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER;
|
||||
@ -324,7 +323,8 @@ pub(crate) fn format_error(e: dlopen2::Error, path: String) -> String {
|
||||
|
||||
let mut buf = vec![0; 500];
|
||||
|
||||
let path = OsStr::new(&path)
|
||||
let path = path
|
||||
.as_os_str()
|
||||
.encode_wide()
|
||||
.chain(Some(0))
|
||||
.collect::<Vec<_>>();
|
||||
@ -384,7 +384,7 @@ mod tests {
|
||||
std::io::Error::from_raw_os_error(0x000000C1),
|
||||
);
|
||||
assert_eq!(
|
||||
format_error(err, "foo.dll".to_string()),
|
||||
format_error(err, &std::path::PathBuf::from("foo.dll")),
|
||||
"foo.dll is not a valid Win32 application.\r\n".to_string(),
|
||||
);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use deno_core::error::AnyError;
|
||||
use std::mem::size_of;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::raw::c_short;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod call;
|
||||
mod callback;
|
||||
@ -41,13 +41,28 @@ const _: () = {
|
||||
pub const UNSTABLE_FEATURE_NAME: &str = "ffi";
|
||||
|
||||
pub trait FfiPermissions {
|
||||
fn check_partial(&mut self, path: Option<&Path>) -> Result<(), AnyError>;
|
||||
fn check_partial_no_path(&mut self) -> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_partial_with_path(
|
||||
&mut self,
|
||||
path: &str,
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
}
|
||||
|
||||
impl FfiPermissions for deno_permissions::PermissionsContainer {
|
||||
#[inline(always)]
|
||||
fn check_partial(&mut self, path: Option<&Path>) -> Result<(), AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_ffi_partial(self, path)
|
||||
fn check_partial_no_path(&mut self) -> Result<(), AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_ffi_partial_no_path(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_partial_with_path(
|
||||
&mut self,
|
||||
path: &str,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_ffi_partial_with_path(
|
||||
self, path,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
Ok(ptr_number as *mut c_void)
|
||||
}
|
||||
@ -36,7 +36,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
Ok(a == b)
|
||||
}
|
||||
@ -50,7 +50,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
Ok(buf as *mut c_void)
|
||||
}
|
||||
@ -64,7 +64,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
let Some(buf) = buf.get_backing_store() else {
|
||||
return Ok(0 as _);
|
||||
@ -85,7 +85,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid pointer to offset, pointer is null"));
|
||||
@ -115,7 +115,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
Ok(ptr as usize)
|
||||
}
|
||||
@ -132,7 +132,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid ArrayBuffer pointer, pointer is null"));
|
||||
@ -164,7 +164,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if src.is_null() {
|
||||
Err(type_error("Invalid ArrayBuffer pointer, pointer is null"))
|
||||
@ -195,7 +195,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid CString pointer, pointer is null"));
|
||||
@ -221,7 +221,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid bool pointer, pointer is null"));
|
||||
@ -241,7 +241,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid u8 pointer, pointer is null"));
|
||||
@ -263,7 +263,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid i8 pointer, pointer is null"));
|
||||
@ -285,7 +285,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid u16 pointer, pointer is null"));
|
||||
@ -307,7 +307,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid i16 pointer, pointer is null"));
|
||||
@ -329,7 +329,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid u32 pointer, pointer is null"));
|
||||
@ -349,7 +349,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid i32 pointer, pointer is null"));
|
||||
@ -372,7 +372,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid u64 pointer, pointer is null"));
|
||||
@ -398,7 +398,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid i64 pointer, pointer is null"));
|
||||
@ -421,7 +421,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid f32 pointer, pointer is null"));
|
||||
@ -441,7 +441,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid f64 pointer, pointer is null"));
|
||||
@ -461,7 +461,7 @@ where
|
||||
FP: FfiPermissions + 'static,
|
||||
{
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check_partial(None)?;
|
||||
permissions.check_partial_no_path()?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid pointer pointer, pointer is null"));
|
||||
|
@ -24,6 +24,7 @@ use deno_core::error::AnyError;
|
||||
use deno_io::fs::FsError;
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub trait FsPermissions {
|
||||
fn check_open<'a>(
|
||||
@ -34,8 +35,18 @@ pub trait FsPermissions {
|
||||
path: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<std::borrow::Cow<'a, Path>, FsError>;
|
||||
fn check_read(&mut self, path: &Path, api_name: &str)
|
||||
-> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_read(
|
||||
&mut self,
|
||||
path: &str,
|
||||
api_name: &str,
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_read_path<'a>(
|
||||
&mut self,
|
||||
path: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
fn check_read_all(&mut self, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_read_blind(
|
||||
&mut self,
|
||||
@ -43,16 +54,24 @@ pub trait FsPermissions {
|
||||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_write(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_write_path<'a>(
|
||||
&mut self,
|
||||
path: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_write_partial(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
fn check_write_all(&mut self, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write_blind(
|
||||
&mut self,
|
||||
@ -96,25 +115,44 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
|
||||
|
||||
// If somehow read or write aren't specified, use read
|
||||
let read = read || !write;
|
||||
let mut path: Cow<'a, Path> = Cow::Borrowed(path);
|
||||
if read {
|
||||
FsPermissions::check_read(self, path, api_name)
|
||||
let resolved_path = FsPermissions::check_read_path(self, &path, api_name)
|
||||
.map_err(|_| FsError::NotCapable("read"))?;
|
||||
if let Cow::Owned(resolved_path) = resolved_path {
|
||||
path = Cow::Owned(resolved_path);
|
||||
}
|
||||
}
|
||||
if write {
|
||||
FsPermissions::check_write(self, path, api_name)
|
||||
.map_err(|_| FsError::NotCapable("write"))?;
|
||||
let resolved_path =
|
||||
FsPermissions::check_write_path(self, &path, api_name)
|
||||
.map_err(|_| FsError::NotCapable("write"))?;
|
||||
if let Cow::Owned(resolved_path) = resolved_path {
|
||||
path = Cow::Owned(resolved_path);
|
||||
}
|
||||
}
|
||||
Ok(Cow::Borrowed(path))
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn check_read(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_read(self, path, api_name)
|
||||
}
|
||||
|
||||
fn check_read_path<'a>(
|
||||
&mut self,
|
||||
path: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_read_path(
|
||||
self,
|
||||
path,
|
||||
Some(api_name),
|
||||
)
|
||||
}
|
||||
fn check_read_blind(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
@ -128,17 +166,27 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
|
||||
|
||||
fn check_write(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_write(self, path, api_name)
|
||||
}
|
||||
|
||||
fn check_write_path<'a>(
|
||||
&mut self,
|
||||
path: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_write_path(
|
||||
self, path, api_name,
|
||||
)
|
||||
}
|
||||
|
||||
fn check_write_partial(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_write_partial(
|
||||
self, path, api_name,
|
||||
)
|
||||
|
302
ext/fs/ops.rs
302
ext/fs/ops.rs
@ -5,6 +5,7 @@ use std::io;
|
||||
use std::io::SeekFrom;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::path::StripPrefixError;
|
||||
use std::rc::Rc;
|
||||
|
||||
use deno_core::anyhow::bail;
|
||||
@ -105,8 +106,9 @@ pub fn op_fs_chdir<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let d = PathBuf::from(&directory);
|
||||
state.borrow_mut::<P>().check_read(&d, "Deno.chdir()")?;
|
||||
let d = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read(directory, "Deno.chdir()")?;
|
||||
state
|
||||
.borrow::<FileSystemRc>()
|
||||
.chdir(&d)
|
||||
@ -188,11 +190,9 @@ pub fn op_fs_mkdir_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let mode = mode.unwrap_or(0o777) & 0o777;
|
||||
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.mkdirSync()")?;
|
||||
|
||||
@ -213,14 +213,12 @@ pub async fn op_fs_mkdir_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let mode = mode.unwrap_or(0o777) & 0o777;
|
||||
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<P>().check_write(&path, "Deno.mkdir()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
let path = state.borrow_mut::<P>().check_write(&path, "Deno.mkdir()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
fs.mkdir_async(path.clone(), recursive, mode)
|
||||
@ -239,8 +237,7 @@ pub fn op_fs_chmod_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.chmodSync()")?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
@ -257,11 +254,10 @@ pub async fn op_fs_chmod_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<P>().check_write(&path, "Deno.chmod()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
let path = state.borrow_mut::<P>().check_write(&path, "Deno.chmod()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
fs.chmod_async(path.clone(), mode)
|
||||
.await
|
||||
@ -279,8 +275,7 @@ pub fn op_fs_chown_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.chownSync()")?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
@ -299,11 +294,10 @@ pub async fn op_fs_chown_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<P>().check_write(&path, "Deno.chown()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
let path = state.borrow_mut::<P>().check_write(&path, "Deno.chown()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
fs.chown_async(path.clone(), uid, gid)
|
||||
.await
|
||||
@ -320,11 +314,9 @@ pub fn op_fs_remove_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.removeSync()")?;
|
||||
.check_write(path, "Deno.removeSync()")?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.remove_sync(&path, recursive)
|
||||
@ -342,21 +334,19 @@ pub async fn op_fs_remove_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
if recursive {
|
||||
let path = if recursive {
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.remove()")?;
|
||||
.check_write(&path, "Deno.remove()")?
|
||||
} else {
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_write_partial(&path, "Deno.remove()")?;
|
||||
}
|
||||
.check_write_partial(&path, "Deno.remove()")?
|
||||
};
|
||||
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
fs.remove_async(path.clone(), recursive)
|
||||
@ -375,12 +365,9 @@ pub fn op_fs_copy_file_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let from = PathBuf::from(from);
|
||||
let to = PathBuf::from(to);
|
||||
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&from, "Deno.copyFileSync()")?;
|
||||
permissions.check_write(&to, "Deno.copyFileSync()")?;
|
||||
let from = permissions.check_read(from, "Deno.copyFileSync()")?;
|
||||
let to = permissions.check_write(to, "Deno.copyFileSync()")?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.copy_file_sync(&from, &to)
|
||||
@ -398,15 +385,12 @@ pub async fn op_fs_copy_file_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let from = PathBuf::from(from);
|
||||
let to = PathBuf::from(to);
|
||||
|
||||
let fs = {
|
||||
let (fs, from, to) = {
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&from, "Deno.copyFile()")?;
|
||||
permissions.check_write(&to, "Deno.copyFile()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
let from = permissions.check_read(&from, "Deno.copyFile()")?;
|
||||
let to = permissions.check_write(&to, "Deno.copyFile()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), from, to)
|
||||
};
|
||||
|
||||
fs.copy_file_async(from.clone(), to.clone())
|
||||
@ -425,8 +409,7 @@ pub fn op_fs_stat_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read(&path, "Deno.statSync()")?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
@ -445,12 +428,11 @@ pub async fn op_fs_stat_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&path, "Deno.stat()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
let path = permissions.check_read(&path, "Deno.stat()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
let stat = fs
|
||||
.stat_async(path.clone())
|
||||
@ -468,8 +450,7 @@ pub fn op_fs_lstat_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read(&path, "Deno.lstatSync()")?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
@ -488,12 +469,11 @@ pub async fn op_fs_lstat_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&path, "Deno.lstat()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
let path = permissions.check_read(&path, "Deno.lstat()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
let stat = fs
|
||||
.lstat_async(path.clone())
|
||||
@ -511,11 +491,9 @@ pub fn op_fs_realpath_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>().clone();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&path, "Deno.realPathSync()")?;
|
||||
let path = permissions.check_read(&path, "Deno.realPathSync()")?;
|
||||
if path.is_relative() {
|
||||
permissions.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPathSync()")?;
|
||||
}
|
||||
@ -536,18 +514,16 @@ pub async fn op_fs_realpath_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs;
|
||||
{
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
fs = state.borrow::<FileSystemRc>().clone();
|
||||
let fs = state.borrow::<FileSystemRc>().clone();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&path, "Deno.realPath()")?;
|
||||
let path = permissions.check_read(&path, "Deno.realPath()")?;
|
||||
if path.is_relative() {
|
||||
permissions.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPath()")?;
|
||||
}
|
||||
}
|
||||
(fs, path)
|
||||
};
|
||||
let resolved_path = fs
|
||||
.realpath_async(path.clone())
|
||||
.await
|
||||
@ -566,9 +542,7 @@ pub fn op_fs_read_dir_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read(&path, "Deno.readDirSync()")?;
|
||||
|
||||
@ -587,14 +561,12 @@ pub async fn op_fs_read_dir_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read(&path, "Deno.readDir()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
let entries = fs
|
||||
@ -614,13 +586,10 @@ pub fn op_fs_rename_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let oldpath = PathBuf::from(oldpath);
|
||||
let newpath = PathBuf::from(newpath);
|
||||
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&oldpath, "Deno.renameSync()")?;
|
||||
permissions.check_write(&oldpath, "Deno.renameSync()")?;
|
||||
permissions.check_write(&newpath, "Deno.renameSync()")?;
|
||||
let _ = permissions.check_read(&oldpath, "Deno.renameSync()")?;
|
||||
let oldpath = permissions.check_write(&oldpath, "Deno.renameSync()")?;
|
||||
let newpath = permissions.check_write(&newpath, "Deno.renameSync()")?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.rename_sync(&oldpath, &newpath)
|
||||
@ -638,16 +607,13 @@ pub async fn op_fs_rename_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let oldpath = PathBuf::from(oldpath);
|
||||
let newpath = PathBuf::from(newpath);
|
||||
|
||||
let fs = {
|
||||
let (fs, oldpath, newpath) = {
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&oldpath, "Deno.rename()")?;
|
||||
permissions.check_write(&oldpath, "Deno.rename()")?;
|
||||
permissions.check_write(&newpath, "Deno.rename()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
_ = permissions.check_read(&oldpath, "Deno.rename()")?;
|
||||
let oldpath = permissions.check_write(&oldpath, "Deno.rename()")?;
|
||||
let newpath = permissions.check_write(&newpath, "Deno.rename()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), oldpath, newpath)
|
||||
};
|
||||
|
||||
fs.rename_async(oldpath.clone(), newpath.clone())
|
||||
@ -666,14 +632,11 @@ pub fn op_fs_link_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let oldpath = PathBuf::from(oldpath);
|
||||
let newpath = PathBuf::from(newpath);
|
||||
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&oldpath, "Deno.linkSync()")?;
|
||||
permissions.check_write(&oldpath, "Deno.linkSync()")?;
|
||||
permissions.check_read(&newpath, "Deno.linkSync()")?;
|
||||
permissions.check_write(&newpath, "Deno.linkSync()")?;
|
||||
_ = permissions.check_read(oldpath, "Deno.linkSync()")?;
|
||||
let oldpath = permissions.check_write(oldpath, "Deno.linkSync()")?;
|
||||
_ = permissions.check_read(newpath, "Deno.linkSync()")?;
|
||||
let newpath = permissions.check_write(newpath, "Deno.linkSync()")?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.link_sync(&oldpath, &newpath)
|
||||
@ -691,17 +654,14 @@ pub async fn op_fs_link_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let oldpath = PathBuf::from(&oldpath);
|
||||
let newpath = PathBuf::from(&newpath);
|
||||
|
||||
let fs = {
|
||||
let (fs, oldpath, newpath) = {
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(&oldpath, "Deno.link()")?;
|
||||
permissions.check_write(&oldpath, "Deno.link()")?;
|
||||
permissions.check_read(&newpath, "Deno.link()")?;
|
||||
permissions.check_write(&newpath, "Deno.link()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
_ = permissions.check_read(&oldpath, "Deno.link()")?;
|
||||
let oldpath = permissions.check_write(&oldpath, "Deno.link()")?;
|
||||
_ = permissions.check_read(&newpath, "Deno.link()")?;
|
||||
let newpath = permissions.check_write(&newpath, "Deno.link()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), oldpath, newpath)
|
||||
};
|
||||
|
||||
fs.link_async(oldpath.clone(), newpath.clone())
|
||||
@ -772,9 +732,7 @@ pub fn op_fs_read_link_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read(&path, "Deno.readLink()")?;
|
||||
|
||||
@ -794,14 +752,12 @@ pub async fn op_fs_read_link_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read(&path, "Deno.readLink()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
let target = fs
|
||||
@ -821,11 +777,9 @@ pub fn op_fs_truncate_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.truncateSync()")?;
|
||||
.check_write(path, "Deno.truncateSync()")?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.truncate_sync(&path, len)
|
||||
@ -843,14 +797,12 @@ pub async fn op_fs_truncate_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.truncate()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
fs.truncate_async(path.clone(), len)
|
||||
@ -872,9 +824,7 @@ pub fn op_fs_utime_sync<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
state.borrow_mut::<P>().check_write(&path, "Deno.utime()")?;
|
||||
let path = state.borrow_mut::<P>().check_write(path, "Deno.utime()")?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.utime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
|
||||
@ -895,12 +845,10 @@ pub async fn op_fs_utime_async<P>(
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state.borrow_mut::<P>().check_write(&path, "Deno.utime()")?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
let path = state.borrow_mut::<P>().check_write(&path, "Deno.utime()")?;
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
fs.utime_async(
|
||||
@ -920,15 +868,18 @@ where
|
||||
#[string]
|
||||
pub fn op_fs_make_temp_dir_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] dir: Option<String>,
|
||||
#[string] dir_arg: Option<String>,
|
||||
#[string] prefix: Option<String>,
|
||||
#[string] suffix: Option<String>,
|
||||
) -> Result<String, AnyError>
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let (dir, fs) =
|
||||
make_temp_check_sync::<P>(state, dir, "Deno.makeTempDirSync()")?;
|
||||
let (dir, fs) = make_temp_check_sync::<P>(
|
||||
state,
|
||||
dir_arg.as_deref(),
|
||||
"Deno.makeTempDirSync()",
|
||||
)?;
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
@ -936,7 +887,11 @@ where
|
||||
for _ in 0..MAX_TRIES {
|
||||
let path = tmp_name(&mut rng, &dir, prefix.as_deref(), suffix.as_deref())?;
|
||||
match fs.mkdir_sync(&path, false, 0o700) {
|
||||
Ok(_) => return path_into_string(path.into_os_string()),
|
||||
Ok(_) => {
|
||||
// PERMISSIONS: ensure the absolute path is not leaked
|
||||
let path = strip_dir_prefix(&dir, dir_arg.as_deref(), path)?;
|
||||
return path_into_string(path.into_os_string());
|
||||
}
|
||||
Err(FsError::Io(ref e)) if e.kind() == io::ErrorKind::AlreadyExists => {
|
||||
continue;
|
||||
}
|
||||
@ -955,14 +910,18 @@ where
|
||||
#[string]
|
||||
pub async fn op_fs_make_temp_dir_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] dir: Option<String>,
|
||||
#[string] dir_arg: Option<String>,
|
||||
#[string] prefix: Option<String>,
|
||||
#[string] suffix: Option<String>,
|
||||
) -> Result<String, AnyError>
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let (dir, fs) = make_temp_check_async::<P>(state, dir, "Deno.makeTempDir()")?;
|
||||
let (dir, fs) = make_temp_check_async::<P>(
|
||||
state,
|
||||
dir_arg.as_deref(),
|
||||
"Deno.makeTempDir()",
|
||||
)?;
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
@ -970,7 +929,11 @@ where
|
||||
for _ in 0..MAX_TRIES {
|
||||
let path = tmp_name(&mut rng, &dir, prefix.as_deref(), suffix.as_deref())?;
|
||||
match fs.clone().mkdir_async(path.clone(), false, 0o700).await {
|
||||
Ok(_) => return path_into_string(path.into_os_string()),
|
||||
Ok(_) => {
|
||||
// PERMISSIONS: ensure the absolute path is not leaked
|
||||
let path = strip_dir_prefix(&dir, dir_arg.as_deref(), path)?;
|
||||
return path_into_string(path.into_os_string());
|
||||
}
|
||||
Err(FsError::Io(ref e)) if e.kind() == io::ErrorKind::AlreadyExists => {
|
||||
continue;
|
||||
}
|
||||
@ -989,15 +952,18 @@ where
|
||||
#[string]
|
||||
pub fn op_fs_make_temp_file_sync<P>(
|
||||
state: &mut OpState,
|
||||
#[string] dir: Option<String>,
|
||||
#[string] dir_arg: Option<String>,
|
||||
#[string] prefix: Option<String>,
|
||||
#[string] suffix: Option<String>,
|
||||
) -> Result<String, AnyError>
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let (dir, fs) =
|
||||
make_temp_check_sync::<P>(state, dir, "Deno.makeTempFileSync()")?;
|
||||
let (dir, fs) = make_temp_check_sync::<P>(
|
||||
state,
|
||||
dir_arg.as_deref(),
|
||||
"Deno.makeTempFileSync()",
|
||||
)?;
|
||||
|
||||
let open_opts = OpenOptions {
|
||||
write: true,
|
||||
@ -1011,7 +977,11 @@ where
|
||||
for _ in 0..MAX_TRIES {
|
||||
let path = tmp_name(&mut rng, &dir, prefix.as_deref(), suffix.as_deref())?;
|
||||
match fs.open_sync(&path, open_opts, None) {
|
||||
Ok(_) => return path_into_string(path.into_os_string()),
|
||||
Ok(_) => {
|
||||
// PERMISSIONS: ensure the absolute path is not leaked
|
||||
let path = strip_dir_prefix(&dir, dir_arg.as_deref(), path)?;
|
||||
return path_into_string(path.into_os_string());
|
||||
}
|
||||
Err(FsError::Io(ref e)) if e.kind() == io::ErrorKind::AlreadyExists => {
|
||||
continue;
|
||||
}
|
||||
@ -1030,15 +1000,18 @@ where
|
||||
#[string]
|
||||
pub async fn op_fs_make_temp_file_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] dir: Option<String>,
|
||||
#[string] dir_arg: Option<String>,
|
||||
#[string] prefix: Option<String>,
|
||||
#[string] suffix: Option<String>,
|
||||
) -> Result<String, AnyError>
|
||||
where
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let (dir, fs) =
|
||||
make_temp_check_async::<P>(state, dir, "Deno.makeTempFile()")?;
|
||||
let (dir, fs) = make_temp_check_async::<P>(
|
||||
state,
|
||||
dir_arg.as_deref(),
|
||||
"Deno.makeTempFile()",
|
||||
)?;
|
||||
|
||||
let open_opts = OpenOptions {
|
||||
write: true,
|
||||
@ -1053,7 +1026,11 @@ where
|
||||
for _ in 0..MAX_TRIES {
|
||||
let path = tmp_name(&mut rng, &dir, prefix.as_deref(), suffix.as_deref())?;
|
||||
match fs.clone().open_async(path.clone(), open_opts, None).await {
|
||||
Ok(_) => return path_into_string(path.into_os_string()),
|
||||
Ok(_) => {
|
||||
// PERMISSIONS: ensure the absolute path is not leaked
|
||||
let path = strip_dir_prefix(&dir, dir_arg.as_deref(), path)?;
|
||||
return path_into_string(path.into_os_string());
|
||||
}
|
||||
Err(FsError::Io(ref e)) if e.kind() == io::ErrorKind::AlreadyExists => {
|
||||
continue;
|
||||
}
|
||||
@ -1067,9 +1044,26 @@ where
|
||||
.context("tmpfile")
|
||||
}
|
||||
|
||||
fn strip_dir_prefix(
|
||||
resolved_dir: &Path,
|
||||
dir_arg: Option<&str>,
|
||||
result_path: PathBuf,
|
||||
) -> Result<PathBuf, StripPrefixError> {
|
||||
if resolved_dir.is_absolute() {
|
||||
match &dir_arg {
|
||||
Some(dir_arg) => {
|
||||
Ok(Path::new(dir_arg).join(result_path.strip_prefix(resolved_dir)?))
|
||||
}
|
||||
None => Ok(result_path),
|
||||
}
|
||||
} else {
|
||||
Ok(result_path)
|
||||
}
|
||||
}
|
||||
|
||||
fn make_temp_check_sync<P>(
|
||||
state: &mut OpState,
|
||||
dir: Option<String>,
|
||||
dir: Option<&str>,
|
||||
api_name: &str,
|
||||
) -> Result<(PathBuf, FileSystemRc), AnyError>
|
||||
where
|
||||
@ -1077,11 +1071,7 @@ where
|
||||
{
|
||||
let fs = state.borrow::<FileSystemRc>().clone();
|
||||
let dir = match dir {
|
||||
Some(dir) => {
|
||||
let dir = PathBuf::from(dir);
|
||||
state.borrow_mut::<P>().check_write(&dir, api_name)?;
|
||||
dir
|
||||
}
|
||||
Some(dir) => state.borrow_mut::<P>().check_write(dir, api_name)?,
|
||||
None => {
|
||||
let dir = fs.tmp_dir().context("tmpdir")?;
|
||||
state
|
||||
@ -1095,7 +1085,7 @@ where
|
||||
|
||||
fn make_temp_check_async<P>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
dir: Option<String>,
|
||||
dir: Option<&str>,
|
||||
api_name: &str,
|
||||
) -> Result<(PathBuf, FileSystemRc), AnyError>
|
||||
where
|
||||
@ -1104,11 +1094,7 @@ where
|
||||
let mut state = state.borrow_mut();
|
||||
let fs = state.borrow::<FileSystemRc>().clone();
|
||||
let dir = match dir {
|
||||
Some(dir) => {
|
||||
let dir = PathBuf::from(dir);
|
||||
state.borrow_mut::<P>().check_write(&dir, api_name)?;
|
||||
dir
|
||||
}
|
||||
Some(dir) => state.borrow_mut::<P>().check_write(dir, api_name)?,
|
||||
None => {
|
||||
let dir = fs.tmp_dir().context("tmpdir")?;
|
||||
state
|
||||
|
@ -1,5 +1,6 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::env::current_dir;
|
||||
@ -36,19 +37,37 @@ pub struct SqliteDbHandler<P: SqliteDbHandlerPermissions + 'static> {
|
||||
}
|
||||
|
||||
pub trait SqliteDbHandlerPermissions {
|
||||
fn check_read(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_read(
|
||||
&mut self,
|
||||
p: &str,
|
||||
api_name: &str,
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_write<'a>(
|
||||
&mut self,
|
||||
p: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
}
|
||||
|
||||
impl SqliteDbHandlerPermissions for deno_permissions::PermissionsContainer {
|
||||
#[inline(always)]
|
||||
fn check_read(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError> {
|
||||
fn check_read(
|
||||
&mut self,
|
||||
p: &str,
|
||||
api_name: &str,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_read(self, p, api_name)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_write(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_write(self, p, api_name)
|
||||
fn check_write<'a>(
|
||||
&mut self,
|
||||
p: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_write_path(self, p, api_name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,28 +93,35 @@ impl<P: SqliteDbHandlerPermissions> DatabaseHandler for SqliteDbHandler<P> {
|
||||
state: Rc<RefCell<OpState>>,
|
||||
path: Option<String>,
|
||||
) -> Result<Self::DB, AnyError> {
|
||||
// Validate path
|
||||
if let Some(path) = &path {
|
||||
if path != ":memory:" {
|
||||
if path.is_empty() {
|
||||
return Err(type_error("Filename cannot be empty"));
|
||||
}
|
||||
if path.starts_with(':') {
|
||||
return Err(type_error(
|
||||
"Filename cannot start with ':' unless prefixed with './'",
|
||||
));
|
||||
}
|
||||
let path = Path::new(path);
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
permissions.check_read(path, "Deno.openKv")?;
|
||||
permissions.check_write(path, "Deno.openKv")?;
|
||||
}
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn validate_path<P: SqliteDbHandlerPermissions + 'static>(
|
||||
state: &RefCell<OpState>,
|
||||
path: Option<String>,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let Some(path) = path else {
|
||||
return Ok(None);
|
||||
};
|
||||
if path == ":memory:" {
|
||||
return Ok(Some(path));
|
||||
}
|
||||
if path.is_empty() {
|
||||
return Err(type_error("Filename cannot be empty"));
|
||||
}
|
||||
if path.starts_with(':') {
|
||||
return Err(type_error(
|
||||
"Filename cannot start with ':' unless prefixed with './'",
|
||||
));
|
||||
}
|
||||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
let path = permissions.check_read(&path, "Deno.openKv")?;
|
||||
let path = permissions.check_write(&path, "Deno.openKv")?;
|
||||
Ok(Some(path.to_string_lossy().to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
let path = path.clone();
|
||||
let path = validate_path::<P>(&state, path)?;
|
||||
let default_storage_dir = self.default_storage_dir.clone();
|
||||
type ConnGen =
|
||||
Arc<dyn Fn() -> rusqlite::Result<rusqlite::Connection> + Send + Sync>;
|
||||
|
@ -16,7 +16,6 @@ use deno_core::OpState;
|
||||
use deno_core::V8CrossThreadTaskSpawner;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::thread_local;
|
||||
@ -482,15 +481,15 @@ deno_core::extension!(deno_napi,
|
||||
);
|
||||
|
||||
pub trait NapiPermissions {
|
||||
fn check(&mut self, path: Option<&Path>)
|
||||
-> std::result::Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check(&mut self, path: &str) -> std::result::Result<PathBuf, AnyError>;
|
||||
}
|
||||
|
||||
// NOTE(bartlomieju): for now, NAPI uses `--allow-ffi` flag, but that might
|
||||
// change in the future.
|
||||
impl NapiPermissions for deno_permissions::PermissionsContainer {
|
||||
#[inline(always)]
|
||||
fn check(&mut self, path: Option<&Path>) -> Result<(), AnyError> {
|
||||
fn check(&mut self, path: &str) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_ffi(self, path)
|
||||
}
|
||||
}
|
||||
@ -501,7 +500,7 @@ unsafe impl Send for NapiModuleHandle {}
|
||||
struct NapiModuleHandle(*const NapiModule);
|
||||
|
||||
static NAPI_LOADED_MODULES: std::sync::LazyLock<
|
||||
RwLock<HashMap<String, NapiModuleHandle>>,
|
||||
RwLock<HashMap<PathBuf, NapiModuleHandle>>,
|
||||
> = std::sync::LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
#[op2(reentrant)]
|
||||
@ -519,15 +518,16 @@ where
|
||||
{
|
||||
// We must limit the OpState borrow because this function can trigger a
|
||||
// re-borrow through the NAPI module.
|
||||
let (async_work_sender, cleanup_hooks, external_ops_tracker) = {
|
||||
let (async_work_sender, cleanup_hooks, external_ops_tracker, path) = {
|
||||
let mut op_state = op_state.borrow_mut();
|
||||
let permissions = op_state.borrow_mut::<NP>();
|
||||
permissions.check(Some(&PathBuf::from(&path)))?;
|
||||
let path = permissions.check(&path)?;
|
||||
let napi_state = op_state.borrow::<NapiState>();
|
||||
(
|
||||
op_state.borrow::<V8CrossThreadTaskSpawner>().clone(),
|
||||
napi_state.env_cleanup_hooks.clone(),
|
||||
op_state.external_ops_tracker.clone(),
|
||||
path,
|
||||
)
|
||||
};
|
||||
|
||||
@ -612,7 +612,7 @@ where
|
||||
} else {
|
||||
return Err(type_error(format!(
|
||||
"Unable to find register Node-API module at {}",
|
||||
path
|
||||
path.display()
|
||||
)));
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@ use deno_core::error::AnyError;
|
||||
use deno_core::OpState;
|
||||
use deno_tls::rustls::RootCertStore;
|
||||
use deno_tls::RootCertStoreProvider;
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
@ -22,12 +23,27 @@ pub const UNSTABLE_FEATURE_NAME: &str = "net";
|
||||
pub trait NetPermissions {
|
||||
fn check_net<T: AsRef<str>>(
|
||||
&mut self,
|
||||
_host: &(T, Option<u16>),
|
||||
_api_name: &str,
|
||||
host: &(T, Option<u16>),
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_read(&mut self, _p: &Path, _api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write(&mut self, _p: &Path, _api_name: &str)
|
||||
-> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_read(
|
||||
&mut self,
|
||||
p: &str,
|
||||
api_name: &str,
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_write(
|
||||
&mut self,
|
||||
p: &str,
|
||||
api_name: &str,
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_write_path<'a>(
|
||||
&mut self,
|
||||
p: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
}
|
||||
|
||||
impl NetPermissions for deno_permissions::PermissionsContainer {
|
||||
@ -43,20 +59,31 @@ impl NetPermissions for deno_permissions::PermissionsContainer {
|
||||
#[inline(always)]
|
||||
fn check_read(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_read(self, path, api_name)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_write(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_write(self, path, api_name)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_write_path<'a>(
|
||||
&mut self,
|
||||
path: &'a Path,
|
||||
api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_write_path(
|
||||
self, path, api_name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper for checking unstable features. Used for sync ops.
|
||||
|
@ -784,6 +784,7 @@ mod tests {
|
||||
use std::net::Ipv6Addr;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use trust_dns_proto::rr::rdata::a::A;
|
||||
@ -991,18 +992,26 @@ mod tests {
|
||||
|
||||
fn check_read(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
p: &str,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
Ok(())
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
Ok(PathBuf::from(p))
|
||||
}
|
||||
|
||||
fn check_write(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
p: &str,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
Ok(())
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
Ok(PathBuf::from(p))
|
||||
}
|
||||
|
||||
fn check_write_path<'a>(
|
||||
&mut self,
|
||||
p: &'a Path,
|
||||
_api_name: &str,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
Ok(Cow::Borrowed(p))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,6 @@ use std::io::ErrorKind;
|
||||
use std::io::Read;
|
||||
use std::net::SocketAddr;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use tokio::io::AsyncReadExt;
|
||||
@ -356,15 +355,17 @@ where
|
||||
.try_borrow::<UnsafelyIgnoreCertificateErrors>()
|
||||
.and_then(|it| it.0.clone());
|
||||
|
||||
{
|
||||
let cert_file = {
|
||||
let mut s = state.borrow_mut();
|
||||
let permissions = s.borrow_mut::<NP>();
|
||||
permissions
|
||||
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.connectTls()")?;
|
||||
if let Some(path) = cert_file {
|
||||
permissions.check_read(Path::new(path), "Deno.connectTls()")?;
|
||||
Some(permissions.check_read(path, "Deno.connectTls()")?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut ca_certs = args
|
||||
.ca_certs
|
||||
|
@ -94,22 +94,22 @@ pub async fn op_net_accept_unix(
|
||||
#[serde]
|
||||
pub async fn op_net_connect_unix<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[string] path: String,
|
||||
#[string] address_path: String,
|
||||
) -> Result<(ResourceId, Option<String>, Option<String>), AnyError>
|
||||
where
|
||||
NP: NetPermissions + 'static,
|
||||
{
|
||||
let address_path = Path::new(&path);
|
||||
{
|
||||
let address_path = {
|
||||
let mut state_ = state.borrow_mut();
|
||||
state_
|
||||
let address_path = state_
|
||||
.borrow_mut::<NP>()
|
||||
.check_read(address_path, "Deno.connect()")?;
|
||||
state_
|
||||
.check_read(&address_path, "Deno.connect()")?;
|
||||
_ = state_
|
||||
.borrow_mut::<NP>()
|
||||
.check_write(address_path, "Deno.connect()")?;
|
||||
}
|
||||
let unix_stream = UnixStream::connect(Path::new(&path)).await?;
|
||||
.check_write_path(&address_path, "Deno.connect()")?;
|
||||
address_path
|
||||
};
|
||||
let unix_stream = UnixStream::connect(&address_path).await?;
|
||||
let local_addr = unix_stream.local_addr()?;
|
||||
let remote_addr = unix_stream.peer_addr()?;
|
||||
let local_addr_path = local_addr.as_pathname().map(pathstring).transpose()?;
|
||||
@ -148,18 +148,17 @@ pub async fn op_net_recv_unixpacket(
|
||||
pub async fn op_net_send_unixpacket<NP>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
#[smi] rid: ResourceId,
|
||||
#[string] path: String,
|
||||
#[string] address_path: String,
|
||||
#[buffer] zero_copy: JsBuffer,
|
||||
) -> Result<usize, AnyError>
|
||||
where
|
||||
NP: NetPermissions + 'static,
|
||||
{
|
||||
let address_path = Path::new(&path);
|
||||
{
|
||||
let address_path = {
|
||||
let mut s = state.borrow_mut();
|
||||
s.borrow_mut::<NP>()
|
||||
.check_write(address_path, "Deno.DatagramConn.send()")?;
|
||||
}
|
||||
.check_write(&address_path, "Deno.DatagramConn.send()")?
|
||||
};
|
||||
|
||||
let resource = state
|
||||
.borrow()
|
||||
@ -178,17 +177,16 @@ where
|
||||
#[serde]
|
||||
pub fn op_net_listen_unix<NP>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
#[string] address_path: String,
|
||||
#[string] api_name: String,
|
||||
) -> Result<(ResourceId, Option<String>), AnyError>
|
||||
where
|
||||
NP: NetPermissions + 'static,
|
||||
{
|
||||
let address_path = Path::new(&path);
|
||||
let permissions = state.borrow_mut::<NP>();
|
||||
let api_call_expr = format!("{}()", api_name);
|
||||
permissions.check_read(address_path, &api_call_expr)?;
|
||||
permissions.check_write(address_path, &api_call_expr)?;
|
||||
let address_path = permissions.check_read(&address_path, &api_call_expr)?;
|
||||
_ = permissions.check_write_path(&address_path, &api_call_expr)?;
|
||||
let listener = UnixListener::bind(address_path)?;
|
||||
let local_addr = listener.local_addr()?;
|
||||
let pathname = local_addr.as_pathname().map(pathstring).transpose()?;
|
||||
@ -199,15 +197,15 @@ where
|
||||
|
||||
pub fn net_listen_unixpacket<NP>(
|
||||
state: &mut OpState,
|
||||
path: String,
|
||||
address_path: String,
|
||||
) -> Result<(ResourceId, Option<String>), AnyError>
|
||||
where
|
||||
NP: NetPermissions + 'static,
|
||||
{
|
||||
let address_path = Path::new(&path);
|
||||
let permissions = state.borrow_mut::<NP>();
|
||||
permissions.check_read(address_path, "Deno.listenDatagram()")?;
|
||||
permissions.check_write(address_path, "Deno.listenDatagram()")?;
|
||||
let address_path =
|
||||
permissions.check_read(&address_path, "Deno.listenDatagram()")?;
|
||||
_ = permissions.check_write_path(&address_path, "Deno.listenDatagram()")?;
|
||||
let socket = UnixDatagram::bind(address_path)?;
|
||||
let local_addr = socket.local_addr()?;
|
||||
let pathname = local_addr.as_pathname().map(pathstring).transpose()?;
|
||||
|
@ -3,8 +3,10 @@
|
||||
#![deny(clippy::print_stderr)]
|
||||
#![deny(clippy::print_stdout)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashSet;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::located_script_name;
|
||||
@ -49,21 +51,29 @@ pub trait NodePermissions {
|
||||
url: &Url,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
#[inline(always)]
|
||||
fn check_read(&mut self, path: &Path) -> Result<(), AnyError> {
|
||||
fn check_read(&mut self, path: &str) -> Result<PathBuf, AnyError> {
|
||||
self.check_read_with_api_name(path, None)
|
||||
}
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_read_with_api_name(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError>;
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_read_path<'a>(
|
||||
&mut self,
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
fn check_sys(&mut self, kind: &str, api_name: &str) -> Result<(), AnyError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
fn check_write_with_api_name(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError>;
|
||||
) -> Result<PathBuf, AnyError>;
|
||||
}
|
||||
|
||||
impl NodePermissions for deno_permissions::PermissionsContainer {
|
||||
@ -79,20 +89,27 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
|
||||
#[inline(always)]
|
||||
fn check_read_with_api_name(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_read_with_api_name(
|
||||
self, path, api_name,
|
||||
)
|
||||
}
|
||||
|
||||
fn check_read_path<'a>(
|
||||
&mut self,
|
||||
path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_read_path(self, path, None)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_write_with_api_name(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
path: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
deno_permissions::PermissionsContainer::check_write_with_api_name(
|
||||
self, path, api_name,
|
||||
)
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
@ -21,8 +19,7 @@ pub fn op_node_fs_exists_sync<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read_with_api_name(&path, Some("node:fs.existsSync()"))?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
@ -37,14 +34,12 @@ pub async fn op_node_fs_exists<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read_with_api_name(&path, Some("node:fs.exists()"))?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
Ok(fs.exists_async(path).await?)
|
||||
@ -59,18 +54,15 @@ pub fn op_node_cp_sync<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = Path::new(path);
|
||||
let new_path = Path::new(new_path);
|
||||
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read_with_api_name(path, Some("node:fs.cpSync"))?;
|
||||
state
|
||||
let new_path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write_with_api_name(new_path, Some("node:fs.cpSync"))?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.cp_sync(path, new_path)?;
|
||||
fs.cp_sync(&path, &new_path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -83,18 +75,15 @@ pub async fn op_node_cp<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
let new_path = PathBuf::from(new_path);
|
||||
|
||||
let fs = {
|
||||
let (fs, path, new_path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read_with_api_name(&path, Some("node:fs.cpSync"))?;
|
||||
state
|
||||
let new_path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write_with_api_name(&new_path, Some("node:fs.cpSync"))?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
(state.borrow::<FileSystemRc>().clone(), path, new_path)
|
||||
};
|
||||
|
||||
fs.cp_async(path, new_path).await?;
|
||||
@ -123,21 +112,21 @@ pub fn op_node_statfs<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
{
|
||||
let path = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_read_with_api_name(Path::new(&path), Some("node:fs.statfs"))?;
|
||||
.check_read_with_api_name(&path, Some("node:fs.statfs"))?;
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_sys("statfs", "node:fs.statfs")?;
|
||||
}
|
||||
path
|
||||
};
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let path = OsStr::new(&path);
|
||||
let path = path.as_os_str();
|
||||
let mut cpath = path.as_bytes().to_vec();
|
||||
cpath.push(0);
|
||||
if bigint {
|
||||
@ -196,7 +185,7 @@ where
|
||||
// Using a vfs here doesn't make sense, it won't align with the windows API
|
||||
// call below.
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let path = Path::new(&path).canonicalize()?;
|
||||
let path = path.canonicalize()?;
|
||||
let root = path
|
||||
.ancestors()
|
||||
.last()
|
||||
@ -256,14 +245,12 @@ pub fn op_node_lutimes_sync<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = Path::new(path);
|
||||
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write_with_api_name(path, Some("node:fs.lutimes"))?;
|
||||
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
fs.lutime_sync(path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)?;
|
||||
fs.lutime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -279,14 +266,12 @@ pub async fn op_node_lutimes<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write_with_api_name(&path, Some("node:fs.lutimesSync"))?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
|
||||
fs.lutime_async(path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
|
||||
@ -305,8 +290,7 @@ pub fn op_node_lchown_sync<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write_with_api_name(&path, Some("node:fs.lchownSync"))?;
|
||||
let fs = state.borrow::<FileSystemRc>();
|
||||
@ -324,13 +308,12 @@ pub async fn op_node_lchown<P>(
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
let fs = {
|
||||
let (fs, path) = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<P>()
|
||||
.check_write_with_api_name(&path, Some("node:fs.lchown"))?;
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
(state.borrow::<FileSystemRc>().clone(), path)
|
||||
};
|
||||
fs.lchown_async(path, uid, gid).await?;
|
||||
Ok(())
|
||||
|
@ -5,12 +5,15 @@
|
||||
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::op2;
|
||||
use deno_core::FsModuleLoader;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_fs::RealFs;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
|
||||
use deno_runtime::worker::MainWorker;
|
||||
use deno_runtime::worker::WorkerOptions;
|
||||
|
||||
@ -34,7 +37,9 @@ async fn main() -> Result<(), AnyError> {
|
||||
eprintln!("Running {main_module}...");
|
||||
let mut worker = MainWorker::bootstrap_from_options(
|
||||
main_module.clone(),
|
||||
PermissionsContainer::allow_all(),
|
||||
PermissionsContainer::allow_all(Arc::new(
|
||||
RuntimePermissionDescriptorParser::new(Arc::new(RealFs)),
|
||||
)),
|
||||
WorkerOptions {
|
||||
module_loader: Rc::new(FsModuleLoader),
|
||||
extensions: vec![hello_runtime::init_ops_and_esm()],
|
||||
|
@ -33,6 +33,7 @@ pub mod fs_util;
|
||||
pub mod inspector_server;
|
||||
pub mod js;
|
||||
pub mod ops;
|
||||
pub mod permissions;
|
||||
pub mod snapshot;
|
||||
pub mod tokio_util;
|
||||
pub mod web_worker;
|
||||
|
@ -123,10 +123,9 @@ fn op_fs_events_open(
|
||||
RecursiveMode::NonRecursive
|
||||
};
|
||||
for path in &args.paths {
|
||||
let path = PathBuf::from(path);
|
||||
state
|
||||
let path = state
|
||||
.borrow_mut::<PermissionsContainer>()
|
||||
.check_read(&path, "Deno.watchFs()")?;
|
||||
.check_read(path, "Deno.watchFs()")?;
|
||||
watcher.watch(&path, recursive_mode)?;
|
||||
}
|
||||
let resource = FsEventsResource {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use ::deno_permissions::parse_sys_kind;
|
||||
use ::deno_permissions::NetDescriptor;
|
||||
use ::deno_permissions::PermissionDescriptorParser;
|
||||
use ::deno_permissions::PermissionState;
|
||||
use ::deno_permissions::PermissionsContainer;
|
||||
use deno_core::error::custom_error;
|
||||
@ -10,7 +10,7 @@ use deno_core::op2;
|
||||
use deno_core::OpState;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
deno_core::extension!(
|
||||
deno_permissions,
|
||||
@ -19,6 +19,12 @@ deno_core::extension!(
|
||||
op_revoke_permission,
|
||||
op_request_permission,
|
||||
],
|
||||
options = {
|
||||
permission_desc_parser: Arc<dyn PermissionDescriptorParser>,
|
||||
},
|
||||
state = |state, options| {
|
||||
state.put(options.permission_desc_parser);
|
||||
},
|
||||
);
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -56,15 +62,37 @@ pub fn op_query_permission(
|
||||
state: &mut OpState,
|
||||
#[serde] args: PermissionArgs,
|
||||
) -> Result<PermissionStatus, AnyError> {
|
||||
let permissions = state.borrow::<PermissionsContainer>().0.lock();
|
||||
let permissions_container = state.borrow::<PermissionsContainer>();
|
||||
// todo(dsherret): don't have this function use the properties of
|
||||
// permission container
|
||||
let desc_parser = &permissions_container.descriptor_parser;
|
||||
let permissions = permissions_container.inner.lock();
|
||||
let path = args.path.as_deref();
|
||||
let perm = match args.name.as_ref() {
|
||||
"read" => permissions.read.query(path.map(Path::new)),
|
||||
"write" => permissions.write.query(path.map(Path::new)),
|
||||
"read" => permissions.read.query(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_read(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"write" => permissions.write.query(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_write(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"net" => permissions.net.query(
|
||||
match args.host.as_deref() {
|
||||
None => None,
|
||||
Some(h) => Some(NetDescriptor::parse(h)?),
|
||||
Some(h) => Some(desc_parser.parse_net_descriptor(h)?),
|
||||
}
|
||||
.as_ref(),
|
||||
),
|
||||
@ -72,8 +100,24 @@ pub fn op_query_permission(
|
||||
"sys" => permissions
|
||||
.sys
|
||||
.query(args.kind.as_deref().map(parse_sys_kind).transpose()?),
|
||||
"run" => permissions.run.query(args.command.as_deref()),
|
||||
"ffi" => permissions.ffi.query(args.path.as_deref().map(Path::new)),
|
||||
"run" => permissions.run.query(
|
||||
args
|
||||
.command
|
||||
.as_deref()
|
||||
.map(|request| desc_parser.parse_run_query(request))
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"ffi" => permissions.ffi.query(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_ffi(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
n => {
|
||||
return Err(custom_error(
|
||||
"ReferenceError",
|
||||
@ -90,15 +134,37 @@ pub fn op_revoke_permission(
|
||||
state: &mut OpState,
|
||||
#[serde] args: PermissionArgs,
|
||||
) -> Result<PermissionStatus, AnyError> {
|
||||
let mut permissions = state.borrow_mut::<PermissionsContainer>().0.lock();
|
||||
// todo(dsherret): don't have this function use the properties of
|
||||
// permission container
|
||||
let permissions_container = state.borrow_mut::<PermissionsContainer>();
|
||||
let desc_parser = &permissions_container.descriptor_parser;
|
||||
let mut permissions = permissions_container.inner.lock();
|
||||
let path = args.path.as_deref();
|
||||
let perm = match args.name.as_ref() {
|
||||
"read" => permissions.read.revoke(path.map(Path::new)),
|
||||
"write" => permissions.write.revoke(path.map(Path::new)),
|
||||
"read" => permissions.read.revoke(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_read(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"write" => permissions.write.revoke(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_write(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"net" => permissions.net.revoke(
|
||||
match args.host.as_deref() {
|
||||
None => None,
|
||||
Some(h) => Some(NetDescriptor::parse(h)?),
|
||||
Some(h) => Some(desc_parser.parse_net_descriptor(h)?),
|
||||
}
|
||||
.as_ref(),
|
||||
),
|
||||
@ -106,8 +172,24 @@ pub fn op_revoke_permission(
|
||||
"sys" => permissions
|
||||
.sys
|
||||
.revoke(args.kind.as_deref().map(parse_sys_kind).transpose()?),
|
||||
"run" => permissions.run.revoke(args.command.as_deref()),
|
||||
"ffi" => permissions.ffi.revoke(args.path.as_deref().map(Path::new)),
|
||||
"run" => permissions.run.revoke(
|
||||
args
|
||||
.command
|
||||
.as_deref()
|
||||
.map(|request| desc_parser.parse_run_query(request))
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"ffi" => permissions.ffi.revoke(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_ffi(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
n => {
|
||||
return Err(custom_error(
|
||||
"ReferenceError",
|
||||
@ -124,15 +206,37 @@ pub fn op_request_permission(
|
||||
state: &mut OpState,
|
||||
#[serde] args: PermissionArgs,
|
||||
) -> Result<PermissionStatus, AnyError> {
|
||||
let mut permissions = state.borrow_mut::<PermissionsContainer>().0.lock();
|
||||
// todo(dsherret): don't have this function use the properties of
|
||||
// permission container
|
||||
let permissions_container = state.borrow_mut::<PermissionsContainer>();
|
||||
let desc_parser = &permissions_container.descriptor_parser;
|
||||
let mut permissions = permissions_container.inner.lock();
|
||||
let path = args.path.as_deref();
|
||||
let perm = match args.name.as_ref() {
|
||||
"read" => permissions.read.request(path.map(Path::new)),
|
||||
"write" => permissions.write.request(path.map(Path::new)),
|
||||
"read" => permissions.read.request(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_read(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"write" => permissions.write.request(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_write(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"net" => permissions.net.request(
|
||||
match args.host.as_deref() {
|
||||
None => None,
|
||||
Some(h) => Some(NetDescriptor::parse(h)?),
|
||||
Some(h) => Some(desc_parser.parse_net_descriptor(h)?),
|
||||
}
|
||||
.as_ref(),
|
||||
),
|
||||
@ -140,8 +244,24 @@ pub fn op_request_permission(
|
||||
"sys" => permissions
|
||||
.sys
|
||||
.request(args.kind.as_deref().map(parse_sys_kind).transpose()?),
|
||||
"run" => permissions.run.request(args.command.as_deref()),
|
||||
"ffi" => permissions.ffi.request(args.path.as_deref().map(Path::new)),
|
||||
"run" => permissions.run.request(
|
||||
args
|
||||
.command
|
||||
.as_deref()
|
||||
.map(|request| desc_parser.parse_run_query(request))
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
"ffi" => permissions.ffi.request(
|
||||
path
|
||||
.map(|path| {
|
||||
Result::<_, AnyError>::Ok(
|
||||
desc_parser.parse_path_query(path)?.into_ffi(),
|
||||
)
|
||||
})
|
||||
.transpose()?
|
||||
.as_ref(),
|
||||
),
|
||||
n => {
|
||||
return Err(custom_error(
|
||||
"ReferenceError",
|
||||
|
@ -17,12 +17,13 @@ use deno_io::ChildStderrResource;
|
||||
use deno_io::ChildStdinResource;
|
||||
use deno_io::ChildStdoutResource;
|
||||
use deno_permissions::PermissionsContainer;
|
||||
use deno_permissions::RunPathQuery;
|
||||
use deno_permissions::RunQueryDescriptor;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitStatus;
|
||||
@ -536,9 +537,9 @@ fn compute_run_cmd_and_check_permissions(
|
||||
.with_context(|| format!("Failed to spawn '{}'", arg_cmd))?;
|
||||
check_run_permission(
|
||||
state,
|
||||
RunPathQuery {
|
||||
requested: arg_cmd,
|
||||
resolved: &cmd,
|
||||
&RunQueryDescriptor::Path {
|
||||
requested: arg_cmd.to_string(),
|
||||
resolved: cmd.clone(),
|
||||
},
|
||||
&run_env,
|
||||
api_name,
|
||||
@ -547,7 +548,7 @@ fn compute_run_cmd_and_check_permissions(
|
||||
}
|
||||
|
||||
struct RunEnv {
|
||||
envs: HashMap<String, String>,
|
||||
envs: HashMap<OsString, OsString>,
|
||||
cwd: PathBuf,
|
||||
}
|
||||
|
||||
@ -567,11 +568,32 @@ fn compute_run_env(
|
||||
.map(|cwd_arg| resolve_path(cwd_arg, &cwd))
|
||||
.unwrap_or(cwd);
|
||||
let envs = if arg_clear_env {
|
||||
arg_envs.iter().cloned().collect()
|
||||
arg_envs
|
||||
.iter()
|
||||
.map(|(k, v)| (OsString::from(k), OsString::from(v)))
|
||||
.collect()
|
||||
} else {
|
||||
let mut envs = std::env::vars().collect::<HashMap<_, _>>();
|
||||
let mut envs = std::env::vars_os()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
if cfg!(windows) {
|
||||
k.to_ascii_uppercase()
|
||||
} else {
|
||||
k
|
||||
},
|
||||
v,
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
for (key, value) in arg_envs {
|
||||
envs.insert(key.clone(), value.clone());
|
||||
envs.insert(
|
||||
OsString::from(if cfg!(windows) {
|
||||
key.to_ascii_uppercase()
|
||||
} else {
|
||||
key.clone()
|
||||
}),
|
||||
OsString::from(value.clone()),
|
||||
);
|
||||
}
|
||||
envs
|
||||
};
|
||||
@ -585,19 +607,7 @@ fn resolve_cmd(cmd: &str, env: &RunEnv) -> Result<PathBuf, AnyError> {
|
||||
if is_path {
|
||||
Ok(resolve_path(cmd, &env.cwd))
|
||||
} else {
|
||||
let path = env.envs.get("PATH").or_else(|| {
|
||||
if cfg!(windows) {
|
||||
env.envs.iter().find_map(|(k, v)| {
|
||||
if k.to_uppercase() == "PATH" {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let path = env.envs.get(&OsString::from("PATH"));
|
||||
match which::which_in(cmd, path, &env.cwd) {
|
||||
Ok(cmd) => Ok(cmd),
|
||||
Err(which::Error::CannotFindBinaryPath) => {
|
||||
@ -614,7 +624,7 @@ fn resolve_path(path: &str, cwd: &Path) -> PathBuf {
|
||||
|
||||
fn check_run_permission(
|
||||
state: &mut OpState,
|
||||
cmd: RunPathQuery,
|
||||
cmd: &RunQueryDescriptor,
|
||||
run_env: &RunEnv,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
@ -647,11 +657,22 @@ fn get_requires_allow_all_env_vars(env: &RunEnv) -> Vec<&str> {
|
||||
key.starts_with("LD_") || key.starts_with("DYLD_")
|
||||
}
|
||||
|
||||
fn is_empty(value: &OsString) -> bool {
|
||||
value.is_empty()
|
||||
|| value.to_str().map(|v| v.trim().is_empty()).unwrap_or(false)
|
||||
}
|
||||
|
||||
let mut found_envs = env
|
||||
.envs
|
||||
.iter()
|
||||
.filter(|(k, v)| requires_allow_all(k) && !v.trim().is_empty())
|
||||
.map(|(k, _)| k.as_str())
|
||||
.filter_map(|(k, v)| {
|
||||
let key = k.to_str()?;
|
||||
if requires_allow_all(key) && !is_empty(v) {
|
||||
Some(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
found_envs.sort();
|
||||
found_envs
|
||||
|
@ -19,6 +19,7 @@ use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_permissions::create_child_permissions;
|
||||
use deno_permissions::ChildPermissionsArg;
|
||||
use deno_permissions::PermissionDescriptorParser;
|
||||
use deno_permissions::PermissionsContainer;
|
||||
use deno_web::deserialize_js_transferables;
|
||||
use deno_web::JsMessageData;
|
||||
@ -153,13 +154,19 @@ fn op_create_worker(
|
||||
"Worker.deno.permissions",
|
||||
);
|
||||
}
|
||||
let permission_desc_parser = state
|
||||
.borrow::<Arc<dyn PermissionDescriptorParser>>()
|
||||
.clone();
|
||||
let parent_permissions = state.borrow_mut::<PermissionsContainer>();
|
||||
let worker_permissions = if let Some(child_permissions_arg) = args.permissions
|
||||
{
|
||||
let mut parent_permissions = parent_permissions.0.lock();
|
||||
let perms =
|
||||
create_child_permissions(&mut parent_permissions, child_permissions_arg)?;
|
||||
PermissionsContainer::new(perms)
|
||||
let mut parent_permissions = parent_permissions.inner.lock();
|
||||
let perms = create_child_permissions(
|
||||
permission_desc_parser.as_ref(),
|
||||
&mut parent_permissions,
|
||||
child_permissions_arg,
|
||||
)?;
|
||||
PermissionsContainer::new(permission_desc_parser, perms)
|
||||
} else {
|
||||
parent_permissions.clone()
|
||||
};
|
||||
|
164
runtime/permissions.rs
Normal file
164
runtime/permissions.rs
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::normalize_path;
|
||||
use deno_permissions::AllowRunDescriptor;
|
||||
use deno_permissions::AllowRunDescriptorParseResult;
|
||||
use deno_permissions::DenyRunDescriptor;
|
||||
use deno_permissions::EnvDescriptor;
|
||||
use deno_permissions::FfiDescriptor;
|
||||
use deno_permissions::NetDescriptor;
|
||||
use deno_permissions::PathQueryDescriptor;
|
||||
use deno_permissions::ReadDescriptor;
|
||||
use deno_permissions::RunQueryDescriptor;
|
||||
use deno_permissions::SysDescriptor;
|
||||
use deno_permissions::WriteDescriptor;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RuntimePermissionDescriptorParser {
|
||||
fs: deno_fs::FileSystemRc,
|
||||
}
|
||||
|
||||
impl RuntimePermissionDescriptorParser {
|
||||
pub fn new(fs: deno_fs::FileSystemRc) -> Self {
|
||||
Self { fs }
|
||||
}
|
||||
|
||||
fn resolve_from_cwd(&self, path: &str) -> Result<PathBuf, AnyError> {
|
||||
if path.is_empty() {
|
||||
bail!("Empty path is not allowed");
|
||||
}
|
||||
let path = Path::new(path);
|
||||
if path.is_absolute() {
|
||||
Ok(normalize_path(path))
|
||||
} else {
|
||||
let cwd = self.resolve_cwd()?;
|
||||
Ok(normalize_path(cwd.join(path)))
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_cwd(&self) -> Result<PathBuf, AnyError> {
|
||||
self
|
||||
.fs
|
||||
.cwd()
|
||||
.map_err(|e| e.into_io_error())
|
||||
.context("failed resolving cwd")
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_permissions::PermissionDescriptorParser
|
||||
for RuntimePermissionDescriptorParser
|
||||
{
|
||||
fn parse_read_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<ReadDescriptor, AnyError> {
|
||||
Ok(ReadDescriptor(self.resolve_from_cwd(text)?))
|
||||
}
|
||||
|
||||
fn parse_write_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<WriteDescriptor, AnyError> {
|
||||
Ok(WriteDescriptor(self.resolve_from_cwd(text)?))
|
||||
}
|
||||
|
||||
fn parse_net_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<NetDescriptor, AnyError> {
|
||||
NetDescriptor::parse(text)
|
||||
}
|
||||
|
||||
fn parse_env_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<EnvDescriptor, AnyError> {
|
||||
if text.is_empty() {
|
||||
Err(AnyError::msg("Empty env not allowed"))
|
||||
} else {
|
||||
Ok(EnvDescriptor::new(text))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_sys_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<deno_permissions::SysDescriptor, AnyError> {
|
||||
if text.is_empty() {
|
||||
Err(AnyError::msg("Empty sys not allowed"))
|
||||
} else {
|
||||
Ok(SysDescriptor(text.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_allow_run_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<AllowRunDescriptorParseResult, AnyError> {
|
||||
Ok(AllowRunDescriptor::parse(text, &self.resolve_cwd()?)?)
|
||||
}
|
||||
|
||||
fn parse_deny_run_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<DenyRunDescriptor, AnyError> {
|
||||
Ok(DenyRunDescriptor::parse(text, &self.resolve_cwd()?))
|
||||
}
|
||||
|
||||
fn parse_ffi_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<deno_permissions::FfiDescriptor, AnyError> {
|
||||
Ok(FfiDescriptor(self.resolve_from_cwd(text)?))
|
||||
}
|
||||
|
||||
// queries
|
||||
|
||||
fn parse_path_query(
|
||||
&self,
|
||||
path: &str,
|
||||
) -> Result<PathQueryDescriptor, AnyError> {
|
||||
Ok(PathQueryDescriptor {
|
||||
resolved: self.resolve_from_cwd(path)?,
|
||||
requested: path.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_run_query(
|
||||
&self,
|
||||
requested: &str,
|
||||
) -> Result<RunQueryDescriptor, AnyError> {
|
||||
if requested.is_empty() {
|
||||
bail!("Empty run query is not allowed");
|
||||
}
|
||||
RunQueryDescriptor::parse(requested)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_fs::RealFs;
|
||||
use deno_permissions::PermissionDescriptorParser;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_handle_empty_value() {
|
||||
let parser = RuntimePermissionDescriptorParser::new(Arc::new(RealFs));
|
||||
assert!(parser.parse_read_descriptor("").is_err());
|
||||
assert!(parser.parse_write_descriptor("").is_err());
|
||||
assert!(parser.parse_env_descriptor("").is_err());
|
||||
assert!(parser.parse_net_descriptor("").is_err());
|
||||
assert!(parser.parse_ffi_descriptor("").is_err());
|
||||
assert!(parser.parse_path_query("").is_err());
|
||||
assert!(parser.parse_run_query("").is_err());
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
||||
|
||||
use crate::ops;
|
||||
use crate::ops::bootstrap::SnapshotOptions;
|
||||
use crate::permissions::RuntimePermissionDescriptorParser;
|
||||
use crate::shared::maybe_transpile_source;
|
||||
use crate::shared::runtime;
|
||||
use deno_cache::SqliteBackedCache;
|
||||
@ -11,6 +12,7 @@ use deno_core::v8;
|
||||
use deno_core::Extension;
|
||||
use deno_http::DefaultHttpPropertyExtractor;
|
||||
use deno_io::fs::FsError;
|
||||
use std::borrow::Cow;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
@ -45,29 +47,32 @@ impl deno_fetch::FetchPermissions for Permissions {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_read(
|
||||
fn check_read<'a>(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_p: &'a Path,
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_ffi::FfiPermissions for Permissions {
|
||||
fn check_partial(
|
||||
fn check_partial_no_path(
|
||||
&mut self,
|
||||
_path: Option<&Path>,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_partial_with_path(
|
||||
&mut self,
|
||||
_path: &str,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_napi::NapiPermissions for Permissions {
|
||||
fn check(
|
||||
&mut self,
|
||||
_path: Option<&Path>,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
fn check(&mut self, _path: &str) -> std::result::Result<PathBuf, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
}
|
||||
@ -80,18 +85,24 @@ impl deno_node::NodePermissions for Permissions {
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
fn check_read_path<'a>(
|
||||
&mut self,
|
||||
_path: &'a Path,
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
fn check_read_with_api_name(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_p: &str,
|
||||
_api_name: Option<&str>,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
) -> Result<PathBuf, deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
fn check_write_with_api_name(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_p: &str,
|
||||
_api_name: Option<&str>,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
) -> Result<PathBuf, deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
fn check_sys(
|
||||
@ -114,17 +125,25 @@ impl deno_net::NetPermissions for Permissions {
|
||||
|
||||
fn check_read(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_p: &str,
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
) -> Result<PathBuf, deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_write(
|
||||
&mut self,
|
||||
_p: &Path,
|
||||
_p: &str,
|
||||
_api_name: &str,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
) -> Result<PathBuf, deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_write_path<'a>(
|
||||
&mut self,
|
||||
_p: &'a Path,
|
||||
_api_name: &str,
|
||||
) -> Result<std::borrow::Cow<'a, Path>, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
}
|
||||
@ -143,9 +162,9 @@ impl deno_fs::FsPermissions for Permissions {
|
||||
|
||||
fn check_read(
|
||||
&mut self,
|
||||
_path: &Path,
|
||||
_path: &str,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
@ -164,17 +183,17 @@ impl deno_fs::FsPermissions for Permissions {
|
||||
|
||||
fn check_write(
|
||||
&mut self,
|
||||
_path: &Path,
|
||||
_path: &str,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_write_partial(
|
||||
&mut self,
|
||||
_path: &Path,
|
||||
_path: &str,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
@ -190,22 +209,38 @@ impl deno_fs::FsPermissions for Permissions {
|
||||
) -> Result<(), AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_read_path<'a>(
|
||||
&mut self,
|
||||
_path: &'a Path,
|
||||
_api_name: &str,
|
||||
) -> Result<std::borrow::Cow<'a, Path>, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_write_path<'a>(
|
||||
&mut self,
|
||||
_path: &'a Path,
|
||||
_api_name: &str,
|
||||
) -> Result<std::borrow::Cow<'a, Path>, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_kv::sqlite::SqliteDbHandlerPermissions for Permissions {
|
||||
fn check_read(
|
||||
&mut self,
|
||||
_path: &Path,
|
||||
_path: &str,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_write(
|
||||
fn check_write<'a>(
|
||||
&mut self,
|
||||
_path: &Path,
|
||||
_path: &'a Path,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<Cow<'a, Path>, AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
}
|
||||
@ -255,7 +290,7 @@ pub fn create_runtime_snapshot(
|
||||
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(),
|
||||
deno_io::deno_io::init_ops_and_esm(Default::default()),
|
||||
deno_fs::deno_fs::init_ops_and_esm::<Permissions>(fs.clone()),
|
||||
deno_node::deno_node::init_ops_and_esm::<Permissions>(None, fs),
|
||||
deno_node::deno_node::init_ops_and_esm::<Permissions>(None, fs.clone()),
|
||||
runtime::init_ops_and_esm(),
|
||||
ops::runtime::deno_runtime::init_ops("deno:runtime".parse().unwrap()),
|
||||
ops::worker_host::deno_worker_host::init_ops(
|
||||
@ -264,7 +299,9 @@ pub fn create_runtime_snapshot(
|
||||
),
|
||||
ops::fs_events::deno_fs_events::init_ops(),
|
||||
ops::os::deno_os::init_ops(Default::default()),
|
||||
ops::permissions::deno_permissions::init_ops(),
|
||||
ops::permissions::deno_permissions::init_ops(Arc::new(
|
||||
RuntimePermissionDescriptorParser::new(fs),
|
||||
)),
|
||||
ops::process::deno_process::init_ops(),
|
||||
ops::signal::deno_signal::init_ops(),
|
||||
ops::tty::deno_tty::init_ops(),
|
||||
|
@ -44,6 +44,7 @@ use deno_http::DefaultHttpPropertyExtractor;
|
||||
use deno_io::Stdio;
|
||||
use deno_kv::dynamic::MultiBackendDbHandler;
|
||||
use deno_node::NodeExtInitServices;
|
||||
use deno_permissions::PermissionDescriptorParser;
|
||||
use deno_permissions::PermissionsContainer;
|
||||
use deno_terminal::colors;
|
||||
use deno_tls::RootCertStoreProvider;
|
||||
@ -356,6 +357,7 @@ pub struct WebWorker {
|
||||
}
|
||||
|
||||
pub struct WebWorkerOptions {
|
||||
// todo(dsherret): extract out the service structs from this options bag
|
||||
pub bootstrap: BootstrapOptions,
|
||||
pub extensions: Vec<Extension>,
|
||||
pub startup_snapshot: Option<&'static [u8]>,
|
||||
@ -377,6 +379,7 @@ pub struct WebWorkerOptions {
|
||||
pub cache_storage_dir: Option<std::path::PathBuf>,
|
||||
pub stdio: Stdio,
|
||||
pub feature_checker: Arc<FeatureChecker>,
|
||||
pub permission_desc_parser: Arc<dyn PermissionDescriptorParser>,
|
||||
pub strace_ops: Option<Vec<String>>,
|
||||
pub close_on_idle: bool,
|
||||
pub maybe_worker_metadata: Option<WorkerMetadata>,
|
||||
@ -501,7 +504,9 @@ impl WebWorker {
|
||||
),
|
||||
ops::fs_events::deno_fs_events::init_ops_and_esm(),
|
||||
ops::os::deno_os_worker::init_ops_and_esm(),
|
||||
ops::permissions::deno_permissions::init_ops_and_esm(),
|
||||
ops::permissions::deno_permissions::init_ops_and_esm(
|
||||
options.permission_desc_parser.clone(),
|
||||
),
|
||||
ops::process::deno_process::init_ops_and_esm(),
|
||||
ops::signal::deno_signal::init_ops_and_esm(),
|
||||
ops::tty::deno_tty::init_ops_and_esm(),
|
||||
|
@ -49,6 +49,7 @@ use crate::code_cache::CodeCache;
|
||||
use crate::code_cache::CodeCacheType;
|
||||
use crate::inspector_server::InspectorServer;
|
||||
use crate::ops;
|
||||
use crate::permissions::RuntimePermissionDescriptorParser;
|
||||
use crate::shared::maybe_transpile_source;
|
||||
use crate::shared::runtime;
|
||||
use crate::BootstrapOptions;
|
||||
@ -157,6 +158,8 @@ pub struct WorkerOptions {
|
||||
/// executed tries to load modules.
|
||||
pub module_loader: Rc<dyn ModuleLoader>,
|
||||
pub node_services: Option<NodeExtInitServices>,
|
||||
pub permission_desc_parser:
|
||||
Arc<dyn deno_permissions::PermissionDescriptorParser>,
|
||||
// Callbacks invoked when creating new instance of WebWorker
|
||||
pub create_web_worker_cb: Arc<ops::worker_host::CreateWebWorkerCb>,
|
||||
pub format_js_error_fn: Option<Arc<FormatJsErrorFn>>,
|
||||
@ -201,13 +204,16 @@ pub struct WorkerOptions {
|
||||
pub v8_code_cache: Option<Arc<dyn CodeCache>>,
|
||||
}
|
||||
|
||||
// todo(dsherret): this is error prone to use. We should separate
|
||||
// out the WorkerOptions from the services.
|
||||
impl Default for WorkerOptions {
|
||||
fn default() -> Self {
|
||||
let real_fs = Arc::new(deno_fs::RealFs);
|
||||
Self {
|
||||
create_web_worker_cb: Arc::new(|_| {
|
||||
unimplemented!("web workers are not supported")
|
||||
}),
|
||||
fs: Arc::new(deno_fs::RealFs),
|
||||
fs: real_fs.clone(),
|
||||
module_loader: Rc::new(FsModuleLoader),
|
||||
skip_op_registration: false,
|
||||
seed: None,
|
||||
@ -232,6 +238,9 @@ impl Default for WorkerOptions {
|
||||
bootstrap: Default::default(),
|
||||
stdio: Default::default(),
|
||||
feature_checker: Default::default(),
|
||||
permission_desc_parser: Arc::new(RuntimePermissionDescriptorParser::new(
|
||||
real_fs,
|
||||
)),
|
||||
v8_code_cache: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -425,7 +434,9 @@ impl MainWorker {
|
||||
),
|
||||
ops::fs_events::deno_fs_events::init_ops_and_esm(),
|
||||
ops::os::deno_os::init_ops_and_esm(exit_code.clone()),
|
||||
ops::permissions::deno_permissions::init_ops_and_esm(),
|
||||
ops::permissions::deno_permissions::init_ops_and_esm(
|
||||
options.permission_desc_parser,
|
||||
),
|
||||
ops::process::deno_process::init_ops_and_esm(),
|
||||
ops::signal::deno_signal::init_ops_and_esm(),
|
||||
ops::tty::deno_tty::init_ops_and_esm(),
|
||||
|
@ -255,12 +255,6 @@ itest!(_052_no_remote_flag {
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(_056_make_temp_file_write_perm {
|
||||
args:
|
||||
"run --quiet --allow-read --allow-write=./subdir/ run/056_make_temp_file_write_perm.ts",
|
||||
output: "run/056_make_temp_file_write_perm.out",
|
||||
});
|
||||
|
||||
itest!(_058_tasks_microtasks_close {
|
||||
args: "run --quiet run/058_tasks_microtasks_close.ts",
|
||||
output: "run/058_tasks_microtasks_close.ts.out",
|
||||
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"envs": {
|
||||
"DYLD_FALLBACK_LIBRARY_PATH": "",
|
||||
"LD_LIBRARY_PATH": ""
|
||||
},
|
||||
"args": "run --allow-run --deny-run=deno --allow-read main.ts",
|
||||
"output": "main.out"
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
NotCapable: Requires run access to "deno", run again with the --allow-run flag
|
||||
at [WILDCARD] {
|
||||
name: "NotCapable"
|
||||
}
|
||||
NotCapable: Requires run access to "[WILDLINE]", run again with the --allow-run flag
|
||||
at [WILDCARD] {
|
||||
name: "NotCapable"
|
||||
}
|
15
tests/specs/permission/deny_run_binary_absolute_path/main.ts
Normal file
15
tests/specs/permission/deny_run_binary_absolute_path/main.ts
Normal file
@ -0,0 +1,15 @@
|
||||
try {
|
||||
new Deno.Command("deno", {
|
||||
args: ["--version"],
|
||||
}).outputSync();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
new Deno.Command(Deno.execPath(), {
|
||||
args: ["--version"],
|
||||
}).outputSync();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
good [WILDCARD]subdir[WILDCARD]
|
||||
good [WILDCARD]subdir[WILDCARD]
|
||||
good [WILDCARD]subdir[WILDCARD]
|
||||
good [WILDCARD]subdir[WILDCARD]
|
@ -0,0 +1,52 @@
|
||||
Deno.mkdirSync("subdir");
|
||||
|
||||
// async file
|
||||
{
|
||||
const path = await Deno.makeTempFile({ dir: `subdir` });
|
||||
try {
|
||||
if (!path.match(/^subdir[/\\][^/\\]+/)) {
|
||||
throw Error("bad " + path);
|
||||
}
|
||||
console.log("good", path);
|
||||
} finally {
|
||||
await Deno.remove(path);
|
||||
}
|
||||
}
|
||||
// sync file
|
||||
{
|
||||
const path = Deno.makeTempFileSync({ dir: `subdir` });
|
||||
try {
|
||||
if (!path.match(/^subdir[/\\][^/\\]+/)) {
|
||||
throw Error("bad " + path);
|
||||
}
|
||||
console.log("good", path);
|
||||
} finally {
|
||||
await Deno.remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
// async dir
|
||||
{
|
||||
const path = await Deno.makeTempDir({ dir: `subdir` });
|
||||
try {
|
||||
if (!path.match(/^subdir[/\\][^/\\]+/)) {
|
||||
throw Error("bad " + path);
|
||||
}
|
||||
console.log("good", path);
|
||||
} finally {
|
||||
await Deno.remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
// sync dir
|
||||
{
|
||||
const path = Deno.makeTempDirSync({ dir: `subdir` });
|
||||
try {
|
||||
if (!path.match(/^subdir[/\\][^/\\]+/)) {
|
||||
throw Error("bad " + path);
|
||||
}
|
||||
console.log("good", path);
|
||||
} finally {
|
||||
await Deno.remove(path);
|
||||
}
|
||||
}
|
15
tests/specs/permission/make_temp_write_perm/__test__.jsonc
Normal file
15
tests/specs/permission/make_temp_write_perm/__test__.jsonc
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"tempDir": true,
|
||||
"tests": {
|
||||
"reduced_perms": {
|
||||
// this should not expose the full directory
|
||||
"args": "run --quiet --allow-read --allow-write=./subdir/ 056_make_temp_file_write_perm.ts",
|
||||
"output": "056_make_temp_file_write_perm.out"
|
||||
},
|
||||
"all_perms": {
|
||||
// this will work the same as above
|
||||
"args": "run --quiet -A 056_make_temp_file_write_perm.ts",
|
||||
"output": "056_make_temp_file_write_perm.out"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
{
|
||||
"args": "run --quiet -A main.ts",
|
||||
"output": "main.out",
|
||||
"tempDir": true,
|
||||
"envs": {
|
||||
"DYLD_FALLBACK_LIBRARY_PATH": "",
|
||||
"LD_LIBRARY_PATH": ""
|
||||
}
|
||||
},
|
||||
"args": "run --quiet -A main.ts",
|
||||
"output": "main.out"
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ PermissionStatus { state: "granted", onchange: null }
|
||||
PermissionStatus { state: "prompt", onchange: null }
|
||||
PermissionStatus { state: "granted", onchange: null }
|
||||
---
|
||||
Info Failed to resolve 'deno' for allow-run: cannot find binary path
|
||||
Info Failed to resolve 'binary' for allow-run: cannot find binary path
|
||||
PermissionStatus { state: "prompt", onchange: null }
|
||||
PermissionStatus { state: "prompt", onchange: null }
|
||||
PermissionStatus { state: "prompt", onchange: null }
|
||||
|
@ -1,36 +1,41 @@
|
||||
// Testing the following (but with `deno` instead of `echo`):
|
||||
// | `deno run --allow-run=echo` | `which path == "/usr/bin/echo"` at startup | `which path != "/usr/bin/echo"` at startup |
|
||||
// |-------------------------------------|--------------------------------------------|--------------------------------------------|
|
||||
// | **`Deno.Command("echo")`** | ✅ | ✅ |
|
||||
// | **`Deno.Command("/usr/bin/echo")`** | ✅ | ❌ |
|
||||
// Testing the following:
|
||||
// | `deno run --allow-run=binary` | `which path == "/usr/bin/binary"` at startup | `which path != "/usr/bin/binary"` at startup |
|
||||
// |---------------------------------------|----------------------------------------------|--------------------------------------------|
|
||||
// | **`Deno.Command("binary")`** | :white_check_mark: | :white_check_mark: |
|
||||
// | **`Deno.Command("/usr/bin/binary")`** | :white_check_mark: | :x: |
|
||||
// | `deno run --allow-run=/usr/bin/binary | `which path == "/usr/bin/binary"` at runtime | `which path != "/usr/bin/binary"` at runtime |
|
||||
// |---------------------------------------|----------------------------------------------|--------------------------------------------|
|
||||
// | **`Deno.Command("binary")`** | :white_check_mark: | :x: |
|
||||
// | **`Deno.Command("/usr/bin/binary")`** | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
// | `deno run --allow-run=/usr/bin/echo | `which path == "/usr/bin/echo"` at runtime | `which path != "/usr/bin/echo"` at runtime |
|
||||
// |-------------------------------------|--------------------------------------------|--------------------------------------------|
|
||||
// | **`Deno.Command("echo")`** | ✅ | ❌ |
|
||||
// | **`Deno.Command("/usr/bin/echo")`** | ✅ | ✅ |
|
||||
const binaryName = Deno.build.os === "windows" ? "binary.exe" : "binary";
|
||||
const pathSep = Deno.build.os === "windows" ? "\\" : "/";
|
||||
const cwd = Deno.cwd();
|
||||
const execPathParent = `${Deno.cwd()}${pathSep}sub`;
|
||||
const execPath = `${execPathParent}${pathSep}${binaryName}`;
|
||||
|
||||
const execPath = Deno.execPath();
|
||||
const execPathParent = execPath.replace(/[/\\][^/\\]+$/, "");
|
||||
Deno.mkdirSync(execPathParent);
|
||||
Deno.copyFileSync(Deno.execPath(), execPath);
|
||||
|
||||
const testUrl = `data:application/typescript;base64,${
|
||||
btoa(`
|
||||
console.error(await Deno.permissions.query({ name: "run", command: "deno" }));
|
||||
console.error(await Deno.permissions.query({ name: "run", command: "binary" }));
|
||||
console.error(await Deno.permissions.query({ name: "run", command: "${
|
||||
execPath.replaceAll("\\", "\\\\")
|
||||
}" }));
|
||||
Deno.env.set("PATH", "");
|
||||
console.error(await Deno.permissions.query({ name: "run", command: "deno" }));
|
||||
console.error(await Deno.permissions.query({ name: "run", command: "binary" }));
|
||||
console.error(await Deno.permissions.query({ name: "run", command: "${
|
||||
execPath.replaceAll("\\", "\\\\")
|
||||
}" }));
|
||||
`)
|
||||
}`;
|
||||
|
||||
const process1 = await new Deno.Command(Deno.execPath(), {
|
||||
await new Deno.Command(Deno.execPath(), {
|
||||
args: [
|
||||
"run",
|
||||
"--allow-env",
|
||||
"--allow-run=deno",
|
||||
"--allow-run=binary",
|
||||
testUrl,
|
||||
],
|
||||
stdout: "inherit",
|
||||
@ -44,7 +49,7 @@ await new Deno.Command(Deno.execPath(), {
|
||||
args: [
|
||||
"run",
|
||||
"--allow-env",
|
||||
"--allow-run=deno",
|
||||
"--allow-run=binary",
|
||||
testUrl,
|
||||
],
|
||||
stderr: "inherit",
|
||||
|
@ -6,11 +6,11 @@
|
||||
},
|
||||
"tests": {
|
||||
"env_arg": {
|
||||
"args": "run --allow-run=echo env_arg.ts",
|
||||
"args": "run --allow-run=curl env_arg.ts",
|
||||
"output": "env_arg.out"
|
||||
},
|
||||
"set_with_allow_env": {
|
||||
"args": "run --allow-run=echo --allow-env set_with_allow_env.ts",
|
||||
"args": "run --allow-run=curl --allow-env set_with_allow_env.ts",
|
||||
"output": "set_with_allow_env.out"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
Deno.env.set("LD_PRELOAD", "./libpreload.so");
|
||||
|
||||
try {
|
||||
new Deno.Command("echo").spawn();
|
||||
new Deno.Command("curl").spawn();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
@ -9,7 +9,7 @@ try {
|
||||
Deno.env.set("DYLD_FALLBACK_LIBRARY_PATH", "./libpreload.so");
|
||||
|
||||
try {
|
||||
Deno.run({ cmd: ["echo"] }).spawnSync();
|
||||
Deno.run({ cmd: ["curl"] }).spawnSync();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
good [WILDCARD]subdir[WILDCARD]
|
@ -1,9 +0,0 @@
|
||||
const path = await Deno.makeTempFile({ dir: `subdir` });
|
||||
try {
|
||||
if (!path.match(/^subdir[/\\][^/\\]+/)) {
|
||||
throw Error("bad " + path);
|
||||
}
|
||||
console.log("good", path);
|
||||
} finally {
|
||||
await Deno.remove(path);
|
||||
}
|
@ -1,4 +1,16 @@
|
||||
// deno-fmt-ignore-file
|
||||
import { toFileUrl } from "@std/path/to-file-url";
|
||||
|
||||
function tryGetCwd() {
|
||||
// will throw in one test but not the other
|
||||
try {
|
||||
return Deno.cwd()
|
||||
} catch {
|
||||
return import.meta.dirname;
|
||||
}
|
||||
}
|
||||
|
||||
const fooExePath = tryGetCwd() + "/foo" + (Deno.build.os === "windows" ? ".exe" : "");
|
||||
postMessage({
|
||||
envGlobal: (await Deno.permissions.query({ name: "env" })).state,
|
||||
envFoo: (await Deno.permissions.query({ name: "env", variable: "foo" })).state,
|
||||
@ -15,11 +27,13 @@ postMessage({
|
||||
readGlobal: (await Deno.permissions.query({ name: "read" })).state,
|
||||
readFoo: (await Deno.permissions.query({ name: "read", path: new URL("foo", import.meta.url) })).state,
|
||||
readBar: (await Deno.permissions.query({ name: "read", path: "bar" })).state,
|
||||
readAbsent: (await Deno.permissions.query({ name: "read", path: "absent" })).state,
|
||||
readAbsent: (await Deno.permissions.query({ name: "read", path: "../absent" })).state,
|
||||
runGlobal: (await Deno.permissions.query({ name: "run" })).state,
|
||||
runFoo: (await Deno.permissions.query({ name: "run", command: new URL("foo", import.meta.url) })).state,
|
||||
runFoo: (await Deno.permissions.query({ name: "run", command: toFileUrl(fooExePath) })).state,
|
||||
runFooPath: (await Deno.permissions.query({ name: "run", command: fooExePath })).state,
|
||||
runBar: (await Deno.permissions.query({ name: "run", command: "bar" })).state,
|
||||
runBaz: (await Deno.permissions.query({ name: "run", command: "./baz" })).state,
|
||||
runUnresolved: (await Deno.permissions.query({ name: "run", command: "unresolved-exec" })).state,
|
||||
runAbsent: (await Deno.permissions.query({ name: "run", command: "absent" })).state,
|
||||
writeGlobal: (await Deno.permissions.query({ name: "write" })).state,
|
||||
writeFoo: (await Deno.permissions.query({ name: "write", path: new URL("foo", import.meta.url) })).state,
|
||||
|
@ -79,7 +79,9 @@ Deno.test(
|
||||
) => {
|
||||
const src = `
|
||||
console.log(
|
||||
${JSON.stringify(Object.keys(expectedEnv))}.map(k => Deno.env.get(k))
|
||||
${
|
||||
JSON.stringify(Object.keys(expectedEnv))
|
||||
}.map(k => Deno.env.get(k) ?? null)
|
||||
)`;
|
||||
const { success, stdout } = await new Deno.Command(Deno.execPath(), {
|
||||
args: ["eval", src],
|
||||
|
@ -5,6 +5,7 @@
|
||||
// Requires to be run with `--allow-net` flag
|
||||
|
||||
import { assert, assertEquals, assertMatch, assertThrows } from "@std/assert";
|
||||
import { toFileUrl } from "@std/path/to-file-url";
|
||||
|
||||
function resolveWorker(worker: string): string {
|
||||
return import.meta.resolve(`../testdata/workers/${worker}`);
|
||||
@ -442,7 +443,31 @@ Deno.test("Worker limit children permissions", async function () {
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
function setupReadCheckGranularWorkerTest() {
|
||||
const tempDir = Deno.realPathSync(Deno.makeTempDirSync());
|
||||
const initialPath = Deno.env.get("PATH")!;
|
||||
const initialCwd = Deno.cwd();
|
||||
Deno.chdir(tempDir);
|
||||
const envSep = Deno.build.os === "windows" ? ";" : ":";
|
||||
Deno.env.set("PATH", initialPath + envSep + tempDir);
|
||||
|
||||
// create executables that will be resolved when doing `which`
|
||||
const ext = Deno.build.os === "windows" ? ".exe" : "";
|
||||
Deno.copyFileSync(Deno.execPath(), tempDir + "/bar" + ext);
|
||||
|
||||
return {
|
||||
tempDir,
|
||||
runFooFilePath: tempDir + "/foo" + ext,
|
||||
[Symbol.dispose]() {
|
||||
Deno.removeSync(tempDir, { recursive: true });
|
||||
Deno.env.set("PATH", initialPath);
|
||||
Deno.chdir(initialCwd);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Deno.test("Worker limit children permissions granularly", async function () {
|
||||
const ctx = setupReadCheckGranularWorkerTest();
|
||||
const workerUrl = resolveWorker("read_check_granular_worker.js");
|
||||
const worker = new Worker(
|
||||
workerUrl,
|
||||
@ -453,8 +478,13 @@ Deno.test("Worker limit children permissions granularly", async function () {
|
||||
env: ["foo"],
|
||||
net: ["foo", "bar:8000"],
|
||||
ffi: [new URL("foo", workerUrl), "bar"],
|
||||
read: [new URL("foo", workerUrl), "bar"],
|
||||
run: [new URL("foo", workerUrl), "bar", "./baz"],
|
||||
read: [new URL("foo", workerUrl), "bar", ctx.tempDir],
|
||||
run: [
|
||||
toFileUrl(ctx.runFooFilePath),
|
||||
"bar",
|
||||
"./baz",
|
||||
"unresolved-exec",
|
||||
],
|
||||
write: [new URL("foo", workerUrl), "bar"],
|
||||
},
|
||||
},
|
||||
@ -482,8 +512,10 @@ Deno.test("Worker limit children permissions granularly", async function () {
|
||||
readAbsent: "prompt",
|
||||
runGlobal: "prompt",
|
||||
runFoo: "granted",
|
||||
runFooPath: "granted",
|
||||
runBar: "granted",
|
||||
runBaz: "granted",
|
||||
runUnresolved: "prompt", // unresolved binaries remain as "prompt"
|
||||
runAbsent: "prompt",
|
||||
writeGlobal: "prompt",
|
||||
writeFoo: "granted",
|
||||
@ -494,6 +526,7 @@ Deno.test("Worker limit children permissions granularly", async function () {
|
||||
});
|
||||
|
||||
Deno.test("Nested worker limit children permissions", async function () {
|
||||
const _cleanup = setupReadCheckGranularWorkerTest();
|
||||
/** This worker has permissions but doesn't grant them to its children */
|
||||
const worker = new Worker(
|
||||
resolveWorker("parent_read_check_worker.js"),
|
||||
@ -521,8 +554,10 @@ Deno.test("Nested worker limit children permissions", async function () {
|
||||
readAbsent: "prompt",
|
||||
runGlobal: "prompt",
|
||||
runFoo: "prompt",
|
||||
runFooPath: "prompt",
|
||||
runBar: "prompt",
|
||||
runBaz: "prompt",
|
||||
runUnresolved: "prompt",
|
||||
runAbsent: "prompt",
|
||||
writeGlobal: "prompt",
|
||||
writeFoo: "prompt",
|
||||
|
@ -218,7 +218,7 @@ async function ensureNoNewITests() {
|
||||
"pm_tests.rs": 0,
|
||||
"publish_tests.rs": 0,
|
||||
"repl_tests.rs": 0,
|
||||
"run_tests.rs": 334,
|
||||
"run_tests.rs": 333,
|
||||
"shared_library_tests.rs": 0,
|
||||
"task_tests.rs": 4,
|
||||
"test_tests.rs": 0,
|
||||
|
Loading…
Reference in New Issue
Block a user