From dd12a668e7b4d9cc293027995012da68b4c3aba7 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Sun, 21 Mar 2021 12:49:58 +0000 Subject: [PATCH] refactor(runtime/permissions): Rename permission structs (#9841) --- runtime/js/11_workers.js | 10 +- runtime/ops/worker_host.rs | 52 ++++----- runtime/permissions.rs | 218 ++++++++++++++++++------------------- 3 files changed, 140 insertions(+), 140 deletions(-) diff --git a/runtime/js/11_workers.js b/runtime/js/11_workers.js index 6797307d9d..2917ec004b 100644 --- a/runtime/js/11_workers.js +++ b/runtime/js/11_workers.js @@ -63,7 +63,7 @@ * @param {string} permission * @return {boolean} */ - function parseBooleanPermission( + function parseUnitPermission( value, permission, ) { @@ -119,12 +119,12 @@ write = "inherit", }) { return { - env: parseBooleanPermission(env, "env"), - hrtime: parseBooleanPermission(hrtime, "hrtime"), + env: parseUnitPermission(env, "env"), + hrtime: parseUnitPermission(hrtime, "hrtime"), net: parseArrayPermission(net, "net"), - plugin: parseBooleanPermission(plugin, "plugin"), + plugin: parseUnitPermission(plugin, "plugin"), read: parseArrayPermission(read, "read"), - run: parseBooleanPermission(run, "run"), + run: parseUnitPermission(run, "run"), write: parseArrayPermission(write, "write"), }; } diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index a56c460f32..817a4c70fd 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -2,13 +2,13 @@ use crate::permissions::resolve_read_allowlist; use crate::permissions::resolve_write_allowlist; -use crate::permissions::BooleanPermission; -use crate::permissions::NetPermission; +use crate::permissions::NetDescriptor; use crate::permissions::PermissionState; use crate::permissions::Permissions; -use crate::permissions::ReadPermission; +use crate::permissions::ReadDescriptor; use crate::permissions::UnaryPermission; -use crate::permissions::WritePermission; +use crate::permissions::UnitPermission; +use crate::permissions::WriteDescriptor; use crate::web_worker::run_web_worker; use crate::web_worker::WebWorker; use crate::web_worker::WebWorkerHandle; @@ -109,9 +109,9 @@ pub fn init( } fn merge_boolean_permission( - mut main: BooleanPermission, + mut main: UnitPermission, worker: Option, -) -> Result { +) -> Result { if let Some(worker) = worker { if worker < main.state { return Err(custom_error( @@ -126,9 +126,9 @@ fn merge_boolean_permission( } fn merge_net_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { + mut main: UnaryPermission, + worker: Option>, +) -> Result, AnyError> { if let Some(worker) = worker { if (worker.global_state < main.global_state) || !worker @@ -149,9 +149,9 @@ fn merge_net_permission( } fn merge_read_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { + mut main: UnaryPermission, + worker: Option>, +) -> Result, AnyError> { if let Some(worker) = worker { if (worker.global_state < main.global_state) || !worker @@ -172,9 +172,9 @@ fn merge_read_permission( } fn merge_write_permission( - mut main: UnaryPermission, - worker: Option>, -) -> Result, AnyError> { + mut main: UnaryPermission, + worker: Option>, +) -> Result, AnyError> { if let Some(worker) = worker { if (worker.global_state < main.global_state) || !worker @@ -216,15 +216,15 @@ struct PermissionsArg { #[serde(default, deserialize_with = "as_permission_state")] hrtime: Option, #[serde(default, deserialize_with = "as_unary_net_permission")] - net: Option>, + net: Option>, #[serde(default, deserialize_with = "as_permission_state")] plugin: Option, #[serde(default, deserialize_with = "as_unary_read_permission")] - read: Option>, + read: Option>, #[serde(default, deserialize_with = "as_permission_state")] run: Option, #[serde(default, deserialize_with = "as_unary_write_permission")] - write: Option>, + write: Option>, } fn as_permission_state<'de, D>( @@ -288,20 +288,20 @@ impl<'de> de::Visitor<'de> for ParseBooleanOrStringVec { fn as_unary_net_permission<'de, D>( deserializer: D, -) -> Result>, D::Error> +) -> Result>, D::Error> where D: Deserializer<'de>, { let value: UnaryPermissionBase = deserializer.deserialize_any(ParseBooleanOrStringVec)?; - let allowed: HashSet = value + let allowed: HashSet = value .paths .into_iter() - .map(NetPermission::from_string) + .map(NetDescriptor::from_string) .collect(); - Ok(Some(UnaryPermission:: { + Ok(Some(UnaryPermission:: { global_state: value.global_state, granted_list: allowed, ..Default::default() @@ -310,7 +310,7 @@ where fn as_unary_read_permission<'de, D>( deserializer: D, -) -> Result>, D::Error> +) -> Result>, D::Error> where D: Deserializer<'de>, { @@ -320,7 +320,7 @@ where let paths: Vec = value.paths.into_iter().map(PathBuf::from).collect(); - Ok(Some(UnaryPermission:: { + Ok(Some(UnaryPermission:: { global_state: value.global_state, granted_list: resolve_read_allowlist(&Some(paths)), ..Default::default() @@ -329,7 +329,7 @@ where fn as_unary_write_permission<'de, D>( deserializer: D, -) -> Result>, D::Error> +) -> Result>, D::Error> where D: Deserializer<'de>, { @@ -339,7 +339,7 @@ where let paths: Vec = value.paths.into_iter().map(PathBuf::from).collect(); - Ok(Some(UnaryPermission:: { + Ok(Some(UnaryPermission:: { global_state: value.global_state, granted_list: resolve_write_allowlist(&Some(paths)), ..Default::default() diff --git a/runtime/permissions.rs b/runtime/permissions.rs index 5cd2280024..ba150f47ef 100644 --- a/runtime/permissions.rs +++ b/runtime/permissions.rs @@ -69,6 +69,41 @@ impl Default for PermissionState { } } +#[derive(Clone, Debug, Default, PartialEq)] +pub struct UnitPermission { + pub name: &'static str, + pub description: &'static str, + pub state: PermissionState, +} + +impl UnitPermission { + pub fn query(&self) -> PermissionState { + self.state + } + + pub fn request(&mut self) -> PermissionState { + if self.state == PermissionState::Prompt { + if permission_prompt(&format!("access to {}", self.description)) { + self.state = PermissionState::Granted; + } else { + self.state = PermissionState::Denied; + } + } + self.state + } + + pub fn revoke(&mut self) -> PermissionState { + if self.state == PermissionState::Granted { + self.state = PermissionState::Prompt; + } + self.state + } + + pub fn check(&self) -> Result<(), AnyError> { + self.state.check(self.name, None) + } +} + #[derive(Clone, Debug, Default, Deserialize, PartialEq)] pub struct UnaryPermission { #[serde(skip)] @@ -81,9 +116,37 @@ pub struct UnaryPermission { } #[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)] -pub struct ReadPermission(pub PathBuf); +pub struct ReadDescriptor(pub PathBuf); -impl UnaryPermission { +#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)] +pub struct WriteDescriptor(pub PathBuf); + +#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)] +pub struct NetDescriptor(pub String, pub Option); + +impl NetDescriptor { + fn new>(host: &&(T, Option)) -> Self { + NetDescriptor(host.0.as_ref().to_string(), host.1) + } + + pub fn from_string(host: String) -> Self { + let url = url::Url::parse(&format!("http://{}", host)).unwrap(); + let hostname = url.host_str().unwrap().to_string(); + + NetDescriptor(hostname, url.port()) + } +} + +impl fmt::Display for NetDescriptor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&match self.1 { + None => self.0.clone(), + Some(port) => format!("{}:{}", self.0, port), + }) + } +} + +impl UnaryPermission { pub fn query(&self, path: Option<&Path>) -> PermissionState { let path = path.map(|p| resolve_from_cwd(p).unwrap()); if self.global_state == PermissionState::Denied @@ -123,13 +186,13 @@ impl UnaryPermission { self .granted_list .retain(|path| !path.0.starts_with(&resolved_path)); - self.granted_list.insert(ReadPermission(resolved_path)); + self.granted_list.insert(ReadDescriptor(resolved_path)); PermissionState::Granted } else { self .denied_list .retain(|path| !resolved_path.starts_with(&path.0)); - self.denied_list.insert(ReadPermission(resolved_path)); + self.denied_list.insert(ReadDescriptor(resolved_path)); self.global_state = PermissionState::Denied; PermissionState::Denied } @@ -189,10 +252,7 @@ impl UnaryPermission { } } -#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)] -pub struct WritePermission(pub PathBuf); - -impl UnaryPermission { +impl UnaryPermission { pub fn query(&self, path: Option<&Path>) -> PermissionState { let path = path.map(|p| resolve_from_cwd(p).unwrap()); if self.global_state == PermissionState::Denied @@ -232,13 +292,13 @@ impl UnaryPermission { self .granted_list .retain(|path| !path.0.starts_with(&resolved_path)); - self.granted_list.insert(WritePermission(resolved_path)); + self.granted_list.insert(WriteDescriptor(resolved_path)); PermissionState::Granted } else { self .denied_list .retain(|path| !resolved_path.starts_with(&path.0)); - self.denied_list.insert(WritePermission(resolved_path)); + self.denied_list.insert(WriteDescriptor(resolved_path)); self.global_state = PermissionState::Denied; PermissionState::Denied } @@ -285,32 +345,7 @@ impl UnaryPermission { } } -#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)] -pub struct NetPermission(pub String, pub Option); - -impl NetPermission { - fn new>(host: &&(T, Option)) -> Self { - NetPermission(host.0.as_ref().to_string(), host.1) - } - - pub fn from_string(host: String) -> Self { - let url = url::Url::parse(&format!("http://{}", host)).unwrap(); - let hostname = url.host_str().unwrap().to_string(); - - NetPermission(hostname, url.port()) - } -} - -impl fmt::Display for NetPermission { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&match self.1 { - None => self.0.clone(), - Some(port) => format!("{}:{}", self.0, port), - }) - } -} - -impl UnaryPermission { +impl UnaryPermission { pub fn query>( &self, host: Option<&(T, Option)>, @@ -323,7 +358,7 @@ impl UnaryPermission { .denied_list .iter() .any(|host_| host.0.as_ref() == host_.0), - Some(_) => self.denied_list.contains(&NetPermission::new(host)), + Some(_) => self.denied_list.contains(&NetDescriptor::new(host)), }, } { @@ -332,11 +367,11 @@ impl UnaryPermission { || match host.as_ref() { None => false, Some(host) => { - self.granted_list.contains(&NetPermission::new(&&( + self.granted_list.contains(&NetDescriptor::new(&&( host.0.as_ref().to_string(), None, ))) - || self.granted_list.contains(&NetPermission::new(host)) + || self.granted_list.contains(&NetDescriptor::new(host)) } } { @@ -353,7 +388,7 @@ impl UnaryPermission { if let Some(host) = host { let state = self.query(Some(host)); if state == PermissionState::Prompt { - let host = NetPermission::new(&host); + let host = NetDescriptor::new(&host); if permission_prompt(&format!("network access to \"{}\"", host)) { if host.1.is_none() { self.granted_list.retain(|h| h.0 != host.0); @@ -393,7 +428,7 @@ impl UnaryPermission { host: Option<&(T, Option)>, ) -> PermissionState { if let Some(host) = host { - self.granted_list.remove(&NetPermission::new(&host)); + self.granted_list.remove(&NetDescriptor::new(&host)); if host.1.is_none() { self.granted_list.retain(|h| h.0 != host.0.as_ref()); } @@ -412,7 +447,7 @@ impl UnaryPermission { ) -> Result<(), AnyError> { self.query(Some(host)).check( self.name, - Some(&format!("\"{}\"", NetPermission::new(&host))), + Some(&format!("\"{}\"", NetDescriptor::new(&host))), ) } @@ -431,50 +466,15 @@ impl UnaryPermission { } } -#[derive(Clone, Debug, Default, PartialEq)] -pub struct BooleanPermission { - pub name: &'static str, - pub description: &'static str, - pub state: PermissionState, -} - -impl BooleanPermission { - pub fn query(&self) -> PermissionState { - self.state - } - - pub fn request(&mut self) -> PermissionState { - if self.state == PermissionState::Prompt { - if permission_prompt(&format!("access to {}", self.description)) { - self.state = PermissionState::Granted; - } else { - self.state = PermissionState::Denied; - } - } - self.state - } - - pub fn revoke(&mut self) -> PermissionState { - if self.state == PermissionState::Granted { - self.state = PermissionState::Prompt; - } - self.state - } - - pub fn check(&self) -> Result<(), AnyError> { - self.state.check(self.name, None) - } -} - #[derive(Clone, Debug, Default, PartialEq)] pub struct Permissions { - pub read: UnaryPermission, - pub write: UnaryPermission, - pub net: UnaryPermission, - pub env: BooleanPermission, - pub run: BooleanPermission, - pub plugin: BooleanPermission, - pub hrtime: BooleanPermission, + pub read: UnaryPermission, + pub write: UnaryPermission, + pub net: UnaryPermission, + pub env: UnitPermission, + pub run: UnitPermission, + pub plugin: UnitPermission, + pub hrtime: UnitPermission, } #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] @@ -491,8 +491,8 @@ pub struct PermissionsOptions { impl Permissions { pub fn new_read( state: &Option>, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> UnaryPermission { + UnaryPermission:: { name: "read", description: "read the file system", global_state: global_state_from_option(state), @@ -503,8 +503,8 @@ impl Permissions { pub fn new_write( state: &Option>, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> UnaryPermission { + UnaryPermission:: { name: "write", description: "write to the file system", global_state: global_state_from_option(state), @@ -515,8 +515,8 @@ impl Permissions { pub fn new_net( state: &Option>, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> UnaryPermission { + UnaryPermission:: { name: "net", description: "network", global_state: global_state_from_option(state), @@ -524,7 +524,7 @@ impl Permissions { .as_ref() .map(|v| { v.iter() - .map(|x| NetPermission::from_string(x.clone())) + .map(|x| NetDescriptor::from_string(x.clone())) .collect() }) .unwrap_or_else(HashSet::new), @@ -532,19 +532,19 @@ impl Permissions { } } - pub fn new_env(state: bool) -> BooleanPermission { + pub fn new_env(state: bool) -> UnitPermission { boolean_permission_from_flag_bool(state, "env", "environment variables") } - pub fn new_run(state: bool) -> BooleanPermission { + pub fn new_run(state: bool) -> UnitPermission { boolean_permission_from_flag_bool(state, "run", "run a subprocess") } - pub fn new_plugin(state: bool) -> BooleanPermission { + pub fn new_plugin(state: bool) -> UnitPermission { boolean_permission_from_flag_bool(state, "plugin", "open a plugin") } - pub fn new_hrtime(state: bool) -> BooleanPermission { + pub fn new_hrtime(state: bool) -> UnitPermission { boolean_permission_from_flag_bool(state, "hrtime", "high precision time") } @@ -619,8 +619,8 @@ fn boolean_permission_from_flag_bool( flag: bool, name: &'static str, description: &'static str, -) -> BooleanPermission { - BooleanPermission { +) -> UnitPermission { + UnitPermission { name, description, state: if flag { @@ -641,11 +641,11 @@ fn global_state_from_option(flag: &Option>) -> PermissionState { pub fn resolve_read_allowlist( allow: &Option>, -) -> HashSet { +) -> HashSet { if let Some(v) = allow { v.iter() .map(|raw_path| { - ReadPermission(resolve_from_cwd(Path::new(&raw_path)).unwrap()) + ReadDescriptor(resolve_from_cwd(Path::new(&raw_path)).unwrap()) }) .collect() } else { @@ -655,11 +655,11 @@ pub fn resolve_read_allowlist( pub fn resolve_write_allowlist( allow: &Option>, -) -> HashSet { +) -> HashSet { if let Some(v) = allow { v.iter() .map(|raw_path| { - WritePermission(resolve_from_cwd(Path::new(&raw_path)).unwrap()) + WriteDescriptor(resolve_from_cwd(Path::new(&raw_path)).unwrap()) }) .collect() } else { @@ -1054,19 +1054,19 @@ mod tests { global_state: PermissionState::Prompt, ..Permissions::new_net(&Some(svec!["127.0.0.1:8000"])) }, - env: BooleanPermission { + env: UnitPermission { state: PermissionState::Prompt, ..Default::default() }, - run: BooleanPermission { + run: UnitPermission { state: PermissionState::Prompt, ..Default::default() }, - plugin: BooleanPermission { + plugin: UnitPermission { state: PermissionState::Prompt, ..Default::default() }, - hrtime: BooleanPermission { + hrtime: UnitPermission { state: PermissionState::Prompt, ..Default::default() }, @@ -1152,19 +1152,19 @@ mod tests { global_state: PermissionState::Prompt, ..Permissions::new_net(&Some(svec!["127.0.0.1"])) }, - env: BooleanPermission { + env: UnitPermission { state: PermissionState::Granted, ..Default::default() }, - run: BooleanPermission { + run: UnitPermission { state: PermissionState::Granted, ..Default::default() }, - plugin: BooleanPermission { + plugin: UnitPermission { state: PermissionState::Prompt, ..Default::default() }, - hrtime: BooleanPermission { + hrtime: UnitPermission { state: PermissionState::Denied, ..Default::default() },