summaryrefslogtreecommitdiff
path: root/runtime/permissions.rs
diff options
context:
space:
mode:
authorYoshiya Hinosawa <stibium121@gmail.com>2022-09-28 21:46:50 +0900
committerGitHub <noreply@github.com>2022-09-28 21:46:50 +0900
commitfa9e7aab6d49f241a4eb30cc0e261f8ceb64af2f (patch)
tree04f3babcb09101e9264f021ecff53f7db266a80c /runtime/permissions.rs
parentb312279e58e51520a38e51cca317a09cdadd7cb4 (diff)
feat: add --allow-sys permission flag (#16028)
Diffstat (limited to 'runtime/permissions.rs')
-rw-r--r--runtime/permissions.rs238
1 files changed, 238 insertions, 0 deletions
diff --git a/runtime/permissions.rs b/runtime/permissions.rs
index a50295910..84ff286b4 100644
--- a/runtime/permissions.rs
+++ b/runtime/permissions.rs
@@ -302,6 +302,9 @@ impl ToString for RunDescriptor {
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
+pub struct SysDescriptor(pub String);
+
+#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct FfiDescriptor(pub PathBuf);
impl UnaryPermission<ReadDescriptor> {
@@ -928,6 +931,128 @@ impl Default for UnaryPermission<EnvDescriptor> {
}
}
+impl UnaryPermission<SysDescriptor> {
+ pub fn query(&self, kind: Option<&str>) -> PermissionState {
+ if self.global_state == PermissionState::Denied
+ && match kind {
+ None => true,
+ Some(kind) => {
+ self.denied_list.contains(&SysDescriptor(kind.to_string()))
+ }
+ }
+ {
+ PermissionState::Denied
+ } else if self.global_state == PermissionState::Granted
+ || match kind {
+ None => false,
+ Some(kind) => {
+ self.granted_list.contains(&SysDescriptor(kind.to_string()))
+ }
+ }
+ {
+ PermissionState::Granted
+ } else {
+ PermissionState::Prompt
+ }
+ }
+
+ pub fn request(&mut self, kind: Option<&str>) -> PermissionState {
+ let state = self.query(kind);
+ if state != PermissionState::Prompt {
+ return state;
+ }
+ if let Some(kind) = kind {
+ let desc = SysDescriptor(kind.to_string());
+ if permission_prompt(
+ &format!("sys access to \"{}\"", kind),
+ self.name,
+ Some("Deno.permissions.query()"),
+ ) {
+ self.granted_list.insert(desc);
+ PermissionState::Granted
+ } else {
+ self.denied_list.insert(desc);
+ self.global_state = PermissionState::Denied;
+ PermissionState::Denied
+ }
+ } else {
+ if permission_prompt(
+ "sys access",
+ self.name,
+ Some("Deno.permissions.query()"),
+ ) {
+ self.global_state = PermissionState::Granted;
+ } else {
+ self.granted_list.clear();
+ self.global_state = PermissionState::Denied;
+ }
+ self.global_state
+ }
+ }
+
+ pub fn revoke(&mut self, kind: Option<&str>) -> PermissionState {
+ if let Some(kind) = kind {
+ self.granted_list.remove(&SysDescriptor(kind.to_string()));
+ } else {
+ self.granted_list.clear();
+ }
+ if self.global_state == PermissionState::Granted {
+ self.global_state = PermissionState::Prompt;
+ }
+ self.query(kind)
+ }
+
+ pub fn check(
+ &mut self,
+ kind: &str,
+ api_name: Option<&str>,
+ ) -> Result<(), AnyError> {
+ let (result, prompted) = self.query(Some(kind)).check(
+ self.name,
+ api_name,
+ Some(&format!("\"{}\"", kind)),
+ self.prompt,
+ );
+ if prompted {
+ if result.is_ok() {
+ self.granted_list.insert(SysDescriptor(kind.to_string()));
+ } else {
+ self.denied_list.insert(SysDescriptor(kind.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, None, Some("all"), self.prompt);
+ if prompted {
+ if result.is_ok() {
+ self.global_state = PermissionState::Granted;
+ } else {
+ self.global_state = PermissionState::Denied;
+ }
+ }
+ result
+ }
+}
+
+impl Default for UnaryPermission<SysDescriptor> {
+ fn default() -> Self {
+ UnaryPermission::<SysDescriptor> {
+ name: "sys",
+ description: "system information",
+ global_state: Default::default(),
+ granted_list: Default::default(),
+ denied_list: Default::default(),
+ prompt: false,
+ }
+ }
+}
+
impl UnaryPermission<RunDescriptor> {
pub fn query(&self, cmd: Option<&str>) -> PermissionState {
if self.global_state == PermissionState::Denied
@@ -1221,6 +1346,7 @@ pub struct Permissions {
pub write: UnaryPermission<WriteDescriptor>,
pub net: UnaryPermission<NetDescriptor>,
pub env: UnaryPermission<EnvDescriptor>,
+ pub sys: UnaryPermission<SysDescriptor>,
pub run: UnaryPermission<RunDescriptor>,
pub ffi: UnaryPermission<FfiDescriptor>,
pub hrtime: UnitPermission,
@@ -1233,6 +1359,7 @@ impl Default for Permissions {
write: Permissions::new_write(&None, false).unwrap(),
net: Permissions::new_net(&None, false).unwrap(),
env: Permissions::new_env(&None, false).unwrap(),
+ sys: Permissions::new_sys(&None, false).unwrap(),
run: Permissions::new_run(&None, false).unwrap(),
ffi: Permissions::new_ffi(&None, false).unwrap(),
hrtime: Permissions::new_hrtime(false),
@@ -1248,6 +1375,7 @@ pub struct PermissionsOptions {
pub allow_ffi: Option<Vec<PathBuf>>,
pub allow_read: Option<Vec<PathBuf>>,
pub allow_run: Option<Vec<String>>,
+ pub allow_sys: Option<Vec<String>>,
pub allow_write: Option<Vec<PathBuf>>,
pub prompt: bool,
}
@@ -1321,6 +1449,31 @@ impl Permissions {
})
}
+ pub fn new_sys(
+ state: &Option<Vec<String>>,
+ prompt: bool,
+ ) -> Result<UnaryPermission<SysDescriptor>, AnyError> {
+ Ok(UnaryPermission::<SysDescriptor> {
+ global_state: global_state_from_option(state),
+ granted_list: state.as_ref().map_or_else(
+ || Ok(HashSet::new()),
+ |v| {
+ v.iter()
+ .map(|x| {
+ if x.is_empty() {
+ Err(AnyError::msg("emtpy"))
+ } else {
+ Ok(SysDescriptor(x.to_string()))
+ }
+ })
+ .collect()
+ },
+ )?,
+ prompt,
+ ..Default::default()
+ })
+ }
+
pub fn new_run(
state: &Option<Vec<String>>,
prompt: bool,
@@ -1373,6 +1526,7 @@ impl Permissions {
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)?,
+ sys: Permissions::new_sys(&opts.allow_sys, opts.prompt)?,
run: Permissions::new_run(&opts.allow_run, opts.prompt)?,
ffi: Permissions::new_ffi(&opts.allow_ffi, opts.prompt)?,
hrtime: Permissions::new_hrtime(opts.allow_hrtime),
@@ -1385,6 +1539,7 @@ impl Permissions {
write: Permissions::new_write(&Some(vec![]), false).unwrap(),
net: Permissions::new_net(&Some(vec![]), false).unwrap(),
env: Permissions::new_env(&Some(vec![]), false).unwrap(),
+ sys: Permissions::new_sys(&Some(vec![]), false).unwrap(),
run: Permissions::new_run(&Some(vec![]), false).unwrap(),
ffi: Permissions::new_ffi(&Some(vec![]), false).unwrap(),
hrtime: Permissions::new_hrtime(true),
@@ -1722,6 +1877,7 @@ pub struct ChildPermissionsArg {
ffi: ChildUnaryPermissionArg,
read: ChildUnaryPermissionArg,
run: ChildUnaryPermissionArg,
+ sys: ChildUnaryPermissionArg,
write: ChildUnaryPermissionArg,
}
@@ -1734,6 +1890,7 @@ impl ChildPermissionsArg {
ffi: ChildUnaryPermissionArg::Inherit,
read: ChildUnaryPermissionArg::Inherit,
run: ChildUnaryPermissionArg::Inherit,
+ sys: ChildUnaryPermissionArg::Inherit,
write: ChildUnaryPermissionArg::Inherit,
}
}
@@ -1746,6 +1903,7 @@ impl ChildPermissionsArg {
ffi: ChildUnaryPermissionArg::NotGranted,
read: ChildUnaryPermissionArg::NotGranted,
run: ChildUnaryPermissionArg::NotGranted,
+ sys: ChildUnaryPermissionArg::NotGranted,
write: ChildUnaryPermissionArg::NotGranted,
}
}
@@ -1822,6 +1980,11 @@ impl<'de> Deserialize<'de> for ChildPermissionsArg {
child_permissions_arg.run = arg.map_err(|e| {
de::Error::custom(format!("(deno.permissions.run) {}", e))
})?;
+ } else if key == "sys" {
+ let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
+ child_permissions_arg.sys = arg.map_err(|e| {
+ de::Error::custom(format!("(deno.permissions.sys) {}", e))
+ })?;
} else if key == "write" {
let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
child_permissions_arg.write = arg.map_err(|e| {
@@ -1872,6 +2035,35 @@ pub fn create_child_permissions(
worker_perms.env.global_state = PermissionState::Denied;
}
worker_perms.env.prompt = main_perms.env.prompt;
+ match child_permissions_arg.sys {
+ ChildUnaryPermissionArg::Inherit => {
+ worker_perms.sys = main_perms.sys.clone();
+ }
+ ChildUnaryPermissionArg::Granted => {
+ if main_perms.sys.check_all().is_err() {
+ return Err(escalation_error());
+ }
+ worker_perms.sys.global_state = PermissionState::Granted;
+ }
+ ChildUnaryPermissionArg::NotGranted => {}
+ ChildUnaryPermissionArg::GrantedList(granted_list) => {
+ worker_perms.sys.granted_list =
+ Permissions::new_sys(&Some(granted_list), false)?.granted_list;
+ if !worker_perms
+ .sys
+ .granted_list
+ .iter()
+ .all(|desc| main_perms.sys.check(&desc.0, None).is_ok())
+ {
+ return Err(escalation_error());
+ }
+ }
+ }
+ worker_perms.sys.denied_list = main_perms.sys.denied_list.clone();
+ if main_perms.sys.global_state == PermissionState::Denied {
+ worker_perms.sys.global_state = PermissionState::Denied;
+ }
+ worker_perms.sys.prompt = main_perms.sys.prompt;
match child_permissions_arg.hrtime {
ChildUnitPermissionArg::Inherit => {
worker_perms.hrtime = main_perms.hrtime.clone();
@@ -2608,6 +2800,10 @@ mod tests {
global_state: PermissionState::Prompt,
..Permissions::new_env(&Some(svec!["HOME"]), false).unwrap()
},
+ sys: UnaryPermission {
+ global_state: PermissionState::Prompt,
+ ..Permissions::new_sys(&Some(svec!["hostname"]), false).unwrap()
+ },
run: UnaryPermission {
global_state: PermissionState::Prompt,
..Permissions::new_run(&Some(svec!["deno"]), false).unwrap()
@@ -2642,6 +2838,10 @@ mod tests {
assert_eq!(perms1.env.query(Some("HOME")), PermissionState::Granted);
assert_eq!(perms2.env.query(None), PermissionState::Prompt);
assert_eq!(perms2.env.query(Some("HOME")), PermissionState::Granted);
+ assert_eq!(perms1.sys.query(None), PermissionState::Granted);
+ assert_eq!(perms1.sys.query(Some("HOME")), PermissionState::Granted);
+ assert_eq!(perms2.env.query(None), PermissionState::Prompt);
+ assert_eq!(perms2.sys.query(Some("hostname")), PermissionState::Granted);
assert_eq!(perms1.run.query(None), PermissionState::Granted);
assert_eq!(perms1.run.query(Some("deno")), PermissionState::Granted);
assert_eq!(perms2.run.query(None), PermissionState::Prompt);
@@ -2681,6 +2881,11 @@ mod tests {
prompt_value.set(false);
assert_eq!(perms.env.request(Some("HOME")), PermissionState::Granted);
prompt_value.set(true);
+ assert_eq!(perms.sys.request(Some("hostname")), PermissionState::Granted);
+ assert_eq!(perms.sys.query(None), PermissionState::Prompt);
+ prompt_value.set(false);
+ assert_eq!(perms.sys.request(Some("hostname")), PermissionState::Granted);
+ prompt_value.set(true);
assert_eq!(perms.run.request(Some("deno")), PermissionState::Granted);
assert_eq!(perms.run.query(None), PermissionState::Prompt);
prompt_value.set(false);
@@ -2728,6 +2933,10 @@ mod tests {
global_state: PermissionState::Prompt,
..Permissions::new_env(&Some(svec!["HOME"]), false).unwrap()
},
+ sys: UnaryPermission {
+ global_state: PermissionState::Prompt,
+ ..Permissions::new_sys(&Some(svec!["hostname"]), false).unwrap()
+ },
run: UnaryPermission {
global_state: PermissionState::Prompt,
..Permissions::new_run(&Some(svec!["deno"]), false).unwrap()
@@ -2754,6 +2963,7 @@ mod tests {
assert_eq!(perms.net.query(Some(&("127.0.0.1", None))), PermissionState::Prompt);
assert_eq!(perms.net.query(Some(&("127.0.0.1", Some(8000)))), PermissionState::Granted);
assert_eq!(perms.env.revoke(Some("HOME")), PermissionState::Prompt);
+ assert_eq!(perms.env.revoke(Some("hostname")), PermissionState::Prompt);
assert_eq!(perms.run.revoke(Some("deno")), PermissionState::Prompt);
assert_eq!(perms.ffi.revoke(Some(Path::new("deno"))), PermissionState::Prompt);
assert_eq!(perms.hrtime.revoke(), PermissionState::Denied);
@@ -2767,6 +2977,7 @@ mod tests {
write: Permissions::new_write(&None, true).unwrap(),
net: Permissions::new_net(&None, true).unwrap(),
env: Permissions::new_env(&None, true).unwrap(),
+ sys: Permissions::new_sys(&None, true).unwrap(),
run: Permissions::new_run(&None, true).unwrap(),
ffi: Permissions::new_ffi(&None, true).unwrap(),
hrtime: Permissions::new_hrtime(false),
@@ -2807,6 +3018,12 @@ mod tests {
assert!(perms.env.check("HOME").is_ok());
assert!(perms.env.check("PATH").is_err());
+ prompt_value.set(true);
+ assert!(perms.env.check("hostname").is_ok());
+ prompt_value.set(false);
+ assert!(perms.env.check("hostname").is_ok());
+ assert!(perms.env.check("osRelease").is_err());
+
assert!(perms.hrtime.check().is_err());
}
@@ -2817,6 +3034,7 @@ mod tests {
write: Permissions::new_write(&None, true).unwrap(),
net: Permissions::new_net(&None, true).unwrap(),
env: Permissions::new_env(&None, true).unwrap(),
+ sys: Permissions::new_sys(&None, true).unwrap(),
run: Permissions::new_run(&None, true).unwrap(),
ffi: Permissions::new_ffi(&None, true).unwrap(),
hrtime: Permissions::new_hrtime(false),
@@ -2867,6 +3085,14 @@ mod tests {
assert!(perms.env.check("PATH").is_ok());
prompt_value.set(false);
+ assert!(perms.sys.check("hostname", None).is_err());
+ prompt_value.set(true);
+ assert!(perms.sys.check("hostname", None).is_err());
+ assert!(perms.sys.check("osRelease", None).is_ok());
+ prompt_value.set(false);
+ assert!(perms.sys.check("osRelease", None).is_ok());
+
+ prompt_value.set(false);
assert!(perms.hrtime.check().is_err());
prompt_value.set(true);
assert!(perms.hrtime.check().is_err());
@@ -2902,6 +3128,7 @@ mod tests {
ffi: ChildUnaryPermissionArg::Inherit,
read: ChildUnaryPermissionArg::Inherit,
run: ChildUnaryPermissionArg::Inherit,
+ sys: ChildUnaryPermissionArg::Inherit,
write: ChildUnaryPermissionArg::Inherit,
}
);
@@ -2914,6 +3141,7 @@ mod tests {
ffi: ChildUnaryPermissionArg::NotGranted,
read: ChildUnaryPermissionArg::NotGranted,
run: ChildUnaryPermissionArg::NotGranted,
+ sys: ChildUnaryPermissionArg::NotGranted,
write: ChildUnaryPermissionArg::NotGranted,
}
);
@@ -2966,6 +3194,7 @@ mod tests {
"ffi": true,
"read": true,
"run": true,
+ "sys": true,
"write": true,
}))
.unwrap(),
@@ -2975,6 +3204,7 @@ mod tests {
ffi: ChildUnaryPermissionArg::Granted,
read: ChildUnaryPermissionArg::Granted,
run: ChildUnaryPermissionArg::Granted,
+ sys: ChildUnaryPermissionArg::Granted,
write: ChildUnaryPermissionArg::Granted,
..ChildPermissionsArg::none()
}
@@ -2986,6 +3216,7 @@ mod tests {
"ffi": false,
"read": false,
"run": false,
+ "sys": false,
"write": false,
}))
.unwrap(),
@@ -2995,6 +3226,7 @@ mod tests {
ffi: ChildUnaryPermissionArg::NotGranted,
read: ChildUnaryPermissionArg::NotGranted,
run: ChildUnaryPermissionArg::NotGranted,
+ sys: ChildUnaryPermissionArg::NotGranted,
write: ChildUnaryPermissionArg::NotGranted,
..ChildPermissionsArg::none()
}
@@ -3006,6 +3238,7 @@ mod tests {
"ffi": ["foo", "file:///bar/baz"],
"read": ["foo", "file:///bar/baz"],
"run": ["foo", "file:///bar/baz", "./qux"],
+ "sys": ["hostname", "osRelease"],
"write": ["foo", "file:///bar/baz"],
}))
.unwrap(),
@@ -3025,6 +3258,10 @@ mod tests {
"file:///bar/baz",
"./qux"
]),
+ sys: ChildUnaryPermissionArg::GrantedList(svec![
+ "hostname",
+ "osRelease"
+ ]),
write: ChildUnaryPermissionArg::GrantedList(svec![
"foo",
"file:///bar/baz"
@@ -3129,6 +3366,7 @@ mod tests {
fn test_handle_empty_value() {
assert!(Permissions::new_read(&Some(vec![PathBuf::new()]), false).is_err());
assert!(Permissions::new_env(&Some(vec![String::new()]), false).is_err());
+ assert!(Permissions::new_sys(&Some(vec![String::new()]), false).is_err());
assert!(Permissions::new_run(&Some(vec![String::new()]), false).is_err());
assert!(Permissions::new_ffi(&Some(vec![PathBuf::new()]), false).is_err());
assert!(Permissions::new_net(&Some(svec![String::new()]), false).is_err());