summaryrefslogtreecommitdiff
path: root/runtime/permissions.rs
diff options
context:
space:
mode:
authorcrowlKats <13135287+crowlKats@users.noreply.github.com>2021-04-10 00:12:00 +0200
committerGitHub <noreply@github.com>2021-04-10 00:12:00 +0200
commite7b7129b7a92b7500ded88f8f5baa25a7f59e56e (patch)
tree6716354fdd09b5b3ef37ec5769aa3ff4732fc039 /runtime/permissions.rs
parent1c7217e3909c72135020ff415e61644e20e1f62c (diff)
feat(permissions): allow run permission to take values (#9833)
This commit adds allowlist support to `--allow-run` flag. Additionally `Deno.permissions.query()` allows to query for specific programs within allowlist.
Diffstat (limited to 'runtime/permissions.rs')
-rw-r--r--runtime/permissions.rs166
1 files changed, 148 insertions, 18 deletions
diff --git a/runtime/permissions.rs b/runtime/permissions.rs
index 45b7c0bf1..dba6dc1a5 100644
--- a/runtime/permissions.rs
+++ b/runtime/permissions.rs
@@ -146,6 +146,9 @@ impl fmt::Display for NetDescriptor {
}
}
+#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
+pub struct RunDescriptor(pub String);
+
impl UnaryPermission<ReadDescriptor> {
pub fn query(&self, path: Option<&Path>) -> PermissionState {
let path = path.map(|p| resolve_from_cwd(p).unwrap());
@@ -466,13 +469,126 @@ impl UnaryPermission<NetDescriptor> {
}
}
+impl UnaryPermission<RunDescriptor> {
+ pub fn query(&self, cmd: Option<&str>) -> PermissionState {
+ if self.global_state == PermissionState::Denied
+ && match cmd {
+ None => true,
+ Some(cmd) => self.denied_list.iter().any(|cmd_| cmd_.0 == cmd),
+ }
+ {
+ PermissionState::Denied
+ } else if self.global_state == PermissionState::Granted
+ || match cmd {
+ None => false,
+ Some(cmd) => self.granted_list.iter().any(|cmd_| cmd_.0 == cmd),
+ }
+ {
+ PermissionState::Granted
+ } else {
+ PermissionState::Prompt
+ }
+ }
+
+ pub fn request(&mut self, cmd: Option<&str>) -> PermissionState {
+ if let Some(cmd) = cmd {
+ let state = self.query(Some(&cmd));
+ if state == PermissionState::Prompt {
+ if permission_prompt(&format!("run access to \"{}\"", cmd)) {
+ self.granted_list.retain(|cmd_| cmd_.0 != cmd);
+ self.granted_list.insert(RunDescriptor(cmd.to_string()));
+ PermissionState::Granted
+ } else {
+ self.denied_list.retain(|cmd_| cmd_.0 != cmd);
+ self.denied_list.insert(RunDescriptor(cmd.to_string()));
+ self.global_state = PermissionState::Denied;
+ PermissionState::Denied
+ }
+ } else {
+ state
+ }
+ } else {
+ let state = self.query(None);
+ if state == PermissionState::Prompt {
+ if permission_prompt("run 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, cmd: Option<&str>) -> PermissionState {
+ if let Some(cmd) = cmd {
+ self.granted_list.retain(|cmd_| cmd_.0 != cmd);
+ } else {
+ self.granted_list.clear();
+ if self.global_state == PermissionState::Granted {
+ self.global_state = PermissionState::Prompt;
+ }
+ }
+ self.query(cmd)
+ }
+
+ pub fn check(&self, cmd: &str) -> Result<(), AnyError> {
+ self
+ .query(Some(cmd))
+ .check(self.name, Some(&format!("\"{}\"", cmd)))
+ }
+
+ pub fn check_all(&self) -> Result<(), AnyError> {
+ self.query(None).check(self.name, Some("all"))
+ }
+}
+
+#[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<ReadDescriptor>,
pub write: UnaryPermission<WriteDescriptor>,
pub net: UnaryPermission<NetDescriptor>,
pub env: UnitPermission,
- pub run: UnitPermission,
+ pub run: UnaryPermission<RunDescriptor>,
pub plugin: UnitPermission,
pub hrtime: UnitPermission,
}
@@ -484,7 +600,7 @@ pub struct PermissionsOptions {
pub allow_net: Option<Vec<String>>,
pub allow_plugin: bool,
pub allow_read: Option<Vec<PathBuf>>,
- pub allow_run: bool,
+ pub allow_run: Option<Vec<String>>,
pub allow_write: Option<Vec<PathBuf>>,
}
@@ -536,8 +652,19 @@ impl Permissions {
boolean_permission_from_flag_bool(state, "env", "environment variables")
}
- pub fn new_run(state: bool) -> UnitPermission {
- boolean_permission_from_flag_bool(state, "run", "run a subprocess")
+ pub fn new_run(
+ state: &Option<Vec<String>>,
+ ) -> UnaryPermission<RunDescriptor> {
+ UnaryPermission::<RunDescriptor> {
+ name: "run",
+ description: "run a subprocess",
+ global_state: global_state_from_option(state),
+ granted_list: state
+ .as_ref()
+ .map(|v| v.iter().map(|x| RunDescriptor(x.clone())).collect())
+ .unwrap_or_else(HashSet::new),
+ denied_list: Default::default(),
+ }
}
pub fn new_plugin(state: bool) -> UnitPermission {
@@ -554,7 +681,7 @@ impl Permissions {
write: Permissions::new_write(&opts.allow_write),
net: Permissions::new_net(&opts.allow_net),
env: Permissions::new_env(opts.allow_env),
- run: Permissions::new_run(opts.allow_run),
+ run: Permissions::new_run(&opts.allow_run),
plugin: Permissions::new_plugin(opts.allow_plugin),
hrtime: Permissions::new_hrtime(opts.allow_hrtime),
}
@@ -566,7 +693,7 @@ impl Permissions {
write: Permissions::new_write(&Some(vec![])),
net: Permissions::new_net(&Some(vec![])),
env: Permissions::new_env(true),
- run: Permissions::new_run(true),
+ run: Permissions::new_run(&Some(vec![])),
plugin: Permissions::new_plugin(true),
hrtime: Permissions::new_hrtime(true),
}
@@ -1062,9 +1189,9 @@ mod tests {
state: PermissionState::Prompt,
..Default::default()
},
- run: UnitPermission {
- state: PermissionState::Prompt,
- ..Default::default()
+ run: UnaryPermission {
+ global_state: PermissionState::Prompt,
+ ..Permissions::new_run(&Some(svec!["deno"]))
},
plugin: UnitPermission {
state: PermissionState::Prompt,
@@ -1093,8 +1220,10 @@ mod tests {
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.run.query(), PermissionState::Granted);
- assert_eq!(perms2.run.query(), PermissionState::Prompt);
+ 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);
+ assert_eq!(perms2.run.query(Some(&"deno".to_string())), PermissionState::Granted);
assert_eq!(perms1.plugin.query(), PermissionState::Granted);
assert_eq!(perms2.plugin.query(), PermissionState::Prompt);
assert_eq!(perms1.hrtime.query(), PermissionState::Granted);
@@ -1126,10 +1255,11 @@ mod tests {
assert_eq!(perms.env.request(), PermissionState::Granted);
set_prompt_result(false);
assert_eq!(perms.env.request(), PermissionState::Granted);
- set_prompt_result(false);
- assert_eq!(perms.run.request(), PermissionState::Denied);
set_prompt_result(true);
- assert_eq!(perms.run.request(), PermissionState::Denied);
+ assert_eq!(perms.run.request(Some(&"deno".to_string())), PermissionState::Granted);
+ assert_eq!(perms.run.query(None), PermissionState::Prompt);
+ set_prompt_result(false);
+ assert_eq!(perms.run.request(Some(&"deno".to_string())), PermissionState::Granted);
set_prompt_result(true);
assert_eq!(perms.plugin.request(), PermissionState::Granted);
set_prompt_result(false);
@@ -1160,9 +1290,9 @@ mod tests {
state: PermissionState::Granted,
..Default::default()
},
- run: UnitPermission {
- state: PermissionState::Granted,
- ..Default::default()
+ run: UnaryPermission {
+ global_state: PermissionState::Prompt,
+ ..Permissions::new_run(&Some(svec!["deno"]))
},
plugin: UnitPermission {
state: PermissionState::Prompt,
@@ -1184,7 +1314,7 @@ mod tests {
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.run.revoke(), 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);
};