From fac64478157ee563b185edb5734688e4523df3a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Sat, 7 Jan 2023 17:25:34 +0100 Subject: [PATCH] refactor(permissions): add PermissionsContainer struct for internal mutability (#17134) Turns out we were cloning permissions which after prompting were discarded, so the state of permissions was never preserved. To handle that we need to store all permissions behind "Arc>" (because there are situations where we need to send them to other thread). Testing and benching code still uses "Permissions" in most places - it's undesirable to share the same permission set between various test/bench files - otherwise granting or revoking permissions in one file would influence behavior of other test files. --- cli/build.rs | 18 +-- cli/cache/mod.rs | 14 +- cli/file_fetcher.rs | 69 +++++---- cli/graph_util.rs | 6 +- cli/lsp/registries.rs | 12 +- cli/lsp/testing/execution.rs | 6 +- cli/module_loader.rs | 13 +- cli/ops/bench.rs | 16 +- cli/ops/testing.rs | 16 +- cli/proc_state.rs | 16 +- cli/standalone.rs | 5 +- cli/tests/run_tests.rs | 17 +++ cli/tools/bench.rs | 13 +- cli/tools/repl/mod.rs | 7 +- cli/tools/run.rs | 20 ++- cli/tools/standalone.rs | 4 +- cli/tools/test.rs | 26 ++-- cli/worker.rs | 11 +- runtime/examples/hello_runtime.rs | 4 +- runtime/ops/fs.rs | 244 +++++++++++++----------------- runtime/ops/fs_events.rs | 7 +- runtime/ops/os/mod.rs | 68 ++++----- runtime/ops/permissions.rs | 8 +- runtime/ops/process.rs | 12 +- runtime/ops/runtime.rs | 10 +- runtime/ops/spawn.rs | 12 +- runtime/ops/worker_host.rs | 14 +- runtime/permissions/mod.rs | 150 +++++++++++++++--- runtime/web_worker.rs | 24 +-- runtime/worker.rs | 24 +-- 30 files changed, 489 insertions(+), 377 deletions(-) diff --git a/cli/build.rs b/cli/build.rs index faeaed0732..b4acc0d1d5 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use deno_core::snapshot_util::*; use deno_core::Extension; use deno_runtime::deno_cache::SqliteBackedCache; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use deno_runtime::*; mod ts { @@ -294,13 +294,13 @@ fn create_cli_snapshot(snapshot_path: PathBuf, files: Vec) { deno_console::init(), deno_url::init(), deno_tls::init(), - deno_web::init::( + deno_web::init::( deno_web::BlobStore::default(), Default::default(), ), - deno_fetch::init::(Default::default()), + deno_fetch::init::(Default::default()), deno_cache::init::(None), - deno_websocket::init::("".to_owned(), None, None), + deno_websocket::init::("".to_owned(), None, None), deno_webstorage::init(None), deno_crypto::init(None), deno_webgpu::init(false), @@ -308,15 +308,15 @@ fn create_cli_snapshot(snapshot_path: PathBuf, files: Vec) { deno_broadcast_channel::InMemoryBroadcastChannel::default(), false, // No --unstable. ), - deno_node::init::(None), // No --unstable. - deno_ffi::init::(false), - deno_net::init::( + deno_node::init::(None), // No --unstable. + deno_ffi::init::(false), + deno_net::init::( None, false, // No --unstable. None, ), - deno_napi::init::(false), + deno_napi::init::(false), deno_http::init(), - deno_flash::init::(false), // No --unstable + deno_flash::init::(false), // No --unstable ]; create_snapshot(CreateSnapshotOptions { diff --git a/cli/cache/mod.rs b/cli/cache/mod.rs index 68bf1e4c62..d2ad1b20ab 100644 --- a/cli/cache/mod.rs +++ b/cli/cache/mod.rs @@ -11,7 +11,7 @@ use deno_graph::source::CacheInfo; use deno_graph::source::LoadFuture; use deno_graph::source::LoadResponse; use deno_graph::source::Loader; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use std::sync::Arc; mod check; @@ -42,17 +42,17 @@ pub const CACHE_PERM: u32 = 0o644; /// a concise interface to the DENO_DIR when building module graphs. pub struct FetchCacher { emit_cache: EmitCache, - dynamic_permissions: Permissions, + dynamic_permissions: PermissionsContainer, file_fetcher: Arc, - root_permissions: Permissions, + root_permissions: PermissionsContainer, } impl FetchCacher { pub fn new( emit_cache: EmitCache, file_fetcher: FileFetcher, - root_permissions: Permissions, - dynamic_permissions: Permissions, + root_permissions: PermissionsContainer, + dynamic_permissions: PermissionsContainer, ) -> Self { let file_fetcher = Arc::new(file_fetcher); @@ -104,7 +104,7 @@ impl Loader for FetchCacher { } let specifier = specifier.clone(); - let mut permissions = if is_dynamic { + let permissions = if is_dynamic { self.dynamic_permissions.clone() } else { self.root_permissions.clone() @@ -113,7 +113,7 @@ impl Loader for FetchCacher { async move { file_fetcher - .fetch(&specifier, &mut permissions) + .fetch(&specifier, permissions) .await .map_or_else( |err| { diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index cc83e6f5f9..2376133f56 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -31,7 +31,7 @@ use deno_runtime::deno_fetch::reqwest::header::AUTHORIZATION; use deno_runtime::deno_fetch::reqwest::header::IF_NONE_MATCH; use deno_runtime::deno_fetch::reqwest::StatusCode; use deno_runtime::deno_web::BlobStore; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use log::debug; use std::borrow::Borrow; use std::collections::HashMap; @@ -406,7 +406,7 @@ impl FileFetcher { fn fetch_remote( &self, specifier: &ModuleSpecifier, - permissions: &mut Permissions, + permissions: PermissionsContainer, redirect_limit: i64, maybe_accept: Option, ) -> Pin> + Send>> { @@ -461,7 +461,6 @@ impl FileFetcher { }; let maybe_auth_token = self.auth_tokens.get(specifier); let specifier = specifier.clone(); - let mut permissions = permissions.clone(); let client = self.http_client.clone(); let file_fetcher = self.clone(); // A single pass of fetch either yields code or yields a redirect. @@ -487,7 +486,7 @@ impl FileFetcher { file_fetcher .fetch_remote( &redirect_url, - &mut permissions, + permissions, redirect_limit - 1, maybe_accept, ) @@ -547,7 +546,7 @@ impl FileFetcher { pub async fn fetch( &self, specifier: &ModuleSpecifier, - permissions: &mut Permissions, + permissions: PermissionsContainer, ) -> Result { debug!("FileFetcher::fetch() - specifier: {}", specifier); self.fetch_with_accept(specifier, permissions, None).await @@ -556,7 +555,7 @@ impl FileFetcher { pub async fn fetch_with_accept( &self, specifier: &ModuleSpecifier, - permissions: &mut Permissions, + permissions: PermissionsContainer, maybe_accept: Option<&str>, ) -> Result { let scheme = get_validated_scheme(specifier)?; @@ -797,7 +796,7 @@ mod tests { async fn test_fetch(specifier: &ModuleSpecifier) -> (File, FileFetcher) { let (file_fetcher, _) = setup(CacheSetting::ReloadAll, None); let result = file_fetcher - .fetch(specifier, &mut Permissions::allow_all()) + .fetch(specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); (result.unwrap(), file_fetcher) @@ -809,7 +808,7 @@ mod tests { let _http_server_guard = test_util::http_server(); let (file_fetcher, _) = setup(CacheSetting::ReloadAll, None); let result: Result = file_fetcher - .fetch_remote(specifier, &mut Permissions::allow_all(), 1, None) + .fetch_remote(specifier, PermissionsContainer::allow_all(), 1, None) .await; assert!(result.is_ok()); let (_, headers, _) = file_fetcher.http_cache.get(specifier).unwrap(); @@ -1053,7 +1052,7 @@ mod tests { file_fetcher.insert_cached(file.clone()); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let result_file = result.unwrap(); @@ -1069,7 +1068,7 @@ mod tests { .unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); @@ -1098,7 +1097,7 @@ mod tests { let specifier = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1130,7 +1129,7 @@ mod tests { ); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1153,7 +1152,7 @@ mod tests { resolve_url_or_path("http://localhost:4545/subdir/mod2.ts").unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1175,7 +1174,7 @@ mod tests { metadata.write(&cache_filename).unwrap(); let result = file_fetcher_01 - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1196,7 +1195,7 @@ mod tests { metadata.write(&cache_filename).unwrap(); let result = file_fetcher_02 - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1219,7 +1218,7 @@ mod tests { ) .unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1252,7 +1251,7 @@ mod tests { .unwrap(); let result = file_fetcher_01 - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); @@ -1271,7 +1270,7 @@ mod tests { ) .unwrap(); let result = file_fetcher_02 - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); @@ -1303,7 +1302,7 @@ mod tests { .unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1356,7 +1355,7 @@ mod tests { .unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1422,7 +1421,7 @@ mod tests { .unwrap(); let result = file_fetcher_01 - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); @@ -1442,7 +1441,7 @@ mod tests { ) .unwrap(); let result = file_fetcher_02 - .fetch(&redirected_specifier, &mut Permissions::allow_all()) + .fetch(&redirected_specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); @@ -1464,12 +1463,12 @@ mod tests { .unwrap(); let result = file_fetcher - .fetch_remote(&specifier, &mut Permissions::allow_all(), 2, None) + .fetch_remote(&specifier, PermissionsContainer::allow_all(), 2, None) .await; assert!(result.is_ok()); let result = file_fetcher - .fetch_remote(&specifier, &mut Permissions::allow_all(), 1, None) + .fetch_remote(&specifier, PermissionsContainer::allow_all(), 1, None) .await; assert!(result.is_err()); @@ -1501,7 +1500,7 @@ mod tests { .unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1545,7 +1544,7 @@ mod tests { resolve_url("http://localhost:4545/run/002_hello.ts").unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_err()); let err = result.unwrap_err(); @@ -1580,7 +1579,7 @@ mod tests { resolve_url("http://localhost:4545/run/002_hello.ts").unwrap(); let result = file_fetcher_01 - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_err()); let err = result.unwrap_err(); @@ -1588,12 +1587,12 @@ mod tests { assert_eq!(err.to_string(), "Specifier not found in cache: \"http://localhost:4545/run/002_hello.ts\", --cached-only is specified."); let result = file_fetcher_02 - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let result = file_fetcher_01 - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); } @@ -1606,7 +1605,7 @@ mod tests { resolve_url_or_path(&fixture_path.to_string_lossy()).unwrap(); fs::write(fixture_path.clone(), r#"console.log("hello deno");"#).unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1614,7 +1613,7 @@ mod tests { fs::write(fixture_path, r#"console.log("goodbye deno");"#).unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1630,7 +1629,7 @@ mod tests { let specifier = ModuleSpecifier::parse("http://localhost:4545/dynamic").unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1639,7 +1638,7 @@ mod tests { let (file_fetcher, _) = setup(CacheSetting::RespectHeaders, Some(temp_dir.clone())); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1657,7 +1656,7 @@ mod tests { let specifier = ModuleSpecifier::parse("http://localhost:4545/dynamic_cache").unwrap(); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); @@ -1666,7 +1665,7 @@ mod tests { let (file_fetcher, _) = setup(CacheSetting::RespectHeaders, Some(temp_dir.clone())); let result = file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await; assert!(result.is_ok()); let file = result.unwrap(); diff --git a/cli/graph_util.rs b/cli/graph_util.rs index d815e33119..8127018922 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -28,7 +28,7 @@ use deno_graph::ModuleGraphError; use deno_graph::ModuleKind; use deno_graph::Range; use deno_graph::Resolved; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::HashSet; @@ -514,8 +514,8 @@ pub async fn create_graph_and_maybe_check( let mut cache = cache::FetchCacher::new( ps.emit_cache.clone(), ps.file_fetcher.clone(), - Permissions::allow_all(), - Permissions::allow_all(), + PermissionsContainer::allow_all(), + PermissionsContainer::allow_all(), ); let maybe_imports = ps.options.to_maybe_imports()?; let maybe_cli_resolver = CliResolver::maybe_new( diff --git a/cli/lsp/registries.rs b/cli/lsp/registries.rs index 81e2552c03..c8e5dad60f 100644 --- a/cli/lsp/registries.rs +++ b/cli/lsp/registries.rs @@ -30,7 +30,7 @@ use deno_core::url::Url; use deno_core::ModuleSpecifier; use deno_graph::Dependency; use deno_runtime::deno_web::BlobStore; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use log::error; use once_cell::sync::Lazy; use regex::Regex; @@ -519,7 +519,7 @@ impl ModuleRegistry { .file_fetcher .fetch_with_accept( specifier, - &mut Permissions::allow_all(), + PermissionsContainer::allow_all(), Some("application/vnd.deno.reg.v2+json, application/vnd.deno.reg.v1+json;q=0.9, application/json;q=0.8"), ) .await; @@ -617,7 +617,7 @@ impl ModuleRegistry { .ok()?; let file = self .file_fetcher - .fetch(&endpoint, &mut Permissions::allow_all()) + .fetch(&endpoint, PermissionsContainer::allow_all()) .await .ok()?; let documentation: lsp::Documentation = @@ -973,7 +973,7 @@ impl ModuleRegistry { let specifier = Url::parse(url).ok()?; let file = self .file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await .ok()?; serde_json::from_str(&file.source).ok() @@ -1030,7 +1030,7 @@ impl ModuleRegistry { let specifier = ModuleSpecifier::parse(url).ok()?; let file = self .file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await .map_err(|err| { error!( @@ -1066,7 +1066,7 @@ impl ModuleRegistry { .ok()?; let file = self .file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await .map_err(|err| { error!( diff --git a/cli/lsp/testing/execution.rs b/cli/lsp/testing/execution.rs index 722f06e2c0..a498df8576 100644 --- a/cli/lsp/testing/execution.rs +++ b/cli/lsp/testing/execution.rs @@ -30,6 +30,7 @@ use deno_core::ModuleSpecifier; use deno_runtime::ops::io::Stdio; use deno_runtime::ops::io::StdioPipe; use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use deno_runtime::tokio_util::run_local; use indexmap::IndexMap; use std::collections::HashMap; @@ -162,7 +163,7 @@ async fn test_specifier( let mut worker = create_main_worker_for_test_or_bench( &ps, specifier.clone(), - permissions, + PermissionsContainer::new(permissions), vec![ops::testing::init(sender, fail_fast_tracker, filter)], Stdio { stdin: StdioPipe::Inherit, @@ -254,6 +255,9 @@ impl TestRun { lsp_log!("Executing test run with arguments: {}", args.join(" ")); let flags = flags_from_vec(args.into_iter().map(String::from).collect())?; let ps = proc_state::ProcState::build(flags).await?; + // 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(&ps.options.permissions_options())?; test::check_specifiers( diff --git a/cli/module_loader.rs b/cli/module_loader.rs index edc89be774..d452c30cf9 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -21,7 +21,7 @@ use deno_core::ModuleSpecifier; use deno_core::ModuleType; use deno_core::OpState; use deno_core::SourceMapGetter; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use std::cell::RefCell; use std::pin::Pin; use std::rc::Rc; @@ -38,7 +38,7 @@ pub struct CliModuleLoader { /// The initial set of permissions used to resolve the static imports in the /// worker. They are decoupled from the worker (dynamic) permissions since /// read access errors must be raised based on the parent thread permissions. - pub root_permissions: Permissions, + pub root_permissions: PermissionsContainer, pub ps: ProcState, } @@ -46,12 +46,15 @@ impl CliModuleLoader { pub fn new(ps: ProcState) -> Rc { Rc::new(CliModuleLoader { lib: ps.options.ts_type_lib_window(), - root_permissions: Permissions::allow_all(), + root_permissions: PermissionsContainer::allow_all(), ps, }) } - pub fn new_for_worker(ps: ProcState, permissions: Permissions) -> Rc { + pub fn new_for_worker( + ps: ProcState, + permissions: PermissionsContainer, + ) -> Rc { Rc::new(CliModuleLoader { lib: ps.options.ts_type_lib_worker(), root_permissions: permissions, @@ -235,7 +238,7 @@ impl ModuleLoader for CliModuleLoader { let ps = self.ps.clone(); let state = op_state.borrow(); - let dynamic_permissions = state.borrow::().clone(); + let dynamic_permissions = state.borrow::().clone(); let root_permissions = if is_dynamic { dynamic_permissions.clone() } else { diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index 6fc881f614..3b27ffa7ec 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -9,7 +9,7 @@ use deno_core::ModuleSpecifier; use deno_core::OpState; use deno_runtime::permissions::create_child_permissions; use deno_runtime::permissions::ChildPermissionsArg; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use serde::Deserialize; use serde::Serialize; use std::sync::atomic::AtomicUsize; @@ -40,7 +40,7 @@ pub fn init( } #[derive(Clone)] -struct PermissionsHolder(Uuid, Permissions); +struct PermissionsHolder(Uuid, PermissionsContainer); #[op] pub fn op_pledge_test_permissions( @@ -48,8 +48,12 @@ pub fn op_pledge_test_permissions( args: ChildPermissionsArg, ) -> Result { let token = Uuid::new_v4(); - let parent_permissions = state.borrow_mut::(); - let worker_permissions = create_child_permissions(parent_permissions, args)?; + let parent_permissions = state.borrow_mut::(); + let worker_permissions = { + let mut parent_permissions = parent_permissions.0.lock(); + let perms = create_child_permissions(&mut parent_permissions, args)?; + PermissionsContainer::new(perms) + }; let parent_permissions = parent_permissions.clone(); if state.try_take::().is_some() { @@ -59,7 +63,7 @@ pub fn op_pledge_test_permissions( state.put::(PermissionsHolder(token, parent_permissions)); // NOTE: This call overrides current permission set for the worker - state.put::(worker_permissions); + state.put::(worker_permissions); Ok(token) } @@ -75,7 +79,7 @@ pub fn op_restore_test_permissions( } let permissions = permissions_holder.1; - state.put::(permissions); + state.put::(permissions); Ok(()) } else { Err(generic_error("no permissions to restore")) diff --git a/cli/ops/testing.rs b/cli/ops/testing.rs index b6fd29fc75..e5c0a2b99c 100644 --- a/cli/ops/testing.rs +++ b/cli/ops/testing.rs @@ -17,7 +17,7 @@ use deno_core::ModuleSpecifier; use deno_core::OpState; use deno_runtime::permissions::create_child_permissions; use deno_runtime::permissions::ChildPermissionsArg; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use serde::Deserialize; use serde::Deserializer; use serde::Serialize; @@ -50,7 +50,7 @@ pub fn init( } #[derive(Clone)] -struct PermissionsHolder(Uuid, Permissions); +struct PermissionsHolder(Uuid, PermissionsContainer); #[op] pub fn op_pledge_test_permissions( @@ -58,8 +58,12 @@ pub fn op_pledge_test_permissions( args: ChildPermissionsArg, ) -> Result { let token = Uuid::new_v4(); - let parent_permissions = state.borrow_mut::(); - let worker_permissions = create_child_permissions(parent_permissions, args)?; + let parent_permissions = state.borrow_mut::(); + let worker_permissions = { + let mut parent_permissions = parent_permissions.0.lock(); + let perms = create_child_permissions(&mut parent_permissions, args)?; + PermissionsContainer::new(perms) + }; let parent_permissions = parent_permissions.clone(); if state.try_take::().is_some() { @@ -68,7 +72,7 @@ pub fn op_pledge_test_permissions( state.put::(PermissionsHolder(token, parent_permissions)); // NOTE: This call overrides current permission set for the worker - state.put::(worker_permissions); + state.put::(worker_permissions); Ok(token) } @@ -84,7 +88,7 @@ pub fn op_restore_test_permissions( } let permissions = permissions_holder.1; - state.put::(permissions); + state.put::(permissions); Ok(()) } else { Err(generic_error("no permissions to restore")) diff --git a/cli/proc_state.rs b/cli/proc_state.rs index eb672d8d04..0dd97b5e3a 100644 --- a/cli/proc_state.rs +++ b/cli/proc_state.rs @@ -59,7 +59,7 @@ use deno_runtime::deno_node::NodeResolutionMode; use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_web::BlobStore; use deno_runtime::inspector_server::InspectorServer; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use import_map::ImportMap; use log::warn; use std::collections::HashSet; @@ -181,7 +181,7 @@ impl ProcState { let maybe_import_map = if let Some(import_map_specifier) = maybe_import_map_specifier { let file = file_fetcher - .fetch(&import_map_specifier, &mut Permissions::allow_all()) + .fetch(&import_map_specifier, PermissionsContainer::allow_all()) .await .context(format!( "Unable to load '{}' import map", @@ -289,8 +289,8 @@ impl ProcState { roots: Vec, is_dynamic: bool, lib: TsTypeLib, - root_permissions: Permissions, - dynamic_permissions: Permissions, + root_permissions: PermissionsContainer, + dynamic_permissions: PermissionsContainer, reload_on_watch: bool, ) -> Result<(), AnyError> { log::debug!("Preparing module load."); @@ -490,8 +490,8 @@ impl ProcState { specifiers, false, lib, - Permissions::allow_all(), - Permissions::allow_all(), + PermissionsContainer::allow_all(), + PermissionsContainer::allow_all(), false, ) .await @@ -668,8 +668,8 @@ impl ProcState { cache::FetchCacher::new( self.emit_cache.clone(), self.file_fetcher.clone(), - Permissions::allow_all(), - Permissions::allow_all(), + PermissionsContainer::allow_all(), + PermissionsContainer::allow_all(), ) } diff --git a/cli/standalone.rs b/cli/standalone.rs index c93631327a..2b0a77e18c 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -29,6 +29,7 @@ use deno_runtime::deno_tls::rustls_pemfile; use deno_runtime::deno_web::BlobStore; use deno_runtime::fmt_errors::format_js_error; use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use deno_runtime::permissions::PermissionsOptions; use deno_runtime::worker::MainWorker; use deno_runtime::worker::WorkerOptions; @@ -226,7 +227,9 @@ pub async fn run( let flags = metadata_to_flags(&metadata); let main_module = &metadata.entrypoint; let ps = ProcState::build(flags).await?; - let permissions = Permissions::from_options(&metadata.permissions)?; + let permissions = PermissionsContainer::new(Permissions::from_options( + &metadata.permissions, + )?); let blob_store = BlobStore::default(); let broadcast_channel = InMemoryBroadcastChannel::default(); let module_loader = Rc::new(EmbeddedModuleLoader { diff --git a/cli/tests/run_tests.rs b/cli/tests/run_tests.rs index dfe95d9a84..8460d3f8f4 100644 --- a/cli/tests/run_tests.rs +++ b/cli/tests/run_tests.rs @@ -3725,4 +3725,21 @@ console.log("finish"); args: "run --quiet run/001_hello.js --allow-net", output: "run/001_hello.js.out", }); + + // Regression test for https://github.com/denoland/deno/issues/16772 + #[test] + fn file_fetcher_preserves_permissions() { + let _guard = util::http_server(); + util::with_pty(&["repl"], |mut console| { + console.write_text( + "const a = import('http://127.0.0.1:4545/run/019_media_types.ts');", + ); + console.write_text("y"); + console.write_line(""); + console.write_line("close();"); + let output = console.read_all_output(); + assert_contains!(output, "success"); + assert_contains!(output, "true"); + }); + } } diff --git a/cli/tools/bench.rs b/cli/tools/bench.rs index 24fb079193..2d54b260d0 100644 --- a/cli/tools/bench.rs +++ b/cli/tools/bench.rs @@ -28,6 +28,7 @@ use deno_core::futures::StreamExt; use deno_core::ModuleSpecifier; use deno_graph::ModuleKind; use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use deno_runtime::tokio_util::run_local; use indexmap::IndexMap; use log::Level; @@ -337,8 +338,8 @@ async fn check_specifiers( specifiers, false, lib, - Permissions::allow_all(), - permissions, + PermissionsContainer::allow_all(), + PermissionsContainer::new(permissions), true, ) .await?; @@ -358,7 +359,7 @@ async fn bench_specifier( let mut worker = create_main_worker_for_test_or_bench( &ps, specifier.clone(), - permissions, + PermissionsContainer::new(permissions), vec![ops::bench::init(channel.clone(), filter)], Default::default(), ) @@ -490,6 +491,9 @@ pub async fn run_benchmarks( bench_flags: BenchFlags, ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; + // 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(&ps.options.permissions_options())?; @@ -527,6 +531,9 @@ pub async fn run_benchmarks_with_watch( bench_flags: BenchFlags, ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; + // 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(&ps.options.permissions_options())?; diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs index fc03dee2f5..00f10b7d66 100644 --- a/cli/tools/repl/mod.rs +++ b/cli/tools/repl/mod.rs @@ -8,6 +8,7 @@ use crate::worker::create_main_worker; use deno_core::error::AnyError; use deno_core::resolve_url_or_path; use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use rustyline::error::ReadlineError; mod cdp; @@ -72,7 +73,7 @@ async fn read_eval_file( let file = ps .file_fetcher - .fetch(&specifier, &mut Permissions::allow_all()) + .fetch(&specifier, PermissionsContainer::allow_all()) .await?; Ok((*file.source).to_string()) @@ -84,7 +85,9 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result { let mut worker = create_main_worker( &ps, main_module.clone(), - Permissions::from_options(&ps.options.permissions_options())?, + PermissionsContainer::new(Permissions::from_options( + &ps.options.permissions_options(), + )?), ) .await?; worker.setup_repl().await?; diff --git a/cli/tools/run.rs b/cli/tools/run.rs index af982e483f..3830affedd 100644 --- a/cli/tools/run.rs +++ b/cli/tools/run.rs @@ -9,6 +9,7 @@ use deno_ast::ModuleSpecifier; use deno_core::error::AnyError; use deno_core::resolve_url_or_path; use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use crate::args::EvalFlags; use crate::args::Flags; @@ -56,8 +57,9 @@ To grant permissions, set them before the script argument. For example: } else { resolve_url_or_path(&run_flags.script)? }; - let permissions = - Permissions::from_options(&ps.options.permissions_options())?; + let permissions = PermissionsContainer::new(Permissions::from_options( + &ps.options.permissions_options(), + )?); let mut worker = create_main_worker(&ps, main_module.clone(), permissions).await?; @@ -71,7 +73,9 @@ pub async fn run_from_stdin(flags: Flags) -> Result { let mut worker = create_main_worker( &ps.clone(), main_module.clone(), - Permissions::from_options(&ps.options.permissions_options())?, + PermissionsContainer::new(Permissions::from_options( + &ps.options.permissions_options(), + )?), ) .await?; @@ -110,8 +114,9 @@ async fn run_with_watch(flags: Flags, script: String) -> Result { let ps = ProcState::build_for_file_watcher((*flags).clone(), sender.clone()) .await?; - let permissions = - Permissions::from_options(&ps.options.permissions_options())?; + let permissions = PermissionsContainer::new(Permissions::from_options( + &ps.options.permissions_options(), + )?); let worker = create_main_worker(&ps, main_module.clone(), permissions).await?; worker.run_for_watcher().await?; @@ -143,8 +148,9 @@ pub async fn eval_command( let main_module = resolve_url_or_path(&format!("./$deno$eval.{}", eval_flags.ext))?; let ps = ProcState::build(flags).await?; - let permissions = - Permissions::from_options(&ps.options.permissions_options())?; + let permissions = PermissionsContainer::new(Permissions::from_options( + &ps.options.permissions_options(), + )?); let mut worker = create_main_worker(&ps, main_module.clone(), permissions).await?; // Create a dummy source file. diff --git a/cli/tools/standalone.rs b/cli/tools/standalone.rs index 471c9605d3..07baecc059 100644 --- a/cli/tools/standalone.rs +++ b/cli/tools/standalone.rs @@ -21,7 +21,7 @@ use deno_core::serde_json; use deno_core::url::Url; use deno_graph::ModuleSpecifier; use deno_runtime::colors; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use std::env; use std::fs; use std::fs::File; @@ -170,7 +170,7 @@ async fn create_standalone_binary( Some(import_map_specifier) => { let file = ps .file_fetcher - .fetch(&import_map_specifier, &mut Permissions::allow_all()) + .fetch(&import_map_specifier, PermissionsContainer::allow_all()) .await .context(format!( "Unable to load '{}' import map", diff --git a/cli/tools/test.rs b/cli/tools/test.rs index 35c0ea0790..9d1774fff7 100644 --- a/cli/tools/test.rs +++ b/cli/tools/test.rs @@ -37,6 +37,7 @@ use deno_runtime::fmt_errors::format_js_error; use deno_runtime::ops::io::Stdio; use deno_runtime::ops::io::StdioPipe; use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use deno_runtime::tokio_util::run_local; use indexmap::IndexMap; use log::Level; @@ -723,7 +724,7 @@ async fn test_specifier( let mut worker = create_main_worker_for_test_or_bench( &ps, specifier.clone(), - permissions, + PermissionsContainer::new(permissions), vec![ops::testing::init( sender, fail_fast_tracker, @@ -895,11 +896,8 @@ async fn fetch_inline_files( ) -> Result, AnyError> { let mut files = Vec::new(); for specifier in specifiers { - let mut fetch_permissions = Permissions::allow_all(); - let file = ps - .file_fetcher - .fetch(&specifier, &mut fetch_permissions) - .await?; + let fetch_permissions = PermissionsContainer::allow_all(); + let file = ps.file_fetcher.fetch(&specifier, fetch_permissions).await?; let inline_files = if file.media_type == MediaType::Unknown { extract_files_from_fenced_blocks( @@ -957,8 +955,8 @@ pub async fn check_specifiers( specifiers, false, lib, - Permissions::allow_all(), - permissions.clone(), + PermissionsContainer::new(Permissions::allow_all()), + PermissionsContainer::new(permissions.clone()), false, ) .await?; @@ -979,8 +977,8 @@ pub async fn check_specifiers( module_specifiers, false, lib, - Permissions::allow_all(), - permissions, + PermissionsContainer::allow_all(), + PermissionsContainer::new(permissions), true, ) .await?; @@ -1324,7 +1322,7 @@ async fn fetch_specifiers_with_test_mode( for (specifier, mode) in &mut specifiers_with_mode { let file = ps .file_fetcher - .fetch(specifier, &mut Permissions::allow_all()) + .fetch(specifier, PermissionsContainer::allow_all()) .await?; if file.media_type == MediaType::Unknown @@ -1342,6 +1340,9 @@ pub async fn run_tests( test_flags: TestFlags, ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; + // 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(&ps.options.permissions_options())?; let specifiers_with_mode = fetch_specifiers_with_test_mode( @@ -1383,6 +1384,9 @@ pub async fn run_tests_with_watch( test_flags: TestFlags, ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; + // 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(&ps.options.permissions_options())?; diff --git a/cli/worker.rs b/cli/worker.rs index ea50966f4f..2d29a7a53d 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -16,7 +16,7 @@ use deno_runtime::colors; use deno_runtime::fmt_errors::format_js_error; use deno_runtime::ops::worker_host::CreateWebWorkerCb; use deno_runtime::ops::worker_host::WorkerEventCb; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use deno_runtime::web_worker::WebWorker; use deno_runtime::web_worker::WebWorkerOptions; use deno_runtime::worker::MainWorker; @@ -410,7 +410,7 @@ impl CliMainWorker { pub async fn create_main_worker( ps: &ProcState, main_module: ModuleSpecifier, - permissions: Permissions, + permissions: PermissionsContainer, ) -> Result { create_main_worker_internal( ps, @@ -426,7 +426,7 @@ pub async fn create_main_worker( pub async fn create_main_worker_for_test_or_bench( ps: &ProcState, main_module: ModuleSpecifier, - permissions: Permissions, + permissions: PermissionsContainer, custom_extensions: Vec, stdio: deno_runtime::ops::io::Stdio, ) -> Result { @@ -444,7 +444,7 @@ pub async fn create_main_worker_for_test_or_bench( async fn create_main_worker_internal( ps: &ProcState, main_module: ModuleSpecifier, - permissions: Permissions, + permissions: PermissionsContainer, mut custom_extensions: Vec, stdio: deno_runtime::ops::io::Stdio, bench_or_test: bool, @@ -731,10 +731,11 @@ mod tests { use deno_core::{resolve_url_or_path, FsModuleLoader}; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; use deno_runtime::deno_web::BlobStore; + use deno_runtime::permissions::Permissions; fn create_test_worker() -> MainWorker { let main_module = resolve_url_or_path("./hello.js").unwrap(); - let permissions = Permissions::default(); + let permissions = PermissionsContainer::new(Permissions::default()); let options = WorkerOptions { bootstrap: BootstrapOptions { diff --git a/runtime/examples/hello_runtime.rs b/runtime/examples/hello_runtime.rs index 19496918ef..fca7ff2c9c 100644 --- a/runtime/examples/hello_runtime.rs +++ b/runtime/examples/hello_runtime.rs @@ -4,7 +4,7 @@ use deno_core::error::AnyError; use deno_core::FsModuleLoader; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; use deno_runtime::deno_web::BlobStore; -use deno_runtime::permissions::Permissions; +use deno_runtime::permissions::PermissionsContainer; use deno_runtime::worker::MainWorker; use deno_runtime::worker::WorkerOptions; use deno_runtime::BootstrapOptions; @@ -71,7 +71,7 @@ async fn main() -> Result<(), AnyError> { let js_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/hello_runtime.js"); let main_module = deno_core::resolve_path(&js_path.to_string_lossy())?; - let permissions = Permissions::allow_all(); + let permissions = PermissionsContainer::allow_all(); let mut worker = MainWorker::bootstrap_from_options( main_module.clone(), diff --git a/runtime/ops/fs.rs b/runtime/ops/fs.rs index 12665ab045..87bb090c30 100644 --- a/runtime/ops/fs.rs +++ b/runtime/ops/fs.rs @@ -3,18 +3,17 @@ use super::io::StdFileResource; use super::utils::into_string; use crate::fs_util::canonicalize_path; -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use deno_core::error::custom_error; use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::op; use deno_core::CancelFuture; use deno_core::CancelHandle; -use deno_core::ZeroCopyBuf; - use deno_core::Extension; use deno_core::OpState; use deno_core::ResourceId; +use deno_core::ZeroCopyBuf; use deno_crypto::rand::thread_rng; use deno_crypto::rand::Rng; use log::debug; @@ -144,11 +143,11 @@ fn open_helper( let _ = mode; // avoid unused warning } - let permissions = state.borrow_mut::(); + let permissions = state.borrow_mut::(); match options { None => { - permissions.read.check(&path, Some(api_name))?; + permissions.check_read(&path, api_name)?; open_options .read(true) .create(false) @@ -159,11 +158,11 @@ fn open_helper( } Some(options) => { if options.read { - permissions.read.check(&path, Some(api_name))?; + permissions.check_read(&path, api_name)?; } if options.write || options.append { - permissions.write.check(&path, Some(api_name))?; + permissions.check_write(&path, api_name)?; } open_options @@ -540,9 +539,8 @@ fn op_umask(state: &mut OpState, mask: Option) -> Result { fn op_chdir(state: &mut OpState, directory: String) -> Result<(), AnyError> { let d = PathBuf::from(&directory); state - .borrow_mut::() - .read - .check(&d, Some("Deno.chdir()"))?; + .borrow_mut::() + .check_read(&d, "Deno.chdir()")?; set_current_dir(&d).map_err(|err| { Error::new(err.kind(), format!("{}, chdir '{}'", err, directory)) })?; @@ -562,9 +560,8 @@ fn op_mkdir_sync(state: &mut OpState, args: MkdirArgs) -> Result<(), AnyError> { let path = Path::new(&args.path).to_path_buf(); let mode = args.mode.unwrap_or(0o777) & 0o777; state - .borrow_mut::() - .write - .check(&path, Some("Deno.mkdirSync()"))?; + .borrow_mut::() + .check_write(&path, "Deno.mkdirSync()")?; debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); let mut builder = std::fs::DirBuilder::new(); builder.recursive(args.recursive); @@ -590,9 +587,8 @@ async fn op_mkdir_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .write - .check(&path, Some("Deno.mkdir()"))?; + .borrow_mut::() + .check_write(&path, "Deno.mkdir()")?; } tokio::task::spawn_blocking(move || { @@ -623,9 +619,8 @@ fn op_chmod_sync( let mode = mode & 0o777; state - .borrow_mut::() - .write - .check(path, Some("Deno.chmodSync()"))?; + .borrow_mut::() + .check_write(path, "Deno.chmodSync()")?; raw_chmod(path, mode) } @@ -641,9 +636,8 @@ async fn op_chmod_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .write - .check(&path, Some("Deno.chmod()"))?; + .borrow_mut::() + .check_write(&path, "Deno.chmod()")?; } tokio::task::spawn_blocking(move || raw_chmod(&path, mode)) @@ -680,9 +674,8 @@ fn op_chown_sync( ) -> Result<(), AnyError> { let path = Path::new(&path).to_path_buf(); state - .borrow_mut::() - .write - .check(&path, Some("Deno.chownSync()"))?; + .borrow_mut::() + .check_write(&path, "Deno.chownSync()")?; #[cfg(unix)] { use crate::errors::get_nix_error_class; @@ -716,9 +709,8 @@ async fn op_chown_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .write - .check(&path, Some("Deno.chown()"))?; + .borrow_mut::() + .check_write(&path, "Deno.chown()")?; } tokio::task::spawn_blocking(move || { @@ -753,9 +745,8 @@ fn op_remove_sync( let path = PathBuf::from(&path); state - .borrow_mut::() - .write - .check(&path, Some("Deno.removeSync()"))?; + .borrow_mut::() + .check_write(&path, "Deno.removeSync()")?; #[cfg(not(unix))] use std::os::windows::prelude::MetadataExt; @@ -802,9 +793,8 @@ async fn op_remove_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .write - .check(&path, Some("Deno.remove()"))?; + .borrow_mut::() + .check_write(&path, "Deno.remove()")?; } tokio::task::spawn_blocking(move || { @@ -854,13 +844,9 @@ fn op_copy_file_sync( let from_path = PathBuf::from(&from); let to_path = PathBuf::from(&to); - let permissions = state.borrow_mut::(); - permissions - .read - .check(&from_path, Some("Deno.copyFileSync()"))?; - permissions - .write - .check(&to_path, Some("Deno.copyFileSync()"))?; + let permissions = state.borrow_mut::(); + permissions.check_read(&from_path, "Deno.copyFileSync()")?; + permissions.check_write(&to_path, "Deno.copyFileSync()")?; // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput // See https://github.com/rust-lang/rust/issues/54800 @@ -955,9 +941,9 @@ async fn op_copy_file_async( { let mut state = state.borrow_mut(); - let permissions = state.borrow_mut::(); - permissions.read.check(&from, Some("Deno.copyFile()"))?; - permissions.write.check(&to, Some("Deno.copyFile()"))?; + let permissions = state.borrow_mut::(); + permissions.check_read(&from, "Deno.copyFile()")?; + permissions.check_write(&to, "Deno.copyFile()")?; } tokio::task::spawn_blocking(move || { @@ -1116,9 +1102,8 @@ fn op_stat_sync( ) -> Result<(), AnyError> { let path = PathBuf::from(&path); state - .borrow_mut::() - .read - .check(&path, Some("Deno.statSync()"))?; + .borrow_mut::() + .check_read(&path, "Deno.statSync()")?; let err_mapper = |err: Error| { Error::new(err.kind(), format!("{}, stat '{}'", err, path.display())) }; @@ -1145,9 +1130,8 @@ async fn op_stat_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .read - .check(&path, Some("Deno.stat()"))?; + .borrow_mut::() + .check_read(&path, "Deno.stat()")?; } tokio::task::spawn_blocking(move || { @@ -1173,10 +1157,10 @@ fn op_realpath_sync( ) -> Result { let path = PathBuf::from(&path); - let permissions = state.borrow_mut::(); - permissions.read.check(&path, Some("Deno.realPathSync()"))?; + let permissions = state.borrow_mut::(); + permissions.check_read(&path, "Deno.realPathSync()")?; if path.is_relative() { - permissions.read.check_blind( + permissions.check_read_blind( ¤t_dir()?, "CWD", "Deno.realPathSync()", @@ -1200,10 +1184,10 @@ async fn op_realpath_async( { let mut state = state.borrow_mut(); - let permissions = state.borrow_mut::(); - permissions.read.check(&path, Some("Deno.realPath()"))?; + let permissions = state.borrow_mut::(); + permissions.check_read(&path, "Deno.realPath()")?; if path.is_relative() { - permissions.read.check_blind( + permissions.check_read_blind( ¤t_dir()?, "CWD", "Deno.realPath()", @@ -1240,9 +1224,8 @@ fn op_read_dir_sync( let path = PathBuf::from(&path); state - .borrow_mut::() - .read - .check(&path, Some("Deno.readDirSync()"))?; + .borrow_mut::() + .check_read(&path, "Deno.readDirSync()")?; debug!("op_read_dir_sync {}", path.display()); let err_mapper = |err: Error| { @@ -1284,9 +1267,8 @@ async fn op_read_dir_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .read - .check(&path, Some("Deno.readDir()"))?; + .borrow_mut::() + .check_read(&path, "Deno.readDir()")?; } tokio::task::spawn_blocking(move || { debug!("op_read_dir_async {}", path.display()); @@ -1332,16 +1314,10 @@ fn op_rename_sync( let oldpath = PathBuf::from(&oldpath); let newpath = PathBuf::from(&newpath); - let permissions = state.borrow_mut::(); - permissions - .read - .check(&oldpath, Some("Deno.renameSync()"))?; - permissions - .write - .check(&oldpath, Some("Deno.renameSync()"))?; - permissions - .write - .check(&newpath, Some("Deno.renameSync()"))?; + let permissions = state.borrow_mut::(); + permissions.check_read(&oldpath, "Deno.renameSync()")?; + permissions.check_write(&oldpath, "Deno.renameSync()")?; + permissions.check_write(&newpath, "Deno.renameSync()")?; let err_mapper = |err: Error| { Error::new( @@ -1368,10 +1344,10 @@ async fn op_rename_async( let newpath = PathBuf::from(&newpath); { let mut state = state.borrow_mut(); - let permissions = state.borrow_mut::(); - permissions.read.check(&oldpath, Some("Deno.rename()"))?; - permissions.write.check(&oldpath, Some("Deno.rename()"))?; - permissions.write.check(&newpath, Some("Deno.rename()"))?; + let permissions = state.borrow_mut::(); + permissions.check_read(&oldpath, "Deno.rename()")?; + permissions.check_write(&oldpath, "Deno.rename()")?; + permissions.check_write(&newpath, "Deno.rename()")?; } tokio::task::spawn_blocking(move || { let err_mapper = |err: Error| { @@ -1401,11 +1377,11 @@ fn op_link_sync( let oldpath = PathBuf::from(&oldpath); let newpath = PathBuf::from(&newpath); - let permissions = state.borrow_mut::(); - permissions.read.check(&oldpath, Some("Deno.linkSync()"))?; - permissions.write.check(&oldpath, Some("Deno.linkSync()"))?; - permissions.read.check(&newpath, Some("Deno.linkSync()"))?; - permissions.write.check(&newpath, Some("Deno.linkSync()"))?; + let permissions = state.borrow_mut::(); + permissions.check_read(&oldpath, "Deno.linkSync()")?; + permissions.check_write(&oldpath, "Deno.linkSync()")?; + permissions.check_read(&newpath, "Deno.linkSync()")?; + permissions.check_write(&newpath, "Deno.linkSync()")?; let err_mapper = |err: Error| { Error::new( @@ -1433,11 +1409,11 @@ async fn op_link_async( { let mut state = state.borrow_mut(); - let permissions = state.borrow_mut::(); - permissions.read.check(&oldpath, Some("Deno.link()"))?; - permissions.write.check(&oldpath, Some("Deno.link()"))?; - permissions.read.check(&newpath, Some("Deno.link()"))?; - permissions.write.check(&newpath, Some("Deno.link()"))?; + let permissions = state.borrow_mut::(); + permissions.check_read(&oldpath, "Deno.link()")?; + permissions.check_write(&oldpath, "Deno.link()")?; + permissions.check_read(&newpath, "Deno.link()")?; + permissions.check_write(&newpath, "Deno.link()")?; } tokio::task::spawn_blocking(move || { @@ -1470,13 +1446,11 @@ fn op_symlink_sync( let newpath = PathBuf::from(&newpath); state - .borrow_mut::() - .write - .check_all(Some("Deno.symlinkSync()"))?; + .borrow_mut::() + .check_write_all("Deno.symlinkSync()")?; state - .borrow_mut::() - .read - .check_all(Some("Deno.symlinkSync()"))?; + .borrow_mut::() + .check_read_all("Deno.symlinkSync()")?; let err_mapper = |err: Error| { Error::new( @@ -1536,13 +1510,11 @@ async fn op_symlink_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .write - .check_all(Some("Deno.symlink()"))?; + .borrow_mut::() + .check_write_all("Deno.symlink()")?; state - .borrow_mut::() - .read - .check_all(Some("Deno.symlink()"))?; + .borrow_mut::() + .check_read_all("Deno.symlink()")?; } tokio::task::spawn_blocking(move || { @@ -1602,9 +1574,8 @@ fn op_read_link_sync( let path = PathBuf::from(&path); state - .borrow_mut::() - .read - .check(&path, Some("Deno.readLink()"))?; + .borrow_mut::() + .check_read(&path, "Deno.readLink()")?; debug!("op_read_link_value {}", path.display()); let err_mapper = |err: Error| { @@ -1629,9 +1600,8 @@ async fn op_read_link_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .read - .check(&path, Some("Deno.readLink()"))?; + .borrow_mut::() + .check_read(&path, "Deno.readLink()")?; } tokio::task::spawn_blocking(move || { debug!("op_read_link_async {}", path.display()); @@ -1688,9 +1658,8 @@ fn op_truncate_sync( let path = PathBuf::from(&path); state - .borrow_mut::() - .write - .check(&path, Some("Deno.truncateSync()"))?; + .borrow_mut::() + .check_write(&path, "Deno.truncateSync()")?; debug!("op_truncate_sync {} {}", path.display(), len); let err_mapper = |err: Error| { @@ -1718,9 +1687,8 @@ async fn op_truncate_async( { let mut state = state.borrow_mut(); state - .borrow_mut::() - .write - .check(&path, Some("Deno.truncate()"))?; + .borrow_mut::() + .check_write(&path, "Deno.truncate()")?; } tokio::task::spawn_blocking(move || { debug!("op_truncate_async {} {}", path.display(), len); @@ -1803,9 +1771,9 @@ fn op_make_temp_dir_sync( let prefix = args.prefix.map(String::from); let suffix = args.suffix.map(String::from); - state.borrow_mut::().write.check( + state.borrow_mut::().check_write( dir.clone().unwrap_or_else(temp_dir).as_path(), - Some("Deno.makeTempDirSync()"), + "Deno.makeTempDirSync()", )?; // TODO(piscisaureus): use byte vector for paths, not a string. @@ -1833,9 +1801,9 @@ async fn op_make_temp_dir_async( let suffix = args.suffix.map(String::from); { let mut state = state.borrow_mut(); - state.borrow_mut::().write.check( + state.borrow_mut::().check_write( dir.clone().unwrap_or_else(temp_dir).as_path(), - Some("Deno.makeTempDir()"), + "Deno.makeTempDir()", )?; } tokio::task::spawn_blocking(move || { @@ -1866,9 +1834,9 @@ fn op_make_temp_file_sync( let prefix = args.prefix.map(String::from); let suffix = args.suffix.map(String::from); - state.borrow_mut::().write.check( + state.borrow_mut::().check_write( dir.clone().unwrap_or_else(temp_dir).as_path(), - Some("Deno.makeTempFileSync()"), + "Deno.makeTempFileSync()", )?; // TODO(piscisaureus): use byte vector for paths, not a string. @@ -1896,9 +1864,9 @@ async fn op_make_temp_file_async( let suffix = args.suffix.map(String::from); { let mut state = state.borrow_mut(); - state.borrow_mut::().write.check( + state.borrow_mut::().check_write( dir.clone().unwrap_or_else(temp_dir).as_path(), - Some("Deno.makeTempFile()"), + "Deno.makeTempFile()", )?; } tokio::task::spawn_blocking(move || { @@ -1973,9 +1941,8 @@ fn op_utime_sync( let mtime = filetime::FileTime::from_unix_time(mtime_secs, mtime_nanos); state - .borrow_mut::() - .write - .check(&path, Some("Deno.utime()"))?; + .borrow_mut::() + .check_write(&path, "Deno.utime()")?; filetime::set_file_times(&path, atime, mtime).map_err(|err| { Error::new(err.kind(), format!("{}, utime '{}'", err, path.display())) })?; @@ -1997,9 +1964,8 @@ async fn op_utime_async( state .borrow_mut() - .borrow_mut::() - .write - .check(&path, Some("Deno.utime()"))?; + .borrow_mut::() + .check_write(&path, "Deno.utime()")?; tokio::task::spawn_blocking(move || { filetime::set_file_times(&path, atime, mtime).map_err(|err| { @@ -2014,11 +1980,9 @@ async fn op_utime_async( #[op] fn op_cwd(state: &mut OpState) -> Result { let path = current_dir()?; - state.borrow_mut::().read.check_blind( - &path, - "CWD", - "Deno.cwd()", - )?; + state + .borrow_mut::() + .check_read_blind(&path, "CWD", "Deno.cwd()")?; let path_str = into_string(path.into_os_string())?; Ok(path_str) } @@ -2028,9 +1992,10 @@ fn op_readfile_sync( state: &mut OpState, path: String, ) -> Result { - let permissions = state.borrow_mut::(); let path = Path::new(&path); - permissions.read.check(path, Some("Deno.readFileSync()"))?; + state + .borrow_mut::() + .check_read(path, "Deno.readFileSync()")?; Ok(std::fs::read(path)?.into()) } @@ -2039,11 +2004,10 @@ fn op_readfile_text_sync( state: &mut OpState, path: String, ) -> Result { - let permissions = state.borrow_mut::(); let path = Path::new(&path); - permissions - .read - .check(path, Some("Deno.readTextFileSync()"))?; + state + .borrow_mut::() + .check_read(path, "Deno.readTextFileSync()")?; Ok(string_from_utf8_lossy(std::fs::read(path)?)) } @@ -2057,9 +2021,8 @@ async fn op_readfile_async( let path = Path::new(&path); let mut state = state.borrow_mut(); state - .borrow_mut::() - .read - .check(path, Some("Deno.readFile()"))?; + .borrow_mut::() + .check_read(path, "Deno.readFile()")?; } let fut = tokio::task::spawn_blocking(move || { let path = Path::new(&path); @@ -2087,9 +2050,8 @@ async fn op_readfile_text_async( let path = Path::new(&path); let mut state = state.borrow_mut(); state - .borrow_mut::() - .read - .check(path, Some("Deno.readTextFile()"))?; + .borrow_mut::() + .check_read(path, "Deno.readTextFile()")?; } let fut = tokio::task::spawn_blocking(move || { let path = Path::new(&path); diff --git a/runtime/ops/fs_events.rs b/runtime/ops/fs_events.rs index d7c4b46707..6cda48ef35 100644 --- a/runtime/ops/fs_events.rs +++ b/runtime/ops/fs_events.rs @@ -1,6 +1,6 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use deno_core::error::AnyError; use deno_core::parking_lot::Mutex; use deno_core::AsyncRefCell; @@ -119,9 +119,8 @@ fn op_fs_events_open( for path in &args.paths { let path = PathBuf::from(path); state - .borrow_mut::() - .read - .check(&path, Some("Deno.watchFs()"))?; + .borrow_mut::() + .check_read(&path, "Deno.watchFs()")?; watcher.watch(&path, recursive_mode)?; } let resource = FsEventsResource { diff --git a/runtime/ops/os/mod.rs b/runtime/ops/os/mod.rs index 28184c949e..537bb33f90 100644 --- a/runtime/ops/os/mod.rs +++ b/runtime/ops/os/mod.rs @@ -1,7 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use super::utils::into_string; -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use crate::worker::ExitCode; use deno_core::error::{type_error, AnyError}; use deno_core::op; @@ -68,11 +68,9 @@ fn noop_op() -> Result<(), AnyError> { #[op] fn op_exec_path(state: &mut OpState) -> Result { let current_exe = env::current_exe().unwrap(); - state.borrow_mut::().read.check_blind( - ¤t_exe, - "exec_path", - "Deno.execPath()", - )?; + state + .borrow_mut::() + .check_read_blind(¤t_exe, "exec_path", "Deno.execPath()")?; // Now apply URL parser to current exe to get fully resolved path, otherwise // we might get `./` and `../` bits in `exec_path` let exe_url = Url::from_file_path(current_exe).unwrap(); @@ -87,7 +85,7 @@ fn op_set_env( key: String, value: String, ) -> Result<(), AnyError> { - state.borrow_mut::().env.check(&key)?; + state.borrow_mut::().check_env(&key)?; if key.is_empty() { return Err(type_error("Key is an empty string.")); } @@ -109,7 +107,7 @@ fn op_set_env( #[op] fn op_env(state: &mut OpState) -> Result, AnyError> { - state.borrow_mut::().env.check_all()?; + state.borrow_mut::().check_env_all()?; Ok(env::vars().collect()) } @@ -121,7 +119,7 @@ fn op_get_env( let skip_permission_check = NODE_ENV_VAR_ALLOWLIST.contains(&key); if !skip_permission_check { - state.borrow_mut::().env.check(&key)?; + state.borrow_mut::().check_env(&key)?; } if key.is_empty() { @@ -144,7 +142,7 @@ fn op_get_env( #[op] fn op_delete_env(state: &mut OpState, key: String) -> Result<(), AnyError> { - state.borrow_mut::().env.check(&key)?; + state.borrow_mut::().check_env(&key)?; if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { return Err(type_error("Key contains invalid characters.")); } @@ -166,27 +164,24 @@ fn op_exit(state: &mut OpState) { #[op] fn op_loadavg(state: &mut OpState) -> Result<(f64, f64, f64), AnyError> { state - .borrow_mut::() - .sys - .check("loadavg", Some("Deno.loadavg()"))?; + .borrow_mut::() + .check_sys("loadavg", "Deno.loadavg()")?; Ok(sys_info::loadavg()) } #[op] fn op_hostname(state: &mut OpState) -> Result { state - .borrow_mut::() - .sys - .check("hostname", Some("Deno.hostname()"))?; + .borrow_mut::() + .check_sys("hostname", "Deno.hostname()")?; Ok(sys_info::hostname()) } #[op] fn op_os_release(state: &mut OpState) -> Result { state - .borrow_mut::() - .sys - .check("osRelease", Some("Deno.osRelease()"))?; + .borrow_mut::() + .check_sys("osRelease", "Deno.osRelease()")?; Ok(sys_info::os_release()) } @@ -195,9 +190,8 @@ fn op_network_interfaces( state: &mut OpState, ) -> Result, AnyError> { state - .borrow_mut::() - .sys - .check("networkInterfaces", Some("Deno.networkInterfaces()"))?; + .borrow_mut::() + .check_sys("networkInterfaces", "Deno.networkInterfaces()")?; Ok(netif::up()?.map(NetworkInterface::from).collect()) } @@ -250,9 +244,8 @@ fn op_system_memory_info( state: &mut OpState, ) -> Result, AnyError> { state - .borrow_mut::() - .sys - .check("systemMemoryInfo", Some("Deno.systemMemoryInfo()"))?; + .borrow_mut::() + .check_sys("systemMemoryInfo", "Deno.systemMemoryInfo()")?; Ok(sys_info::mem_info()) } @@ -260,9 +253,8 @@ fn op_system_memory_info( #[op] fn op_gid(state: &mut OpState) -> Result, AnyError> { state - .borrow_mut::() - .sys - .check("gid", Some("Deno.gid()"))?; + .borrow_mut::() + .check_sys("gid", "Deno.gid()")?; // TODO(bartlomieju): #[allow(clippy::undocumented_unsafe_blocks)] unsafe { @@ -274,9 +266,8 @@ fn op_gid(state: &mut OpState) -> Result, AnyError> { #[op] fn op_gid(state: &mut OpState) -> Result, AnyError> { state - .borrow_mut::() - .sys - .check("gid", Some("Deno.gid()"))?; + .borrow_mut::() + .check_sys("gid", "Deno.gid()")?; Ok(None) } @@ -284,9 +275,8 @@ fn op_gid(state: &mut OpState) -> Result, AnyError> { #[op] fn op_uid(state: &mut OpState) -> Result, AnyError> { state - .borrow_mut::() - .sys - .check("uid", Some("Deno.uid()"))?; + .borrow_mut::() + .check_sys("uid", "Deno.uid()")?; // TODO(bartlomieju): #[allow(clippy::undocumented_unsafe_blocks)] unsafe { @@ -298,9 +288,8 @@ fn op_uid(state: &mut OpState) -> Result, AnyError> { #[op] fn op_uid(state: &mut OpState) -> Result, AnyError> { state - .borrow_mut::() - .sys - .check("uid", Some("Deno.uid()"))?; + .borrow_mut::() + .check_sys("uid", "Deno.uid()")?; Ok(None) } @@ -428,9 +417,8 @@ fn rss() -> usize { fn os_uptime(state: &mut OpState) -> Result { state - .borrow_mut::() - .sys - .check("osUptime", Some("Deno.osUptime()"))?; + .borrow_mut::() + .check_sys("osUptime", "Deno.osUptime()")?; Ok(sys_info::os_uptime()) } diff --git a/runtime/ops/permissions.rs b/runtime/ops/permissions.rs index 8a22446765..d0b0cdd8b4 100644 --- a/runtime/ops/permissions.rs +++ b/runtime/ops/permissions.rs @@ -1,7 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use crate::permissions::parse_sys_kind; -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use deno_core::error::custom_error; use deno_core::error::uri_error; use deno_core::error::AnyError; @@ -37,7 +37,7 @@ pub fn op_query_permission( state: &mut OpState, args: PermissionArgs, ) -> Result { - let permissions = state.borrow::(); + let permissions = state.borrow::().0.lock(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { "read" => permissions.read.query(path.map(Path::new)), @@ -71,7 +71,7 @@ pub fn op_revoke_permission( state: &mut OpState, args: PermissionArgs, ) -> Result { - let permissions = state.borrow_mut::(); + let mut permissions = state.borrow_mut::().0.lock(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { "read" => permissions.read.revoke(path.map(Path::new)), @@ -105,7 +105,7 @@ pub fn op_request_permission( state: &mut OpState, args: PermissionArgs, ) -> Result { - let permissions = state.borrow_mut::(); + let mut permissions = state.borrow_mut::().0.lock(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { "read" => permissions.read.request(path.map(Path::new)), diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index b831f13385..86ad292b88 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -4,7 +4,7 @@ use super::io::ChildStderrResource; use super::io::ChildStdinResource; use super::io::ChildStdoutResource; use super::io::StdFileResource; -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use deno_core::error::AnyError; use deno_core::op; @@ -145,9 +145,8 @@ struct RunInfo { fn op_run(state: &mut OpState, run_args: RunArgs) -> Result { let args = run_args.cmd; state - .borrow_mut::() - .run - .check(&args[0], Some("Deno.run()"))?; + .borrow_mut::() + .check_run(&args[0], "Deno.run()")?; let env = run_args.env; let cwd = run_args.cwd; @@ -354,9 +353,8 @@ fn op_kill( api_name: String, ) -> Result<(), AnyError> { state - .borrow_mut::() - .run - .check_all(Some(&api_name))?; + .borrow_mut::() + .check_run_all(&api_name)?; kill(pid, &signal)?; Ok(()) } diff --git a/runtime/ops/runtime.rs b/runtime/ops/runtime.rs index 582fb18fc6..52dc3f7457 100644 --- a/runtime/ops/runtime.rs +++ b/runtime/ops/runtime.rs @@ -1,6 +1,6 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::op; @@ -26,11 +26,9 @@ fn op_main_module(state: &mut OpState) -> Result { let main_path = std::env::current_dir() .context("Failed to get current working directory")? .join(main_url.to_string()); - state.borrow_mut::().read.check_blind( - &main_path, - "main_module", - "Deno.mainModule", - )?; + state + .borrow_mut::() + .check_read_blind(&main_path, "main_module", "Deno.mainModule")?; } Ok(main) } diff --git a/runtime/ops/spawn.rs b/runtime/ops/spawn.rs index 11940013c5..4bbf1ef489 100644 --- a/runtime/ops/spawn.rs +++ b/runtime/ops/spawn.rs @@ -5,7 +5,7 @@ use super::io::ChildStdinResource; use super::io::ChildStdoutResource; use super::process::Stdio; use super::process::StdioOrRid; -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use deno_core::error::AnyError; use deno_core::op; use deno_core::Extension; @@ -131,9 +131,8 @@ fn node_unstable_create_command( api_name: &str, ) -> Result { state - .borrow_mut::() - .run - .check(&args.cmd, Some(api_name))?; + .borrow_mut::() + .check_run(&args.cmd, api_name)?; let mut command = std::process::Command::new(args.cmd); @@ -196,9 +195,8 @@ fn create_command( ) -> Result { super::check_unstable(state, "Deno.spawn"); state - .borrow_mut::() - .run - .check(&args.cmd, Some(api_name))?; + .borrow_mut::() + .check_run(&args.cmd, api_name)?; let mut command = std::process::Command::new(args.cmd); diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 54aa0d9165..041d3ee6f6 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -3,7 +3,7 @@ use crate::ops::TestingFeaturesEnabled; use crate::permissions::create_child_permissions; use crate::permissions::ChildPermissionsArg; -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use crate::web_worker::run_web_worker; use crate::web_worker::SendableWebWorkerHandle; use crate::web_worker::WebWorker; @@ -15,7 +15,6 @@ use crate::worker::FormatJsErrorFn; use deno_core::error::AnyError; use deno_core::futures::future::LocalFutureObj; use deno_core::op; - use deno_core::serde::Deserialize; use deno_core::CancelFuture; use deno_core::CancelHandle; @@ -32,8 +31,8 @@ use std::sync::Arc; pub struct CreateWebWorkerArgs { pub name: String, pub worker_id: WorkerId, - pub parent_permissions: Permissions, - pub permissions: Permissions, + pub parent_permissions: PermissionsContainer, + pub permissions: PermissionsContainer, pub main_module: ModuleSpecifier, pub worker_type: WebWorkerType, } @@ -164,10 +163,13 @@ fn op_create_worker( if args.permissions.is_some() { super::check_unstable(state, "Worker.deno.permissions"); } - let parent_permissions = state.borrow_mut::(); + let parent_permissions = state.borrow_mut::(); let worker_permissions = if let Some(child_permissions_arg) = args.permissions { - create_child_permissions(parent_permissions, child_permissions_arg)? + let mut parent_permissions = parent_permissions.0.lock(); + let perms = + create_child_permissions(&mut parent_permissions, child_permissions_arg)?; + PermissionsContainer::new(perms) } else { parent_permissions.clone() }; diff --git a/runtime/permissions/mod.rs b/runtime/permissions/mod.rs index d2de1cc94f..024aa81d9a 100644 --- a/runtime/permissions/mod.rs +++ b/runtime/permissions/mod.rs @@ -6,6 +6,7 @@ use deno_core::error::custom_error; use deno_core::error::type_error; use deno_core::error::uri_error; use deno_core::error::AnyError; +use deno_core::parking_lot::Mutex; use deno_core::serde::de; use deno_core::serde::Deserialize; use deno_core::serde::Deserializer; @@ -22,6 +23,7 @@ use std::hash::Hash; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::string::ToString; +use std::sync::Arc; mod prompter; use prompter::permission_prompt; @@ -1614,97 +1616,207 @@ impl Permissions { } } -impl deno_flash::FlashPermissions for Permissions { +/// Wrapper struct for `Permissions` that can be shared across threads. +/// +/// We need a way to have internal mutability for permissions as they might get +/// passed to a future that will prompt the user for permission (and in such +/// case might need to be mutated). Also for the Web Worker API we need a way +/// to send permissions to a new thread. +#[derive(Clone, Debug)] +pub struct PermissionsContainer(pub Arc>); + +impl PermissionsContainer { + pub fn new(perms: Permissions) -> Self { + Self(Arc::new(Mutex::new(perms))) + } + + pub fn allow_all() -> Self { + Self::new(Permissions::allow_all()) + } + + #[inline(always)] + pub fn check_specifier( + &self, + specifier: &ModuleSpecifier, + ) -> Result<(), AnyError> { + self.0.lock().check_specifier(specifier) + } + + #[inline(always)] + pub fn check_read( + &mut self, + path: &Path, + api_name: &str, + ) -> Result<(), AnyError> { + self.0.lock().read.check(path, Some(api_name)) + } + + #[inline(always)] + pub fn check_read_blind( + &mut self, + path: &Path, + display: &str, + api_name: &str, + ) -> Result<(), AnyError> { + self.0.lock().read.check_blind(path, display, api_name) + } + + #[inline(always)] + pub fn check_read_all(&mut self, api_name: &str) -> Result<(), AnyError> { + self.0.lock().read.check_all(Some(api_name)) + } + + #[inline(always)] + pub fn check_write( + &mut self, + path: &Path, + api_name: &str, + ) -> Result<(), AnyError> { + self.0.lock().write.check(path, Some(api_name)) + } + + #[inline(always)] + pub fn check_write_all(&mut self, api_name: &str) -> Result<(), AnyError> { + self.0.lock().write.check_all(Some(api_name)) + } + + #[inline(always)] + pub fn check_run( + &mut self, + cmd: &str, + api_name: &str, + ) -> Result<(), AnyError> { + self.0.lock().run.check(cmd, Some(api_name)) + } + + #[inline(always)] + pub fn check_run_all(&mut self, api_name: &str) -> Result<(), AnyError> { + self.0.lock().run.check_all(Some(api_name)) + } + + #[inline(always)] + pub fn check_sys( + &mut self, + kind: &str, + api_name: &str, + ) -> Result<(), AnyError> { + self.0.lock().sys.check(kind, Some(api_name)) + } + + #[inline(always)] + pub fn check_env(&mut self, var: &str) -> Result<(), AnyError> { + self.0.lock().env.check(var) + } + + #[inline(always)] + pub fn check_env_all(&mut self) -> Result<(), AnyError> { + self.0.lock().env.check_all() + } +} + +impl deno_flash::FlashPermissions for PermissionsContainer { + #[inline(always)] fn check_net>( &mut self, host: &(T, Option), api_name: &str, ) -> Result<(), AnyError> { - self.net.check(host, Some(api_name)) + self.0.lock().net.check(host, Some(api_name)) } } -impl deno_node::NodePermissions for Permissions { +impl deno_node::NodePermissions for PermissionsContainer { + #[inline(always)] fn check_read(&mut self, path: &Path) -> Result<(), AnyError> { - self.read.check(path, None) + self.0.lock().read.check(path, None) } } -impl deno_net::NetPermissions for Permissions { +impl deno_net::NetPermissions for PermissionsContainer { + #[inline(always)] fn check_net>( &mut self, host: &(T, Option), api_name: &str, ) -> Result<(), AnyError> { - self.net.check(host, Some(api_name)) + self.0.lock().net.check(host, Some(api_name)) } + #[inline(always)] fn check_read( &mut self, path: &Path, api_name: &str, ) -> Result<(), AnyError> { - self.read.check(path, Some(api_name)) + self.0.lock().read.check(path, Some(api_name)) } + #[inline(always)] fn check_write( &mut self, path: &Path, api_name: &str, ) -> Result<(), AnyError> { - self.write.check(path, Some(api_name)) + self.0.lock().write.check(path, Some(api_name)) } } -impl deno_fetch::FetchPermissions for Permissions { +impl deno_fetch::FetchPermissions for PermissionsContainer { + #[inline(always)] fn check_net_url( &mut self, url: &url::Url, api_name: &str, ) -> Result<(), AnyError> { - self.net.check_url(url, Some(api_name)) + self.0.lock().net.check_url(url, Some(api_name)) } + #[inline(always)] fn check_read( &mut self, path: &Path, api_name: &str, ) -> Result<(), AnyError> { - self.read.check(path, Some(api_name)) + self.0.lock().read.check(path, Some(api_name)) } } -impl deno_web::TimersPermission for Permissions { +impl deno_web::TimersPermission for PermissionsContainer { + #[inline(always)] fn allow_hrtime(&mut self) -> bool { - self.hrtime.check().is_ok() + self.0.lock().hrtime.check().is_ok() } + #[inline(always)] fn check_unstable(&self, state: &OpState, api_name: &'static str) { crate::ops::check_unstable(state, api_name); } } -impl deno_websocket::WebSocketPermissions for Permissions { +impl deno_websocket::WebSocketPermissions for PermissionsContainer { + #[inline(always)] fn check_net_url( &mut self, url: &url::Url, api_name: &str, ) -> Result<(), AnyError> { - self.net.check_url(url, Some(api_name)) + self.0.lock().net.check_url(url, Some(api_name)) } } // NOTE(bartlomieju): for now, NAPI uses `--allow-ffi` flag, but that might // change in the future. -impl deno_napi::NapiPermissions for Permissions { +impl deno_napi::NapiPermissions for PermissionsContainer { + #[inline(always)] fn check(&mut self, path: Option<&Path>) -> Result<(), AnyError> { - self.ffi.check(path) + self.0.lock().ffi.check(path) } } -impl deno_ffi::FfiPermissions for Permissions { +impl deno_ffi::FfiPermissions for PermissionsContainer { + #[inline(always)] fn check(&mut self, path: Option<&Path>) -> Result<(), AnyError> { - self.ffi.check(path) + self.0.lock().ffi.check(path) } } diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 75c9f0821c..97ccbc870d 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -4,7 +4,7 @@ use crate::inspector_server::InspectorServer; use crate::js; use crate::ops; use crate::ops::io::Stdio; -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use crate::tokio_util::run_local; use crate::worker::FormatJsErrorFn; use crate::BootstrapOptions; @@ -348,7 +348,7 @@ pub struct WebWorkerOptions { impl WebWorker { pub fn bootstrap_from_options( name: String, - permissions: Permissions, + permissions: PermissionsContainer, main_module: ModuleSpecifier, worker_id: WorkerId, options: WebWorkerOptions, @@ -362,7 +362,7 @@ impl WebWorker { pub fn from_options( name: String, - permissions: Permissions, + permissions: PermissionsContainer, main_module: ModuleSpecifier, worker_id: WorkerId, mut options: WebWorkerOptions, @@ -372,7 +372,7 @@ impl WebWorker { let enable_testing_features = options.bootstrap.enable_testing_features; let perm_ext = Extension::builder() .state(move |state| { - state.put::(permissions.clone()); + state.put::(permissions.clone()); state.put(ops::UnstableChecker { unstable }); state.put(ops::TestingFeaturesEnabled(enable_testing_features)); Ok(()) @@ -388,11 +388,11 @@ impl WebWorker { deno_webidl::init(), deno_console::init(), deno_url::init(), - deno_web::init::( + deno_web::init::( options.blob_store.clone(), Some(main_module.clone()), ), - deno_fetch::init::(deno_fetch::Options { + deno_fetch::init::(deno_fetch::Options { user_agent: options.bootstrap.user_agent.clone(), root_cert_store: options.root_cert_store.clone(), unsafely_ignore_certificate_errors: options @@ -402,7 +402,7 @@ impl WebWorker { ..Default::default() }), deno_cache::init::(create_cache), - deno_websocket::init::( + deno_websocket::init::( options.bootstrap.user_agent.clone(), options.root_cert_store.clone(), options.unsafely_ignore_certificate_errors.clone(), @@ -412,7 +412,7 @@ impl WebWorker { deno_crypto::init(options.seed), deno_webgpu::init(unstable), // ffi - deno_ffi::init::(unstable), + deno_ffi::init::(unstable), // Runtime ops that are always initialized for WebWorkers ops::web_worker::init(), ops::runtime::init(main_module.clone()), @@ -428,13 +428,13 @@ impl WebWorker { ops::io::init(), ops::io::init_stdio(options.stdio), deno_tls::init(), - deno_net::init::( + deno_net::init::( options.root_cert_store.clone(), unstable, options.unsafely_ignore_certificate_errors.clone(), ), - deno_napi::init::(unstable), - deno_node::init::(options.npm_resolver), + deno_napi::init::(unstable), + deno_node::init::(options.npm_resolver), ops::os::init_for_worker(), ops::permissions::init(), ops::process::init(), @@ -442,7 +442,7 @@ impl WebWorker { ops::signal::init(), ops::tty::init(), deno_http::init(), - deno_flash::init::(unstable), + deno_flash::init::(unstable), ops::http::init(), // Permissions ext (worker specific state) perm_ext, diff --git a/runtime/worker.rs b/runtime/worker.rs index ea9f4f3e7b..64b8b2c066 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -38,7 +38,7 @@ use crate::inspector_server::InspectorServer; use crate::js; use crate::ops; use crate::ops::io::Stdio; -use crate::permissions::Permissions; +use crate::permissions::PermissionsContainer; use crate::BootstrapOptions; pub type FormatJsErrorFn = dyn Fn(&JsError) -> String + Sync + Send; @@ -185,7 +185,7 @@ impl Default for WorkerOptions { impl MainWorker { pub fn bootstrap_from_options( main_module: ModuleSpecifier, - permissions: Permissions, + permissions: PermissionsContainer, options: WorkerOptions, ) -> Self { let bootstrap_options = options.bootstrap.clone(); @@ -196,7 +196,7 @@ impl MainWorker { pub fn from_options( main_module: ModuleSpecifier, - permissions: Permissions, + permissions: PermissionsContainer, mut options: WorkerOptions, ) -> Self { // Permissions: many ops depend on this @@ -204,7 +204,7 @@ impl MainWorker { let enable_testing_features = options.bootstrap.enable_testing_features; let perm_ext = Extension::builder() .state(move |state| { - state.put::(permissions.clone()); + state.put::(permissions.clone()); state.put(ops::UnstableChecker { unstable }); state.put(ops::TestingFeaturesEnabled(enable_testing_features)); Ok(()) @@ -222,11 +222,11 @@ impl MainWorker { deno_webidl::init(), deno_console::init(), deno_url::init(), - deno_web::init::( + deno_web::init::( options.blob_store.clone(), options.bootstrap.location.clone(), ), - deno_fetch::init::(deno_fetch::Options { + deno_fetch::init::(deno_fetch::Options { user_agent: options.bootstrap.user_agent.clone(), root_cert_store: options.root_cert_store.clone(), unsafely_ignore_certificate_errors: options @@ -236,7 +236,7 @@ impl MainWorker { ..Default::default() }), deno_cache::init::(create_cache), - deno_websocket::init::( + deno_websocket::init::( options.bootstrap.user_agent.clone(), options.root_cert_store.clone(), options.unsafely_ignore_certificate_errors.clone(), @@ -246,7 +246,7 @@ impl MainWorker { deno_crypto::init(options.seed), deno_webgpu::init(unstable), // ffi - deno_ffi::init::(unstable), + deno_ffi::init::(unstable), // Runtime ops ops::runtime::init(main_module.clone()), ops::worker_host::init( @@ -261,20 +261,20 @@ impl MainWorker { ops::io::init(), ops::io::init_stdio(options.stdio), deno_tls::init(), - deno_net::init::( + deno_net::init::( options.root_cert_store.clone(), unstable, options.unsafely_ignore_certificate_errors.clone(), ), - deno_napi::init::(unstable), - deno_node::init::(options.npm_resolver), + deno_napi::init::(unstable), + deno_node::init::(options.npm_resolver), ops::os::init(exit_code.clone()), ops::permissions::init(), ops::process::init(), ops::signal::init(), ops::tty::init(), deno_http::init(), - deno_flash::init::(unstable), + deno_flash::init::(unstable), ops::http::init(), // Permissions ext (worker specific state) perm_ext,