diff options
author | crowlKats <13135287+crowlKats@users.noreply.github.com> | 2021-04-13 13:25:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-13 13:25:21 +0200 |
commit | 8b59d9f7bc2ce4aa33b6b8ac41495c62d3791f3c (patch) | |
tree | 2dbbd97062244f65145e917ee6025e5ac595675a /runtime/permissions.rs | |
parent | ec1fce58d93de61462ddf0c9e9c58e6e844d2230 (diff) |
feat(permissions): allow env permission to take values (#9825)
Diffstat (limited to 'runtime/permissions.rs')
-rw-r--r-- | runtime/permissions.rs | 219 |
1 files changed, 193 insertions, 26 deletions
diff --git a/runtime/permissions.rs b/runtime/permissions.rs index a266de40b..e43e0eaa0 100644 --- a/runtime/permissions.rs +++ b/runtime/permissions.rs @@ -196,6 +196,9 @@ impl fmt::Display for NetDescriptor { } #[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)] +pub struct EnvDescriptor(pub String); + +#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)] pub struct RunDescriptor(pub String); impl UnaryPermission<ReadDescriptor> { @@ -574,6 +577,114 @@ impl UnaryPermission<NetDescriptor> { } } +impl UnaryPermission<EnvDescriptor> { + pub fn query(&self, env: Option<&str>) -> PermissionState { + #[cfg(windows)] + let env = env.map(|env| env.to_uppercase()); + #[cfg(windows)] + let env = env.as_deref(); + if self.global_state == PermissionState::Denied + && match env { + None => true, + Some(env) => self.denied_list.iter().any(|env_| env_.0 == env), + } + { + PermissionState::Denied + } else if self.global_state == PermissionState::Granted + || match env { + None => false, + Some(env) => self.granted_list.iter().any(|env_| env_.0 == env), + } + { + PermissionState::Granted + } else { + PermissionState::Prompt + } + } + + pub fn request(&mut self, env: Option<&str>) -> PermissionState { + if let Some(env) = env { + #[cfg(windows)] + let env = env.to_uppercase(); + let state = self.query(Some(&env)); + if state == PermissionState::Prompt { + if permission_prompt(&format!("env access to \"{}\"", env)) { + self.granted_list.retain(|env_| env_.0 != env); + self.granted_list.insert(EnvDescriptor(env.to_string())); + PermissionState::Granted + } else { + self.denied_list.retain(|env_| env_.0 != env); + self.denied_list.insert(EnvDescriptor(env.to_string())); + self.global_state = PermissionState::Denied; + PermissionState::Denied + } + } else { + state + } + } else { + let state = self.query(None); + if state == PermissionState::Prompt { + if permission_prompt("env access") { + self.granted_list.clear(); + self.global_state = PermissionState::Granted; + PermissionState::Granted + } else { + self.global_state = PermissionState::Denied; + PermissionState::Denied + } + } else { + state + } + } + } + + pub fn revoke(&mut self, env: Option<&str>) -> PermissionState { + if let Some(env) = env { + #[cfg(windows)] + let env = env.to_uppercase(); + self.granted_list.retain(|env_| env_.0 != env); + } else { + self.granted_list.clear(); + if self.global_state == PermissionState::Granted { + self.global_state = PermissionState::Prompt; + } + } + self.query(env) + } + + pub fn check(&mut self, env: &str) -> Result<(), AnyError> { + #[cfg(windows)] + let env = &env.to_uppercase(); + let (result, prompted) = self.query(Some(env)).check( + self.name, + Some(&format!("\"{}\"", env)), + self.prompt, + ); + if prompted { + if result.is_ok() { + self.granted_list.insert(EnvDescriptor(env.to_string())); + } else { + self.denied_list.insert(EnvDescriptor(env.to_string())); + self.global_state = PermissionState::Denied; + } + } + result + } + + pub fn check_all(&mut self) -> Result<(), AnyError> { + let (result, prompted) = + self.query(None).check(self.name, Some("all"), self.prompt); + if prompted { + if result.is_ok() { + self.global_state = PermissionState::Granted; + } else { + self.global_state = PermissionState::Denied; + } + } + result + } +} + impl UnaryPermission<RunDescriptor> { pub fn query(&self, cmd: Option<&str>) -> PermissionState { if self.global_state == PermissionState::Denied @@ -677,7 +788,7 @@ pub struct Permissions { pub read: UnaryPermission<ReadDescriptor>, pub write: UnaryPermission<WriteDescriptor>, pub net: UnaryPermission<NetDescriptor>, - pub env: UnitPermission, + pub env: UnaryPermission<EnvDescriptor>, pub run: UnaryPermission<RunDescriptor>, pub plugin: UnitPermission, pub hrtime: UnitPermission, @@ -685,7 +796,7 @@ pub struct Permissions { #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct PermissionsOptions { - pub allow_env: bool, + pub allow_env: Option<Vec<String>>, pub allow_hrtime: bool, pub allow_net: Option<Vec<String>>, pub allow_plugin: bool, @@ -745,13 +856,31 @@ impl Permissions { } } - pub fn new_env(state: bool, prompt: bool) -> UnitPermission { - boolean_permission_from_flag_bool( - state, - "env", - "environment variables", + pub fn new_env( + state: &Option<Vec<String>>, + prompt: bool, + ) -> UnaryPermission<EnvDescriptor> { + UnaryPermission::<EnvDescriptor> { + name: "env", + description: "environment variables", + global_state: global_state_from_option(state), + granted_list: state + .as_ref() + .map(|v| { + v.iter() + .map(|x| { + EnvDescriptor(if cfg!(windows) { + x.to_uppercase() + } else { + x.clone() + }) + }) + .collect() + }) + .unwrap_or_else(HashSet::new), + denied_list: Default::default(), prompt, - ) + } } pub fn new_run( @@ -772,11 +901,11 @@ impl Permissions { } pub fn new_plugin(state: bool, prompt: bool) -> UnitPermission { - boolean_permission_from_flag_bool(state, "plugin", "open a plugin", prompt) + unit_permission_from_flag_bool(state, "plugin", "open a plugin", prompt) } pub fn new_hrtime(state: bool, prompt: bool) -> UnitPermission { - boolean_permission_from_flag_bool( + unit_permission_from_flag_bool( state, "hrtime", "high precision time", @@ -789,7 +918,7 @@ impl Permissions { read: Permissions::new_read(&opts.allow_read, opts.prompt), write: Permissions::new_write(&opts.allow_write, opts.prompt), net: Permissions::new_net(&opts.allow_net, opts.prompt), - env: Permissions::new_env(opts.allow_env, opts.prompt), + env: Permissions::new_env(&opts.allow_env, opts.prompt), run: Permissions::new_run(&opts.allow_run, opts.prompt), plugin: Permissions::new_plugin(opts.allow_plugin, opts.prompt), hrtime: Permissions::new_hrtime(opts.allow_hrtime, opts.prompt), @@ -801,7 +930,7 @@ impl Permissions { read: Permissions::new_read(&Some(vec![]), false), write: Permissions::new_write(&Some(vec![]), false), net: Permissions::new_net(&Some(vec![]), false), - env: Permissions::new_env(true, false), + env: Permissions::new_env(&Some(vec![]), false), run: Permissions::new_run(&Some(vec![]), false), plugin: Permissions::new_plugin(true, false), hrtime: Permissions::new_hrtime(true, false), @@ -845,7 +974,7 @@ impl deno_websocket::WebSocketPermissions for Permissions { } } -fn boolean_permission_from_flag_bool( +fn unit_permission_from_flag_bool( flag: bool, name: &'static str, description: &'static str, @@ -1289,9 +1418,9 @@ mod tests { global_state: PermissionState::Prompt, ..Permissions::new_net(&Some(svec!["127.0.0.1:8000"]), false) }, - env: UnitPermission { - state: PermissionState::Prompt, - ..Default::default() + env: UnaryPermission { + global_state: PermissionState::Prompt, + ..Permissions::new_env(&Some(svec!["HOME"]), false) }, run: UnaryPermission { global_state: PermissionState::Prompt, @@ -1322,8 +1451,10 @@ mod tests { assert_eq!(perms1.net.query(Some(&("127.0.0.1", None))), PermissionState::Granted); assert_eq!(perms2.net.query::<&str>(None), PermissionState::Prompt); assert_eq!(perms2.net.query(Some(&("127.0.0.1", Some(8000)))), PermissionState::Granted); - assert_eq!(perms1.env.query(), PermissionState::Granted); - assert_eq!(perms2.env.query(), PermissionState::Prompt); + assert_eq!(perms1.env.query(None), PermissionState::Granted); + assert_eq!(perms1.env.query(Some(&"HOME".to_string())), PermissionState::Granted); + assert_eq!(perms2.env.query(None), PermissionState::Prompt); + assert_eq!(perms2.env.query(Some(&"HOME".to_string())), PermissionState::Granted); assert_eq!(perms1.run.query(None), PermissionState::Granted); assert_eq!(perms1.run.query(Some(&"deno".to_string())), PermissionState::Granted); assert_eq!(perms2.run.query(None), PermissionState::Prompt); @@ -1356,9 +1487,10 @@ mod tests { set_prompt_result(false); assert_eq!(perms.net.request(Some(&("127.0.0.1", Some(8000)))), PermissionState::Granted); set_prompt_result(true); - assert_eq!(perms.env.request(), PermissionState::Granted); + assert_eq!(perms.env.request(Some(&"HOME".to_string())), PermissionState::Granted); + assert_eq!(perms.env.query(None), PermissionState::Prompt); set_prompt_result(false); - assert_eq!(perms.env.request(), PermissionState::Granted); + assert_eq!(perms.env.request(Some(&"HOME".to_string())), PermissionState::Granted); set_prompt_result(true); assert_eq!(perms.run.request(Some(&"deno".to_string())), PermissionState::Granted); assert_eq!(perms.run.query(None), PermissionState::Prompt); @@ -1390,9 +1522,9 @@ mod tests { global_state: PermissionState::Prompt, ..Permissions::new_net(&Some(svec!["127.0.0.1"]), false) }, - env: UnitPermission { - state: PermissionState::Granted, - ..Default::default() + env: UnaryPermission { + global_state: PermissionState::Prompt, + ..Permissions::new_env(&Some(svec!["HOME"]), false) }, run: UnaryPermission { global_state: PermissionState::Prompt, @@ -1417,7 +1549,7 @@ mod tests { assert_eq!(perms.write.query(Some(&Path::new("/foo/bar"))), PermissionState::Prompt); assert_eq!(perms.net.revoke(Some(&("127.0.0.1", Some(8000)))), PermissionState::Granted); assert_eq!(perms.net.revoke(Some(&("127.0.0.1", None))), PermissionState::Prompt); - assert_eq!(perms.env.revoke(), PermissionState::Prompt); + assert_eq!(perms.env.revoke(Some(&"HOME".to_string())), PermissionState::Prompt); assert_eq!(perms.run.revoke(Some(&"deno".to_string())), PermissionState::Prompt); assert_eq!(perms.plugin.revoke(), PermissionState::Prompt); assert_eq!(perms.hrtime.revoke(), PermissionState::Denied); @@ -1430,7 +1562,7 @@ mod tests { read: Permissions::new_read(&None, true), write: Permissions::new_write(&None, true), net: Permissions::new_net(&None, true), - env: Permissions::new_env(false, true), + env: Permissions::new_env(&None, true), run: Permissions::new_run(&None, true), plugin: Permissions::new_plugin(false, true), hrtime: Permissions::new_hrtime(false, true), @@ -1466,6 +1598,12 @@ mod tests { assert!(perms.run.check("ls").is_err()); set_prompt_result(true); + assert!(perms.env.check("HOME").is_ok()); + set_prompt_result(false); + assert!(perms.env.check("HOME").is_ok()); + assert!(perms.env.check("PATH").is_err()); + + set_prompt_result(true); assert!(perms.hrtime.check().is_ok()); set_prompt_result(false); assert!(perms.hrtime.check().is_ok()); @@ -1477,7 +1615,7 @@ mod tests { read: Permissions::new_read(&None, true), write: Permissions::new_write(&None, true), net: Permissions::new_net(&None, true), - env: Permissions::new_env(false, true), + env: Permissions::new_env(&None, true), run: Permissions::new_run(&None, true), plugin: Permissions::new_plugin(false, true), hrtime: Permissions::new_hrtime(false, true), @@ -1520,8 +1658,37 @@ mod tests { assert!(perms.run.check("ls").is_ok()); set_prompt_result(false); + assert!(perms.env.check("HOME").is_err()); + set_prompt_result(true); + assert!(perms.env.check("HOME").is_err()); + assert!(perms.env.check("PATH").is_ok()); + set_prompt_result(false); + assert!(perms.env.check("PATH").is_ok()); + + set_prompt_result(false); assert!(perms.hrtime.check().is_err()); set_prompt_result(true); assert!(perms.hrtime.check().is_err()); } + + #[test] + #[cfg(windows)] + fn test_env_windows() { + let mut perms = Permissions::allow_all(); + perms.env = UnaryPermission { + global_state: PermissionState::Prompt, + ..Permissions::new_env(&Some(svec!["HOME"]), false) + }; + + set_prompt_result(true); + assert!(perms.env.check("HOME").is_ok()); + set_prompt_result(false); + assert!(perms.env.check("HOME").is_ok()); + assert!(perms.env.check("hOmE").is_ok()); + + assert_eq!( + perms.env.revoke(Some(&"HomE".to_string())), + PermissionState::Prompt + ); + } } |