diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-01-07 17:25:34 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-07 17:25:34 +0100 |
commit | fac64478157ee563b185edb5734688e4523df3a1 (patch) | |
tree | 888d562982e1fc37dfb9a4459928bcec84d55dfc /runtime/permissions/mod.rs | |
parent | 82e930726ee5dbac8e6eae0962c07c72daf9843c (diff) |
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<Mutex<>>" (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.
Diffstat (limited to 'runtime/permissions/mod.rs')
-rw-r--r-- | runtime/permissions/mod.rs | 150 |
1 files changed, 131 insertions, 19 deletions
diff --git a/runtime/permissions/mod.rs b/runtime/permissions/mod.rs index d2de1cc94..024aa81d9 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<Mutex<Permissions>>); + +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<T: AsRef<str>>( &mut self, host: &(T, Option<u16>), 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<T: AsRef<str>>( &mut self, host: &(T, Option<u16>), 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) } } |