diff options
author | crowlKats <13135287+crowlKats@users.noreply.github.com> | 2021-03-17 22:45:12 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-17 17:45:12 -0400 |
commit | 0e70d9e59bc0e70f1921bb217ee00fc2e6facb69 (patch) | |
tree | d501399bd07855148ce817c568e7228bdfd87d87 /runtime/ops | |
parent | b3fe85163f303a1592335b23c25554dd0e39a4c4 (diff) |
refactor: clean up permission handling (#9367)
Diffstat (limited to 'runtime/ops')
-rw-r--r-- | runtime/ops/fs.rs | 105 | ||||
-rw-r--r-- | runtime/ops/fs_events.rs | 3 | ||||
-rw-r--r-- | runtime/ops/net.rs | 20 | ||||
-rw-r--r-- | runtime/ops/os.rs | 21 | ||||
-rw-r--r-- | runtime/ops/permissions.rs | 48 | ||||
-rw-r--r-- | runtime/ops/plugin.rs | 2 | ||||
-rw-r--r-- | runtime/ops/process.rs | 6 | ||||
-rw-r--r-- | runtime/ops/runtime.rs | 3 | ||||
-rw-r--r-- | runtime/ops/timers.rs | 2 | ||||
-rw-r--r-- | runtime/ops/tls.rs | 14 | ||||
-rw-r--r-- | runtime/ops/worker_host.rs | 239 |
11 files changed, 282 insertions, 181 deletions
diff --git a/runtime/ops/fs.rs b/runtime/ops/fs.rs index 8560d9f3e..c9a2f1efe 100644 --- a/runtime/ops/fs.rs +++ b/runtime/ops/fs.rs @@ -161,11 +161,11 @@ fn open_helper( let options = args.options; if options.read { - permissions.check_read(&path)?; + permissions.read.check(&path)?; } if options.write || options.append { - permissions.check_write(&path)?; + permissions.write.check(&path)?; } open_options @@ -463,7 +463,7 @@ fn op_chdir( ) -> Result<Value, AnyError> { let args: ChdirArgs = serde_json::from_value(args)?; let d = PathBuf::from(&args.directory); - state.borrow::<Permissions>().check_read(&d)?; + state.borrow::<Permissions>().read.check(&d)?; set_current_dir(&d)?; Ok(json!({})) } @@ -484,7 +484,7 @@ fn op_mkdir_sync( let args: MkdirArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); let mode = args.mode.unwrap_or(0o777) & 0o777; - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); let mut builder = std::fs::DirBuilder::new(); builder.recursive(args.recursive); @@ -508,7 +508,7 @@ async fn op_mkdir_async( { let state = state.borrow(); - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; } tokio::task::spawn_blocking(move || { @@ -543,7 +543,7 @@ fn op_chmod_sync( let path = Path::new(&args.path).to_path_buf(); let mode = args.mode & 0o777; - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; debug!("op_chmod_sync {} {:o}", path.display(), mode); #[cfg(unix)] { @@ -572,7 +572,7 @@ async fn op_chmod_async( { let state = state.borrow(); - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; } tokio::task::spawn_blocking(move || { @@ -611,7 +611,7 @@ fn op_chown_sync( ) -> Result<Value, AnyError> { let args: ChownArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; debug!( "op_chown_sync {} {:?} {:?}", path.display(), @@ -643,7 +643,7 @@ async fn op_chown_async( { let state = state.borrow(); - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; } tokio::task::spawn_blocking(move || { @@ -685,7 +685,7 @@ fn op_remove_sync( let path = PathBuf::from(&args.path); let recursive = args.recursive; - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; #[cfg(not(unix))] use std::os::windows::prelude::MetadataExt; @@ -730,7 +730,7 @@ async fn op_remove_async( { let state = state.borrow(); - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; } tokio::task::spawn_blocking(move || { @@ -786,8 +786,8 @@ fn op_copy_file_sync( let to = PathBuf::from(&args.to); let permissions = state.borrow::<Permissions>(); - permissions.check_read(&from)?; - permissions.check_write(&to)?; + permissions.read.check(&from)?; + permissions.write.check(&to)?; debug!("op_copy_file_sync {} {}", from.display(), to.display()); // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput @@ -814,8 +814,8 @@ async fn op_copy_file_async( { let state = state.borrow(); let permissions = state.borrow::<Permissions>(); - permissions.check_read(&from)?; - permissions.check_write(&to)?; + permissions.read.check(&from)?; + permissions.write.check(&to)?; } debug!("op_copy_file_async {} {}", from.display(), to.display()); @@ -908,7 +908,7 @@ fn op_stat_sync( let args: StatArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let lstat = args.lstat; - state.borrow::<Permissions>().check_read(&path)?; + state.borrow::<Permissions>().read.check(&path)?; debug!("op_stat_sync {} {}", path.display(), lstat); let metadata = if lstat { std::fs::symlink_metadata(&path)? @@ -929,7 +929,7 @@ async fn op_stat_async( { let state = state.borrow(); - state.borrow::<Permissions>().check_read(&path)?; + state.borrow::<Permissions>().read.check(&path)?; } tokio::task::spawn_blocking(move || { @@ -960,9 +960,9 @@ fn op_realpath_sync( let path = PathBuf::from(&args.path); let permissions = state.borrow::<Permissions>(); - permissions.check_read(&path)?; + permissions.read.check(&path)?; if path.is_relative() { - permissions.check_read_blind(¤t_dir()?, "CWD")?; + permissions.read.check_blind(¤t_dir()?, "CWD")?; } debug!("op_realpath_sync {}", path.display()); @@ -984,9 +984,9 @@ async fn op_realpath_async( { let state = state.borrow(); let permissions = state.borrow::<Permissions>(); - permissions.check_read(&path)?; + permissions.read.check(&path)?; if path.is_relative() { - permissions.check_read_blind(¤t_dir()?, "CWD")?; + permissions.read.check_blind(¤t_dir()?, "CWD")?; } } @@ -1016,7 +1016,7 @@ fn op_read_dir_sync( let args: ReadDirArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); - state.borrow::<Permissions>().check_read(&path)?; + state.borrow::<Permissions>().read.check(&path)?; debug!("op_read_dir_sync {}", path.display()); let entries: Vec<_> = std::fs::read_dir(path)? @@ -1048,7 +1048,7 @@ async fn op_read_dir_async( let path = PathBuf::from(&args.path); { let state = state.borrow(); - state.borrow::<Permissions>().check_read(&path)?; + state.borrow::<Permissions>().read.check(&path)?; } tokio::task::spawn_blocking(move || { debug!("op_read_dir_async {}", path.display()); @@ -1092,9 +1092,9 @@ fn op_rename_sync( let newpath = PathBuf::from(&args.newpath); let permissions = state.borrow::<Permissions>(); - permissions.check_read(&oldpath)?; - permissions.check_write(&oldpath)?; - permissions.check_write(&newpath)?; + permissions.read.check(&oldpath)?; + permissions.write.check(&oldpath)?; + permissions.write.check(&newpath)?; debug!("op_rename_sync {} {}", oldpath.display(), newpath.display()); std::fs::rename(&oldpath, &newpath)?; Ok(json!({})) @@ -1111,9 +1111,9 @@ async fn op_rename_async( { let state = state.borrow(); let permissions = state.borrow::<Permissions>(); - permissions.check_read(&oldpath)?; - permissions.check_write(&oldpath)?; - permissions.check_write(&newpath)?; + permissions.read.check(&oldpath)?; + permissions.write.check(&oldpath)?; + permissions.write.check(&newpath)?; } tokio::task::spawn_blocking(move || { debug!( @@ -1145,10 +1145,10 @@ fn op_link_sync( let newpath = PathBuf::from(&args.newpath); let permissions = state.borrow::<Permissions>(); - permissions.check_read(&oldpath)?; - permissions.check_write(&oldpath)?; - permissions.check_read(&newpath)?; - permissions.check_write(&newpath)?; + permissions.read.check(&oldpath)?; + permissions.write.check(&oldpath)?; + permissions.read.check(&newpath)?; + permissions.write.check(&newpath)?; debug!("op_link_sync {} {}", oldpath.display(), newpath.display()); std::fs::hard_link(&oldpath, &newpath)?; @@ -1167,10 +1167,10 @@ async fn op_link_async( { let state = state.borrow(); let permissions = state.borrow::<Permissions>(); - permissions.check_read(&oldpath)?; - permissions.check_write(&oldpath)?; - permissions.check_read(&newpath)?; - permissions.check_write(&newpath)?; + permissions.read.check(&oldpath)?; + permissions.write.check(&oldpath)?; + permissions.read.check(&newpath)?; + permissions.write.check(&newpath)?; } tokio::task::spawn_blocking(move || { @@ -1207,7 +1207,7 @@ fn op_symlink_sync( let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); - state.borrow::<Permissions>().check_write(&newpath)?; + state.borrow::<Permissions>().write.check(&newpath)?; debug!( "op_symlink_sync {} {}", @@ -1259,7 +1259,7 @@ async fn op_symlink_async( { let state = state.borrow(); - state.borrow::<Permissions>().check_write(&newpath)?; + state.borrow::<Permissions>().write.check(&newpath)?; } tokio::task::spawn_blocking(move || { @@ -1315,7 +1315,7 @@ fn op_read_link_sync( let args: ReadLinkArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); - state.borrow::<Permissions>().check_read(&path)?; + state.borrow::<Permissions>().read.check(&path)?; debug!("op_read_link_value {}", path.display()); let target = std::fs::read_link(&path)?.into_os_string(); @@ -1332,7 +1332,7 @@ async fn op_read_link_async( let path = PathBuf::from(&args.path); { let state = state.borrow(); - state.borrow::<Permissions>().check_read(&path)?; + state.borrow::<Permissions>().read.check(&path)?; } tokio::task::spawn_blocking(move || { debug!("op_read_link_async {}", path.display()); @@ -1411,7 +1411,7 @@ fn op_truncate_sync( let path = PathBuf::from(&args.path); let len = args.len; - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; debug!("op_truncate_sync {} {}", path.display(), len); let f = std::fs::OpenOptions::new().write(true).open(&path)?; @@ -1429,7 +1429,7 @@ async fn op_truncate_async( let len = args.len; { let state = state.borrow(); - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; } tokio::task::spawn_blocking(move || { debug!("op_truncate_async {} {}", path.display(), len); @@ -1507,7 +1507,8 @@ fn op_make_temp_dir_sync( state .borrow::<Permissions>() - .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + .write + .check(dir.clone().unwrap_or_else(temp_dir).as_path())?; // TODO(piscisaureus): use byte vector for paths, not a string. // See https://github.com/denoland/deno/issues/627. @@ -1538,7 +1539,8 @@ async fn op_make_temp_dir_async( let state = state.borrow(); state .borrow::<Permissions>() - .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + .write + .check(dir.clone().unwrap_or_else(temp_dir).as_path())?; } tokio::task::spawn_blocking(move || { // TODO(piscisaureus): use byte vector for paths, not a string. @@ -1572,7 +1574,8 @@ fn op_make_temp_file_sync( state .borrow::<Permissions>() - .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + .write + .check(dir.clone().unwrap_or_else(temp_dir).as_path())?; // TODO(piscisaureus): use byte vector for paths, not a string. // See https://github.com/denoland/deno/issues/627. @@ -1603,7 +1606,8 @@ async fn op_make_temp_file_async( let state = state.borrow(); state .borrow::<Permissions>() - .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + .write + .check(dir.clone().unwrap_or_else(temp_dir).as_path())?; } tokio::task::spawn_blocking(move || { // TODO(piscisaureus): use byte vector for paths, not a string. @@ -1718,7 +1722,7 @@ fn op_utime_sync( let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - state.borrow::<Permissions>().check_write(&path)?; + state.borrow::<Permissions>().write.check(&path)?; filetime::set_file_times(path, atime, mtime)?; Ok(json!({})) } @@ -1735,7 +1739,7 @@ async fn op_utime_async( let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - state.borrow().borrow::<Permissions>().check_write(&path)?; + state.borrow().borrow::<Permissions>().write.check(&path)?; tokio::task::spawn_blocking(move || { filetime::set_file_times(path, atime, mtime)?; @@ -1753,7 +1757,8 @@ fn op_cwd( let path = current_dir()?; state .borrow::<Permissions>() - .check_read_blind(&path, "CWD")?; + .read + .check_blind(&path, "CWD")?; let path_str = into_string(path.into_os_string())?; Ok(json!(path_str)) } diff --git a/runtime/ops/fs_events.rs b/runtime/ops/fs_events.rs index 6f6ba04bd..aafe91d71 100644 --- a/runtime/ops/fs_events.rs +++ b/runtime/ops/fs_events.rs @@ -112,7 +112,8 @@ fn op_fs_events_open( for path in &args.paths { state .borrow::<Permissions>() - .check_read(&PathBuf::from(path))?; + .read + .check(&PathBuf::from(path))?; watcher.watch(path, recursive_mode)?; } let resource = FsEventsResource { diff --git a/runtime/ops/net.rs b/runtime/ops/net.rs index 7e80bb86b..9084cac0d 100644 --- a/runtime/ops/net.rs +++ b/runtime/ops/net.rs @@ -204,7 +204,8 @@ async fn op_datagram_send( { let s = state.borrow(); s.borrow::<Permissions>() - .check_net(&(&args.hostname, Some(args.port)))?; + .net + .check(&(&args.hostname, Some(args.port)))?; } let addr = resolve_addr(&args.hostname, args.port) .await? @@ -229,7 +230,7 @@ async fn op_datagram_send( let address_path = Path::new(&args.path); { let s = state.borrow(); - s.borrow::<Permissions>().check_write(&address_path)?; + s.borrow::<Permissions>().write.check(&address_path)?; } let resource = state .borrow() @@ -269,7 +270,8 @@ async fn op_connect( let state_ = state.borrow(); state_ .borrow::<Permissions>() - .check_net(&(&args.hostname, Some(args.port)))?; + .net + .check(&(&args.hostname, Some(args.port)))?; } let addr = resolve_addr(&args.hostname, args.port) .await? @@ -306,8 +308,8 @@ async fn op_connect( super::check_unstable2(&state, "Deno.connect"); { let state_ = state.borrow(); - state_.borrow::<Permissions>().check_read(&address_path)?; - state_.borrow::<Permissions>().check_write(&address_path)?; + state_.borrow::<Permissions>().read.check(&address_path)?; + state_.borrow::<Permissions>().write.check(&address_path)?; } let path = args.path; let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?; @@ -433,7 +435,7 @@ fn op_listen( if transport == "udp" { super::check_unstable(state, "Deno.listenDatagram"); } - permissions.check_net(&(&args.hostname, Some(args.port)))?; + permissions.net.check(&(&args.hostname, Some(args.port)))?; } let addr = resolve_addr_sync(&args.hostname, args.port)? .next() @@ -471,8 +473,8 @@ fn op_listen( if transport == "unixpacket" { super::check_unstable(state, "Deno.listenDatagram"); } - permissions.check_read(&address_path)?; - permissions.check_write(&address_path)?; + permissions.read.check(&address_path)?; + permissions.write.check(&address_path)?; } let (rid, local_addr) = if transport == "unix" { net_unix::listen_unix(state, &address_path)? @@ -580,7 +582,7 @@ async fn op_dns_resolve( let socker_addr = &ns.socket_addr; let ip = socker_addr.ip().to_string(); let port = socker_addr.port(); - perm.check_net(&(ip, Some(port)))?; + perm.net.check(&(ip, Some(port)))?; } } diff --git a/runtime/ops/os.rs b/runtime/ops/os.rs index 10e0c8bc1..addab7894 100644 --- a/runtime/ops/os.rs +++ b/runtime/ops/os.rs @@ -34,7 +34,8 @@ fn op_exec_path( let current_exe = env::current_exe().unwrap(); state .borrow::<Permissions>() - .check_read_blind(¤t_exe, "exec_path")?; + .read + .check_blind(¤t_exe, "exec_path")?; // Now apply URL parser to current exe to get fully resolved path, otherwise // we might get `./` and `../` bits in `exec_path` let exe_url = Url::from_file_path(current_exe).unwrap(); @@ -54,7 +55,7 @@ fn op_set_env( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: SetEnv = serde_json::from_value(args)?; - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; let invalid_key = args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]); let invalid_value = args.value.contains('\0'); @@ -70,7 +71,7 @@ fn op_env( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; let v = env::vars().collect::<HashMap<String, String>>(); Ok(json!(v)) } @@ -86,7 +87,7 @@ fn op_get_env( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: GetEnv = serde_json::from_value(args)?; - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; if args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]) { return Err(type_error("Key contains invalid characters.")); } @@ -108,7 +109,7 @@ fn op_delete_env( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: DeleteEnv = serde_json::from_value(args)?; - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; if args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]) { return Err(type_error("Key contains invalid characters.")); } @@ -136,7 +137,7 @@ fn op_loadavg( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { super::check_unstable(state, "Deno.loadavg"); - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; match sys_info::loadavg() { Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])), Err(_) => Ok(json!([0f64, 0f64, 0f64])), @@ -149,7 +150,7 @@ fn op_hostname( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { super::check_unstable(state, "Deno.hostname"); - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string()); Ok(json!(hostname)) } @@ -160,7 +161,7 @@ fn op_os_release( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { super::check_unstable(state, "Deno.osRelease"); - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; let release = sys_info::os_release().unwrap_or_else(|_| "".to_string()); Ok(json!(release)) } @@ -171,7 +172,7 @@ fn op_system_memory_info( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { super::check_unstable(state, "Deno.systemMemoryInfo"); - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; match sys_info::mem_info() { Ok(info) => Ok(json!({ "total": info.total, @@ -192,7 +193,7 @@ fn op_system_cpu_info( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { super::check_unstable(state, "Deno.systemCpuInfo"); - state.borrow::<Permissions>().check_env()?; + state.borrow::<Permissions>().env.check()?; let cores = sys_info::cpu_num().ok(); let speed = sys_info::cpu_speed().ok(); diff --git a/runtime/ops/permissions.rs b/runtime/ops/permissions.rs index 86ad2206b..b82efd89c 100644 --- a/runtime/ops/permissions.rs +++ b/runtime/ops/permissions.rs @@ -35,19 +35,19 @@ pub fn op_query_permission( let permissions = state.borrow::<Permissions>(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { - "read" => permissions.query_read(&path.as_deref().map(Path::new)), - "write" => permissions.query_write(&path.as_deref().map(Path::new)), - "net" => permissions.query_net( - &match args.host.as_deref() { + "read" => permissions.read.query(path.as_deref().map(Path::new)), + "write" => permissions.write.query(path.as_deref().map(Path::new)), + "net" => permissions.net.query( + match args.host.as_deref() { None => None, Some(h) => Some(parse_host(h)?), } .as_ref(), ), - "env" => permissions.query_env(), - "run" => permissions.query_run(), - "plugin" => permissions.query_plugin(), - "hrtime" => permissions.query_hrtime(), + "env" => permissions.env.query(), + "run" => permissions.run.query(), + "plugin" => permissions.plugin.query(), + "hrtime" => permissions.hrtime.query(), n => { return Err(custom_error( "ReferenceError", @@ -67,19 +67,19 @@ pub fn op_revoke_permission( let permissions = state.borrow_mut::<Permissions>(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { - "read" => permissions.revoke_read(&path.as_deref().map(Path::new)), - "write" => permissions.revoke_write(&path.as_deref().map(Path::new)), - "net" => permissions.revoke_net( - &match args.host.as_deref() { + "read" => permissions.read.revoke(path.as_deref().map(Path::new)), + "write" => permissions.write.revoke(path.as_deref().map(Path::new)), + "net" => permissions.net.revoke( + match args.host.as_deref() { None => None, Some(h) => Some(parse_host(h)?), } .as_ref(), ), - "env" => permissions.revoke_env(), - "run" => permissions.revoke_run(), - "plugin" => permissions.revoke_plugin(), - "hrtime" => permissions.revoke_hrtime(), + "env" => permissions.env.revoke(), + "run" => permissions.run.revoke(), + "plugin" => permissions.plugin.revoke(), + "hrtime" => permissions.hrtime.revoke(), n => { return Err(custom_error( "ReferenceError", @@ -99,19 +99,19 @@ pub fn op_request_permission( let permissions = state.borrow_mut::<Permissions>(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { - "read" => permissions.request_read(&path.as_deref().map(Path::new)), - "write" => permissions.request_write(&path.as_deref().map(Path::new)), - "net" => permissions.request_net( - &match args.host.as_deref() { + "read" => permissions.read.request(path.as_deref().map(Path::new)), + "write" => permissions.write.request(path.as_deref().map(Path::new)), + "net" => permissions.net.request( + match args.host.as_deref() { None => None, Some(h) => Some(parse_host(h)?), } .as_ref(), ), - "env" => permissions.request_env(), - "run" => permissions.request_run(), - "plugin" => permissions.request_plugin(), - "hrtime" => permissions.request_hrtime(), + "env" => permissions.env.request(), + "run" => permissions.run.request(), + "plugin" => permissions.plugin.request(), + "hrtime" => permissions.hrtime.request(), n => { return Err(custom_error( "ReferenceError", diff --git a/runtime/ops/plugin.rs b/runtime/ops/plugin.rs index 424b1dca0..e02276756 100644 --- a/runtime/ops/plugin.rs +++ b/runtime/ops/plugin.rs @@ -46,7 +46,7 @@ pub fn op_open_plugin( super::check_unstable(state, "Deno.openPlugin"); let permissions = state.borrow::<Permissions>(); - permissions.check_plugin(&filename)?; + permissions.plugin.check()?; debug!("Loading Plugin: {:#?}", filename); let plugin_lib = Library::open(filename).map(Rc::new)?; diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index 89f323232..a60b451eb 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -88,7 +88,7 @@ fn op_run( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let run_args: RunArgs = serde_json::from_value(args)?; - state.borrow::<Permissions>().check_run()?; + state.borrow::<Permissions>().run.check()?; let args = run_args.cmd; let env = run_args.env; @@ -193,7 +193,7 @@ async fn op_run_status( { let s = state.borrow(); - s.borrow::<Permissions>().check_run()?; + s.borrow::<Permissions>().run.check()?; } let resource = state @@ -285,7 +285,7 @@ fn op_kill( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { super::check_unstable(state, "Deno.kill"); - state.borrow::<Permissions>().check_run()?; + state.borrow::<Permissions>().run.check()?; let args: KillArgs = serde_json::from_value(args)?; kill(args.pid, args.signo)?; diff --git a/runtime/ops/runtime.rs b/runtime/ops/runtime.rs index a2f377bed..420931b0c 100644 --- a/runtime/ops/runtime.rs +++ b/runtime/ops/runtime.rs @@ -32,7 +32,8 @@ fn op_main_module( let main_path = std::env::current_dir().unwrap().join(main_url.to_string()); state .borrow::<Permissions>() - .check_read_blind(&main_path, "main_module")?; + .read + .check_blind(&main_path, "main_module")?; } Ok(json!(&main)) } diff --git a/runtime/ops/timers.rs b/runtime/ops/timers.rs index 783395cad..34a3eea5f 100644 --- a/runtime/ops/timers.rs +++ b/runtime/ops/timers.rs @@ -166,7 +166,7 @@ fn op_now( // If the permission is not enabled // Round the nano result on 2 milliseconds // see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision - if op_state.borrow::<Permissions>().check_hrtime().is_err() { + if op_state.borrow::<Permissions>().hrtime.check().is_err() { subsec_nanos -= subsec_nanos % reduced_time_precision; } diff --git a/runtime/ops/tls.rs b/runtime/ops/tls.rs index 893c068c4..f35425555 100644 --- a/runtime/ops/tls.rs +++ b/runtime/ops/tls.rs @@ -110,9 +110,9 @@ async fn op_start_tls( super::check_unstable2(&state, "Deno.startTls"); let s = state.borrow(); let permissions = s.borrow::<Permissions>(); - permissions.check_net(&(&domain, Some(0)))?; + permissions.net.check(&(&domain, Some(0)))?; if let Some(path) = &args.cert_file { - permissions.check_read(Path::new(&path))?; + permissions.read.check(Path::new(&path))?; } } @@ -174,9 +174,9 @@ async fn op_connect_tls( { let s = state.borrow(); let permissions = s.borrow::<Permissions>(); - permissions.check_net(&(&args.hostname, Some(args.port)))?; + permissions.net.check(&(&args.hostname, Some(args.port)))?; if let Some(path) = &args.cert_file { - permissions.check_read(Path::new(&path))?; + permissions.read.check(Path::new(&path))?; } } let mut domain = args.hostname.as_str(); @@ -318,9 +318,9 @@ fn op_listen_tls( let key_file = args.key_file; { let permissions = state.borrow::<Permissions>(); - permissions.check_net(&(&args.hostname, Some(args.port)))?; - permissions.check_read(Path::new(&cert_file))?; - permissions.check_read(Path::new(&key_file))?; + permissions.net.check(&(&args.hostname, Some(args.port)))?; + permissions.read.check(Path::new(&cert_file))?; + permissions.read.check(Path::new(&key_file))?; } let mut config = ServerConfig::new(NoClientAuth::new()); config diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 6b375605f..df624cd44 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -1,9 +1,14 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use crate::permissions::resolve_fs_allowlist; +use crate::permissions::resolve_read_allowlist; +use crate::permissions::resolve_write_allowlist; +use crate::permissions::BooleanPermission; +use crate::permissions::NetPermission; use crate::permissions::PermissionState; use crate::permissions::Permissions; +use crate::permissions::ReadPermission; use crate::permissions::UnaryPermission; +use crate::permissions::WritePermission; use crate::web_worker::run_web_worker; use crate::web_worker::WebWorker; use crate::web_worker::WebWorkerHandle; @@ -105,49 +110,54 @@ pub fn init( ); } -fn merge_permission_state( - target: &PermissionState, +fn merge_boolean_permission( + target: &BooleanPermission, incoming: Option<PermissionState>, -) -> Result<PermissionState, AnyError> { - match target { +) -> Result<BooleanPermission, AnyError> { + let mut perm = target.clone(); + perm.state = match target.state { PermissionState::Granted => match incoming { - Some(x) => Ok(x), - None => Ok(*target), + Some(state) => state, + None => perm.state, }, _ => match incoming { - Some(x) => match x { - PermissionState::Denied => Ok(x), - _ => Err(custom_error( - "PermissionDenied", - "Can't escalate parent thread permissions", - )), + Some(state) => match state { + PermissionState::Denied => state, + _ => { + return Err(custom_error( + "PermissionDenied", + "Can't escalate parent thread permissions", + )) + } }, - None => Ok(*target), + None => perm.state, }, - } + }; + Ok(perm) } fn check_net_permission_contains( - a: &HashSet<String>, - b: &HashSet<String>, + a: &HashSet<NetPermission>, + b: &HashSet<NetPermission>, ) -> bool { b.iter().all(|x| a.contains(x)) } fn merge_net_permissions( - target: &UnaryPermission<String>, - incoming: Option<UnaryPermission<String>>, -) -> Result<UnaryPermission<String>, AnyError> { + target: &UnaryPermission<NetPermission>, + incoming: Option<UnaryPermission<NetPermission>>, +) -> Result<UnaryPermission<NetPermission>, AnyError> { if incoming.is_none() { return Ok(target.clone()); }; let new_permissions = incoming.unwrap(); match &target.global_state { - PermissionState::Granted => Ok(UnaryPermission::<String> { + PermissionState::Granted => Ok(UnaryPermission::<NetPermission> { global_state: new_permissions.global_state, granted_list: new_permissions.granted_list, denied_list: new_permissions.denied_list, + ..Permissions::new_net(&None) }), PermissionState::Prompt => match new_permissions.global_state { //Throw @@ -161,10 +171,11 @@ fn merge_net_permissions( &target.granted_list, &new_permissions.granted_list, ) { - Ok(UnaryPermission::<String> { + Ok(UnaryPermission::<NetPermission> { global_state: new_permissions.global_state, granted_list: new_permissions.granted_list, denied_list: target.denied_list.clone(), + ..Permissions::new_net(&None) }) } else { Err(custom_error( @@ -174,17 +185,19 @@ fn merge_net_permissions( } } //Copy - PermissionState::Denied => Ok(UnaryPermission::<String> { + PermissionState::Denied => Ok(UnaryPermission::<NetPermission> { global_state: new_permissions.global_state, granted_list: new_permissions.granted_list, denied_list: new_permissions.denied_list, + ..Permissions::new_net(&None) }), }, PermissionState::Denied => match new_permissions.global_state { - PermissionState::Denied => Ok(UnaryPermission::<String> { + PermissionState::Denied => Ok(UnaryPermission::<NetPermission> { global_state: new_permissions.global_state, granted_list: new_permissions.granted_list, denied_list: new_permissions.denied_list, + ..Permissions::new_net(&None) }), _ => Err(custom_error( "PermissionDenied", @@ -194,45 +207,105 @@ fn merge_net_permissions( } } -enum WorkerPermissionType { - READ, - WRITE, -} - fn check_read_permissions( - allow_list: &HashSet<PathBuf>, + allow_list: &HashSet<ReadPermission>, current_permissions: &Permissions, ) -> bool { allow_list .iter() - .all(|x| current_permissions.check_read(&x).is_ok()) + .all(|x| current_permissions.read.check(&x.0).is_ok()) } fn check_write_permissions( - allow_list: &HashSet<PathBuf>, + allow_list: &HashSet<WritePermission>, current_permissions: &Permissions, ) -> bool { allow_list .iter() - .all(|x| current_permissions.check_write(&x).is_ok()) + .all(|x| current_permissions.write.check(&x.0).is_ok()) +} + +fn merge_read_permissions( + target: &UnaryPermission<ReadPermission>, + incoming: Option<UnaryPermission<ReadPermission>>, + current_permissions: &Permissions, +) -> Result<UnaryPermission<ReadPermission>, AnyError> { + if incoming.is_none() { + return Ok(target.clone()); + }; + + let new_permissions = incoming.unwrap(); + match &target.global_state { + PermissionState::Granted => Ok(UnaryPermission::<ReadPermission> { + global_state: new_permissions.global_state, + granted_list: new_permissions.granted_list, + denied_list: new_permissions.denied_list, + ..Permissions::new_read(&None) + }), + PermissionState::Prompt => match new_permissions.global_state { + //Throw + PermissionState::Granted => Err(custom_error( + "PermissionDenied", + "Can't escalate parent thread permissions", + )), + //Merge + PermissionState::Prompt => { + if check_read_permissions( + &new_permissions.granted_list, + current_permissions, + ) { + Ok(UnaryPermission::<ReadPermission> { + global_state: new_permissions.global_state, + granted_list: new_permissions.granted_list, + denied_list: target.denied_list.clone(), + ..Permissions::new_read(&None) + }) + } else { + Err(custom_error( + "PermissionDenied", + "Can't escalate parent thread permissions", + )) + } + } + //Copy + PermissionState::Denied => Ok(UnaryPermission::<ReadPermission> { + global_state: new_permissions.global_state, + granted_list: new_permissions.granted_list, + denied_list: new_permissions.denied_list, + ..Permissions::new_read(&None) + }), + }, + PermissionState::Denied => match new_permissions.global_state { + PermissionState::Denied => Ok(UnaryPermission::<ReadPermission> { + global_state: new_permissions.global_state, + granted_list: new_permissions.granted_list, + denied_list: new_permissions.denied_list, + ..Permissions::new_read(&None) + }), + _ => Err(custom_error( + "PermissionDenied", + "Can't escalate parent thread permissions", + )), + }, + } } -fn merge_read_write_permissions( - permission_type: WorkerPermissionType, - target: &UnaryPermission<PathBuf>, - incoming: Option<UnaryPermission<PathBuf>>, +fn merge_write_permissions( + target: &UnaryPermission<WritePermission>, + incoming: Option<UnaryPermission<WritePermission>>, current_permissions: &Permissions, -) -> Result<UnaryPermission<PathBuf>, AnyError> { +) -> Result<UnaryPermission<WritePermission>, AnyError> { if incoming.is_none() { return Ok(target.clone()); }; let new_permissions = incoming.unwrap(); match &target.global_state { - PermissionState::Granted => Ok(UnaryPermission::<PathBuf> { + PermissionState::Granted => Ok(UnaryPermission::<WritePermission> { global_state: new_permissions.global_state, granted_list: new_permissions.granted_list, denied_list: new_permissions.denied_list, + ..Permissions::new_write(&None) }), PermissionState::Prompt => match new_permissions.global_state { //Throw @@ -242,20 +315,15 @@ fn merge_read_write_permissions( )), //Merge PermissionState::Prompt => { - if match permission_type { - WorkerPermissionType::READ => check_read_permissions( - &new_permissions.granted_list, - current_permissions, - ), - WorkerPermissionType::WRITE => check_write_permissions( - &new_permissions.granted_list, - current_permissions, - ), - } { - Ok(UnaryPermission::<PathBuf> { + if check_write_permissions( + &new_permissions.granted_list, + current_permissions, + ) { + Ok(UnaryPermission::<WritePermission> { global_state: new_permissions.global_state, granted_list: new_permissions.granted_list, denied_list: target.denied_list.clone(), + ..Permissions::new_write(&None) }) } else { Err(custom_error( @@ -265,17 +333,19 @@ fn merge_read_write_permissions( } } //Copy - PermissionState::Denied => Ok(UnaryPermission::<PathBuf> { + PermissionState::Denied => Ok(UnaryPermission::<WritePermission> { global_state: new_permissions.global_state, granted_list: new_permissions.granted_list, denied_list: new_permissions.denied_list, + ..Permissions::new_write(&None) }), }, PermissionState::Denied => match new_permissions.global_state { - PermissionState::Denied => Ok(UnaryPermission::<PathBuf> { + PermissionState::Denied => Ok(UnaryPermission::<WritePermission> { global_state: new_permissions.global_state, granted_list: new_permissions.granted_list, denied_list: new_permissions.denied_list, + ..Permissions::new_write(&None) }), _ => Err(custom_error( "PermissionDenied", @@ -290,11 +360,11 @@ fn create_worker_permissions( permission_args: PermissionsArg, ) -> Result<Permissions, AnyError> { Ok(Permissions { - env: merge_permission_state( + env: merge_boolean_permission( &main_thread_permissions.env, permission_args.env, )?, - hrtime: merge_permission_state( + hrtime: merge_boolean_permission( &main_thread_permissions.hrtime, permission_args.hrtime, )?, @@ -302,22 +372,20 @@ fn create_worker_permissions( &main_thread_permissions.net, permission_args.net, )?, - plugin: merge_permission_state( + plugin: merge_boolean_permission( &main_thread_permissions.plugin, permission_args.plugin, )?, - read: merge_read_write_permissions( - WorkerPermissionType::READ, + read: merge_read_permissions( &main_thread_permissions.read, permission_args.read, &main_thread_permissions, )?, - run: merge_permission_state( + run: merge_boolean_permission( &main_thread_permissions.run, permission_args.run, )?, - write: merge_read_write_permissions( - WorkerPermissionType::WRITE, + write: merge_write_permissions( &main_thread_permissions.write, permission_args.write, &main_thread_permissions, @@ -331,16 +399,16 @@ struct PermissionsArg { env: Option<PermissionState>, #[serde(default, deserialize_with = "as_permission_state")] hrtime: Option<PermissionState>, - #[serde(default, deserialize_with = "as_unary_string_permission")] - net: Option<UnaryPermission<String>>, + #[serde(default, deserialize_with = "as_unary_net_permission")] + net: Option<UnaryPermission<NetPermission>>, #[serde(default, deserialize_with = "as_permission_state")] plugin: Option<PermissionState>, - #[serde(default, deserialize_with = "as_unary_path_permission")] - read: Option<UnaryPermission<PathBuf>>, + #[serde(default, deserialize_with = "as_unary_read_permission")] + read: Option<UnaryPermission<ReadPermission>>, #[serde(default, deserialize_with = "as_permission_state")] run: Option<PermissionState>, - #[serde(default, deserialize_with = "as_unary_path_permission")] - write: Option<UnaryPermission<PathBuf>>, + #[serde(default, deserialize_with = "as_unary_write_permission")] + write: Option<UnaryPermission<WritePermission>>, } fn as_permission_state<'de, D>( @@ -402,27 +470,50 @@ impl<'de> de::Visitor<'de> for ParseBooleanOrStringVec { } } -fn as_unary_string_permission<'de, D>( +fn as_unary_net_permission<'de, D>( deserializer: D, -) -> Result<Option<UnaryPermission<String>>, D::Error> +) -> Result<Option<UnaryPermission<NetPermission>>, D::Error> where D: Deserializer<'de>, { let value: UnaryPermissionBase = deserializer.deserialize_any(ParseBooleanOrStringVec)?; - let allowed: HashSet<String> = value.paths.into_iter().collect(); + let allowed: HashSet<NetPermission> = value + .paths + .into_iter() + .map(NetPermission::from_string) + .collect(); - Ok(Some(UnaryPermission::<String> { + Ok(Some(UnaryPermission::<NetPermission> { global_state: value.global_state, granted_list: allowed, ..Default::default() })) } -fn as_unary_path_permission<'de, D>( +fn as_unary_read_permission<'de, D>( + deserializer: D, +) -> Result<Option<UnaryPermission<ReadPermission>>, D::Error> +where + D: Deserializer<'de>, +{ + let value: UnaryPermissionBase = + deserializer.deserialize_any(ParseBooleanOrStringVec)?; + + let paths: Vec<PathBuf> = + value.paths.into_iter().map(PathBuf::from).collect(); + + Ok(Some(UnaryPermission::<ReadPermission> { + global_state: value.global_state, + granted_list: resolve_read_allowlist(&Some(paths)), + ..Default::default() + })) +} + +fn as_unary_write_permission<'de, D>( deserializer: D, -) -> Result<Option<UnaryPermission<PathBuf>>, D::Error> +) -> Result<Option<UnaryPermission<WritePermission>>, D::Error> where D: Deserializer<'de>, { @@ -432,9 +523,9 @@ where let paths: Vec<PathBuf> = value.paths.into_iter().map(PathBuf::from).collect(); - Ok(Some(UnaryPermission::<PathBuf> { + Ok(Some(UnaryPermission::<WritePermission> { global_state: value.global_state, - granted_list: resolve_fs_allowlist(&Some(paths)), + granted_list: resolve_write_allowlist(&Some(paths)), ..Default::default() })) } |