1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 07:14:47 -05:00

refactor: clean up permission handling (#9367)

This commit is contained in:
crowlKats 2021-03-17 22:45:12 +01:00 committed by GitHub
parent b3fe85163f
commit 0e70d9e59b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 969 additions and 894 deletions

View file

@ -1,4 +1,4 @@
[WILDCARD]error: Uncaught PermissionDenied: read access to "non-existent", run again with the --allow-read flag [WILDCARD]error: Uncaught PermissionDenied: Requires read access to "non-existent", run again with the --allow-read flag
Deno.readFileSync("non-existent"); Deno.readFileSync("non-existent");
^ ^
at [WILDCARD] at [WILDCARD]

View file

@ -1,2 +1,2 @@
[WILDCARD]error: Uncaught (in promise) PermissionDenied: read access to "[WILDCARD]001_hello.js", run again with the --allow-read flag [WILDCARD]error: Uncaught (in promise) PermissionDenied: Requires read access to "[WILDCARD]001_hello.js", run again with the --allow-read flag
[WILDCARD] [WILDCARD]

View file

@ -1,4 +1,4 @@
error: Uncaught (in promise) TypeError: network access to "localhost:4545", run again with the --allow-net flag error: Uncaught (in promise) TypeError: Requires net access to "localhost:4545", run again with the --allow-net flag
await import("http://localhost:4545/cli/tests/subdir/mod4.js"); await import("http://localhost:4545/cli/tests/subdir/mod4.js");
^ ^
at async file:///[WILDCARD]/error_015_dynamic_import_permissions.js:2:3 at async file:///[WILDCARD]/error_015_dynamic_import_permissions.js:2:3

View file

@ -1,3 +1,3 @@
[WILDCARD] [WILDCARD]
error: Uncaught (in worker "") read access to "[WILDCARD]worker_types.ts", run again with the --allow-read flag error: Uncaught (in worker "") Requires read access to "[WILDCARD]worker_types.ts", run again with the --allow-read flag
[WILDCARD] [WILDCARD]

View file

@ -1,3 +1,3 @@
[WILDCARD] [WILDCARD]
error: Uncaught (in worker "") network access to "localhost:4545", run again with the --allow-net flag error: Uncaught (in worker "") Requires net access to "localhost:4545", run again with the --allow-net flag
[WILDCARD] [WILDCARD]

View file

@ -5520,7 +5520,7 @@ console.log("finish");
assert_eq!(util::strip_ansi_codes(&stdout_str), "0.147205063401058\n"); assert_eq!(util::strip_ansi_codes(&stdout_str), "0.147205063401058\n");
let stderr_str = String::from_utf8(output.stderr).unwrap(); let stderr_str = String::from_utf8(output.stderr).unwrap();
assert!(util::strip_ansi_codes(&stderr_str) assert!(util::strip_ansi_codes(&stderr_str)
.contains("PermissionDenied: write access")); .contains("PermissionDenied: Requires write access"));
} }
#[test] #[test]
@ -5784,7 +5784,7 @@ console.log("finish");
let out = String::from_utf8_lossy(&output.stdout); let out = String::from_utf8_lossy(&output.stdout);
assert!(!output.status.success()); assert!(!output.status.success());
assert!(err.starts_with("Check file")); assert!(err.starts_with("Check file"));
assert!(err.contains(r#"error: Uncaught (in promise) PermissionDenied: network access to "127.0.0.1:4553""#)); assert!(err.contains(r#"error: Uncaught (in promise) PermissionDenied: Requires net access to "127.0.0.1:4553""#));
assert!(out.is_empty()); assert!(out.is_empty());
} }
@ -5806,7 +5806,7 @@ console.log("finish");
let out = String::from_utf8_lossy(&output.stdout); let out = String::from_utf8_lossy(&output.stdout);
assert!(!output.status.success()); assert!(!output.status.success());
assert!(err.starts_with("Check file")); assert!(err.starts_with("Check file"));
assert!(err.contains(r#"error: Uncaught (in promise) PermissionDenied: network access to "127.0.0.1:4553""#)); assert!(err.contains(r#"error: Uncaught (in promise) PermissionDenied: Requires net access to "127.0.0.1:4553""#));
assert!(out.is_empty()); assert!(out.is_empty());
} }

View file

@ -44,7 +44,7 @@ unitTest({ perms: { read: false } }, function dirCwdPermError(): void {
Deno.cwd(); Deno.cwd();
}, },
Deno.errors.PermissionDenied, Deno.errors.PermissionDenied,
"read access to <CWD>, run again with the --allow-read flag", "Requires read access to <CWD>, run again with the --allow-read flag",
); );
}); });

View file

@ -158,7 +158,7 @@ unitTest({ perms: { read: false } }, function execPathPerm(): void {
Deno.execPath(); Deno.execPath();
}, },
Deno.errors.PermissionDenied, Deno.errors.PermissionDenied,
"read access to <exec_path>, run again with the --allow-read flag", "Requires read access to <exec_path>, run again with the --allow-read flag",
); );
}); });

View file

@ -161,11 +161,11 @@ fn open_helper(
let options = args.options; let options = args.options;
if options.read { if options.read {
permissions.check_read(&path)?; permissions.read.check(&path)?;
} }
if options.write || options.append { if options.write || options.append {
permissions.check_write(&path)?; permissions.write.check(&path)?;
} }
open_options open_options
@ -463,7 +463,7 @@ fn op_chdir(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: ChdirArgs = serde_json::from_value(args)?; let args: ChdirArgs = serde_json::from_value(args)?;
let d = PathBuf::from(&args.directory); let d = PathBuf::from(&args.directory);
state.borrow::<Permissions>().check_read(&d)?; state.borrow::<Permissions>().read.check(&d)?;
set_current_dir(&d)?; set_current_dir(&d)?;
Ok(json!({})) Ok(json!({}))
} }
@ -484,7 +484,7 @@ fn op_mkdir_sync(
let args: MkdirArgs = serde_json::from_value(args)?; let args: MkdirArgs = serde_json::from_value(args)?;
let path = Path::new(&args.path).to_path_buf(); let path = Path::new(&args.path).to_path_buf();
let mode = args.mode.unwrap_or(0o777) & 0o777; 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); debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive);
let mut builder = std::fs::DirBuilder::new(); let mut builder = std::fs::DirBuilder::new();
builder.recursive(args.recursive); builder.recursive(args.recursive);
@ -508,7 +508,7 @@ async fn op_mkdir_async(
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_write(&path)?; state.borrow::<Permissions>().write.check(&path)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -543,7 +543,7 @@ fn op_chmod_sync(
let path = Path::new(&args.path).to_path_buf(); let path = Path::new(&args.path).to_path_buf();
let mode = args.mode & 0o777; 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); debug!("op_chmod_sync {} {:o}", path.display(), mode);
#[cfg(unix)] #[cfg(unix)]
{ {
@ -572,7 +572,7 @@ async fn op_chmod_async(
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_write(&path)?; state.borrow::<Permissions>().write.check(&path)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -611,7 +611,7 @@ fn op_chown_sync(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: ChownArgs = serde_json::from_value(args)?; let args: ChownArgs = serde_json::from_value(args)?;
let path = Path::new(&args.path).to_path_buf(); let path = Path::new(&args.path).to_path_buf();
state.borrow::<Permissions>().check_write(&path)?; state.borrow::<Permissions>().write.check(&path)?;
debug!( debug!(
"op_chown_sync {} {:?} {:?}", "op_chown_sync {} {:?} {:?}",
path.display(), path.display(),
@ -643,7 +643,7 @@ async fn op_chown_async(
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_write(&path)?; state.borrow::<Permissions>().write.check(&path)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -685,7 +685,7 @@ fn op_remove_sync(
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let recursive = args.recursive; let recursive = args.recursive;
state.borrow::<Permissions>().check_write(&path)?; state.borrow::<Permissions>().write.check(&path)?;
#[cfg(not(unix))] #[cfg(not(unix))]
use std::os::windows::prelude::MetadataExt; use std::os::windows::prelude::MetadataExt;
@ -730,7 +730,7 @@ async fn op_remove_async(
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_write(&path)?; state.borrow::<Permissions>().write.check(&path)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -786,8 +786,8 @@ fn op_copy_file_sync(
let to = PathBuf::from(&args.to); let to = PathBuf::from(&args.to);
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_read(&from)?; permissions.read.check(&from)?;
permissions.check_write(&to)?; permissions.write.check(&to)?;
debug!("op_copy_file_sync {} {}", from.display(), to.display()); debug!("op_copy_file_sync {} {}", from.display(), to.display());
// On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput // 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 state = state.borrow();
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_read(&from)?; permissions.read.check(&from)?;
permissions.check_write(&to)?; permissions.write.check(&to)?;
} }
debug!("op_copy_file_async {} {}", from.display(), to.display()); 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 args: StatArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let lstat = args.lstat; let lstat = args.lstat;
state.borrow::<Permissions>().check_read(&path)?; state.borrow::<Permissions>().read.check(&path)?;
debug!("op_stat_sync {} {}", path.display(), lstat); debug!("op_stat_sync {} {}", path.display(), lstat);
let metadata = if lstat { let metadata = if lstat {
std::fs::symlink_metadata(&path)? std::fs::symlink_metadata(&path)?
@ -929,7 +929,7 @@ async fn op_stat_async(
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_read(&path)?; state.borrow::<Permissions>().read.check(&path)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -960,9 +960,9 @@ fn op_realpath_sync(
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_read(&path)?; permissions.read.check(&path)?;
if path.is_relative() { if path.is_relative() {
permissions.check_read_blind(&current_dir()?, "CWD")?; permissions.read.check_blind(&current_dir()?, "CWD")?;
} }
debug!("op_realpath_sync {}", path.display()); debug!("op_realpath_sync {}", path.display());
@ -984,9 +984,9 @@ async fn op_realpath_async(
{ {
let state = state.borrow(); let state = state.borrow();
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_read(&path)?; permissions.read.check(&path)?;
if path.is_relative() { if path.is_relative() {
permissions.check_read_blind(&current_dir()?, "CWD")?; permissions.read.check_blind(&current_dir()?, "CWD")?;
} }
} }
@ -1016,7 +1016,7 @@ fn op_read_dir_sync(
let args: ReadDirArgs = serde_json::from_value(args)?; let args: ReadDirArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); 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()); debug!("op_read_dir_sync {}", path.display());
let entries: Vec<_> = std::fs::read_dir(path)? 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 path = PathBuf::from(&args.path);
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_read(&path)?; state.borrow::<Permissions>().read.check(&path)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
debug!("op_read_dir_async {}", path.display()); debug!("op_read_dir_async {}", path.display());
@ -1092,9 +1092,9 @@ fn op_rename_sync(
let newpath = PathBuf::from(&args.newpath); let newpath = PathBuf::from(&args.newpath);
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_read(&oldpath)?; permissions.read.check(&oldpath)?;
permissions.check_write(&oldpath)?; permissions.write.check(&oldpath)?;
permissions.check_write(&newpath)?; permissions.write.check(&newpath)?;
debug!("op_rename_sync {} {}", oldpath.display(), newpath.display()); debug!("op_rename_sync {} {}", oldpath.display(), newpath.display());
std::fs::rename(&oldpath, &newpath)?; std::fs::rename(&oldpath, &newpath)?;
Ok(json!({})) Ok(json!({}))
@ -1111,9 +1111,9 @@ async fn op_rename_async(
{ {
let state = state.borrow(); let state = state.borrow();
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_read(&oldpath)?; permissions.read.check(&oldpath)?;
permissions.check_write(&oldpath)?; permissions.write.check(&oldpath)?;
permissions.check_write(&newpath)?; permissions.write.check(&newpath)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
debug!( debug!(
@ -1145,10 +1145,10 @@ fn op_link_sync(
let newpath = PathBuf::from(&args.newpath); let newpath = PathBuf::from(&args.newpath);
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_read(&oldpath)?; permissions.read.check(&oldpath)?;
permissions.check_write(&oldpath)?; permissions.write.check(&oldpath)?;
permissions.check_read(&newpath)?; permissions.read.check(&newpath)?;
permissions.check_write(&newpath)?; permissions.write.check(&newpath)?;
debug!("op_link_sync {} {}", oldpath.display(), newpath.display()); debug!("op_link_sync {} {}", oldpath.display(), newpath.display());
std::fs::hard_link(&oldpath, &newpath)?; std::fs::hard_link(&oldpath, &newpath)?;
@ -1167,10 +1167,10 @@ async fn op_link_async(
{ {
let state = state.borrow(); let state = state.borrow();
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_read(&oldpath)?; permissions.read.check(&oldpath)?;
permissions.check_write(&oldpath)?; permissions.write.check(&oldpath)?;
permissions.check_read(&newpath)?; permissions.read.check(&newpath)?;
permissions.check_write(&newpath)?; permissions.write.check(&newpath)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -1207,7 +1207,7 @@ fn op_symlink_sync(
let oldpath = PathBuf::from(&args.oldpath); let oldpath = PathBuf::from(&args.oldpath);
let newpath = PathBuf::from(&args.newpath); let newpath = PathBuf::from(&args.newpath);
state.borrow::<Permissions>().check_write(&newpath)?; state.borrow::<Permissions>().write.check(&newpath)?;
debug!( debug!(
"op_symlink_sync {} {}", "op_symlink_sync {} {}",
@ -1259,7 +1259,7 @@ async fn op_symlink_async(
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_write(&newpath)?; state.borrow::<Permissions>().write.check(&newpath)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -1315,7 +1315,7 @@ fn op_read_link_sync(
let args: ReadLinkArgs = serde_json::from_value(args)?; let args: ReadLinkArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); 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()); debug!("op_read_link_value {}", path.display());
let target = std::fs::read_link(&path)?.into_os_string(); 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 path = PathBuf::from(&args.path);
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_read(&path)?; state.borrow::<Permissions>().read.check(&path)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
debug!("op_read_link_async {}", path.display()); debug!("op_read_link_async {}", path.display());
@ -1411,7 +1411,7 @@ fn op_truncate_sync(
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let len = args.len; let len = args.len;
state.borrow::<Permissions>().check_write(&path)?; state.borrow::<Permissions>().write.check(&path)?;
debug!("op_truncate_sync {} {}", path.display(), len); debug!("op_truncate_sync {} {}", path.display(), len);
let f = std::fs::OpenOptions::new().write(true).open(&path)?; let f = std::fs::OpenOptions::new().write(true).open(&path)?;
@ -1429,7 +1429,7 @@ async fn op_truncate_async(
let len = args.len; let len = args.len;
{ {
let state = state.borrow(); let state = state.borrow();
state.borrow::<Permissions>().check_write(&path)?; state.borrow::<Permissions>().write.check(&path)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
debug!("op_truncate_async {} {}", path.display(), len); debug!("op_truncate_async {} {}", path.display(), len);
@ -1507,7 +1507,8 @@ fn op_make_temp_dir_sync(
state state
.borrow::<Permissions>() .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. // TODO(piscisaureus): use byte vector for paths, not a string.
// See https://github.com/denoland/deno/issues/627. // See https://github.com/denoland/deno/issues/627.
@ -1538,7 +1539,8 @@ async fn op_make_temp_dir_async(
let state = state.borrow(); let state = state.borrow();
state state
.borrow::<Permissions>() .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 || { tokio::task::spawn_blocking(move || {
// TODO(piscisaureus): use byte vector for paths, not a string. // TODO(piscisaureus): use byte vector for paths, not a string.
@ -1572,7 +1574,8 @@ fn op_make_temp_file_sync(
state state
.borrow::<Permissions>() .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. // TODO(piscisaureus): use byte vector for paths, not a string.
// See https://github.com/denoland/deno/issues/627. // See https://github.com/denoland/deno/issues/627.
@ -1603,7 +1606,8 @@ async fn op_make_temp_file_async(
let state = state.borrow(); let state = state.borrow();
state state
.borrow::<Permissions>() .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 || { tokio::task::spawn_blocking(move || {
// TODO(piscisaureus): use byte vector for paths, not a string. // 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 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); 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)?; filetime::set_file_times(path, atime, mtime)?;
Ok(json!({})) 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 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); 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 || { tokio::task::spawn_blocking(move || {
filetime::set_file_times(path, atime, mtime)?; filetime::set_file_times(path, atime, mtime)?;
@ -1753,7 +1757,8 @@ fn op_cwd(
let path = current_dir()?; let path = current_dir()?;
state state
.borrow::<Permissions>() .borrow::<Permissions>()
.check_read_blind(&path, "CWD")?; .read
.check_blind(&path, "CWD")?;
let path_str = into_string(path.into_os_string())?; let path_str = into_string(path.into_os_string())?;
Ok(json!(path_str)) Ok(json!(path_str))
} }

View file

@ -112,7 +112,8 @@ fn op_fs_events_open(
for path in &args.paths { for path in &args.paths {
state state
.borrow::<Permissions>() .borrow::<Permissions>()
.check_read(&PathBuf::from(path))?; .read
.check(&PathBuf::from(path))?;
watcher.watch(path, recursive_mode)?; watcher.watch(path, recursive_mode)?;
} }
let resource = FsEventsResource { let resource = FsEventsResource {

View file

@ -204,7 +204,8 @@ async fn op_datagram_send(
{ {
let s = state.borrow(); let s = state.borrow();
s.borrow::<Permissions>() 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) let addr = resolve_addr(&args.hostname, args.port)
.await? .await?
@ -229,7 +230,7 @@ async fn op_datagram_send(
let address_path = Path::new(&args.path); let address_path = Path::new(&args.path);
{ {
let s = state.borrow(); let s = state.borrow();
s.borrow::<Permissions>().check_write(&address_path)?; s.borrow::<Permissions>().write.check(&address_path)?;
} }
let resource = state let resource = state
.borrow() .borrow()
@ -269,7 +270,8 @@ async fn op_connect(
let state_ = state.borrow(); let state_ = state.borrow();
state_ state_
.borrow::<Permissions>() .borrow::<Permissions>()
.check_net(&(&args.hostname, Some(args.port)))?; .net
.check(&(&args.hostname, Some(args.port)))?;
} }
let addr = resolve_addr(&args.hostname, args.port) let addr = resolve_addr(&args.hostname, args.port)
.await? .await?
@ -306,8 +308,8 @@ async fn op_connect(
super::check_unstable2(&state, "Deno.connect"); super::check_unstable2(&state, "Deno.connect");
{ {
let state_ = state.borrow(); let state_ = state.borrow();
state_.borrow::<Permissions>().check_read(&address_path)?; state_.borrow::<Permissions>().read.check(&address_path)?;
state_.borrow::<Permissions>().check_write(&address_path)?; state_.borrow::<Permissions>().write.check(&address_path)?;
} }
let path = args.path; let path = args.path;
let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?; let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?;
@ -433,7 +435,7 @@ fn op_listen(
if transport == "udp" { if transport == "udp" {
super::check_unstable(state, "Deno.listenDatagram"); 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)? let addr = resolve_addr_sync(&args.hostname, args.port)?
.next() .next()
@ -471,8 +473,8 @@ fn op_listen(
if transport == "unixpacket" { if transport == "unixpacket" {
super::check_unstable(state, "Deno.listenDatagram"); super::check_unstable(state, "Deno.listenDatagram");
} }
permissions.check_read(&address_path)?; permissions.read.check(&address_path)?;
permissions.check_write(&address_path)?; permissions.write.check(&address_path)?;
} }
let (rid, local_addr) = if transport == "unix" { let (rid, local_addr) = if transport == "unix" {
net_unix::listen_unix(state, &address_path)? net_unix::listen_unix(state, &address_path)?
@ -580,7 +582,7 @@ async fn op_dns_resolve(
let socker_addr = &ns.socket_addr; let socker_addr = &ns.socket_addr;
let ip = socker_addr.ip().to_string(); let ip = socker_addr.ip().to_string();
let port = socker_addr.port(); let port = socker_addr.port();
perm.check_net(&(ip, Some(port)))?; perm.net.check(&(ip, Some(port)))?;
} }
} }

View file

@ -34,7 +34,8 @@ fn op_exec_path(
let current_exe = env::current_exe().unwrap(); let current_exe = env::current_exe().unwrap();
state state
.borrow::<Permissions>() .borrow::<Permissions>()
.check_read_blind(&current_exe, "exec_path")?; .read
.check_blind(&current_exe, "exec_path")?;
// Now apply URL parser to current exe to get fully resolved path, otherwise // Now apply URL parser to current exe to get fully resolved path, otherwise
// we might get `./` and `../` bits in `exec_path` // we might get `./` and `../` bits in `exec_path`
let exe_url = Url::from_file_path(current_exe).unwrap(); let exe_url = Url::from_file_path(current_exe).unwrap();
@ -54,7 +55,7 @@ fn op_set_env(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: SetEnv = serde_json::from_value(args)?; let args: SetEnv = serde_json::from_value(args)?;
state.borrow::<Permissions>().check_env()?; state.borrow::<Permissions>().env.check()?;
let invalid_key = let invalid_key =
args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]); args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]);
let invalid_value = args.value.contains('\0'); let invalid_value = args.value.contains('\0');
@ -70,7 +71,7 @@ fn op_env(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
state.borrow::<Permissions>().check_env()?; state.borrow::<Permissions>().env.check()?;
let v = env::vars().collect::<HashMap<String, String>>(); let v = env::vars().collect::<HashMap<String, String>>();
Ok(json!(v)) Ok(json!(v))
} }
@ -86,7 +87,7 @@ fn op_get_env(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: GetEnv = serde_json::from_value(args)?; 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]) { if args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]) {
return Err(type_error("Key contains invalid characters.")); return Err(type_error("Key contains invalid characters."));
} }
@ -108,7 +109,7 @@ fn op_delete_env(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: DeleteEnv = serde_json::from_value(args)?; 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]) { if args.key.is_empty() || args.key.contains(&['=', '\0'] as &[char]) {
return Err(type_error("Key contains invalid characters.")); return Err(type_error("Key contains invalid characters."));
} }
@ -136,7 +137,7 @@ fn op_loadavg(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
super::check_unstable(state, "Deno.loadavg"); super::check_unstable(state, "Deno.loadavg");
state.borrow::<Permissions>().check_env()?; state.borrow::<Permissions>().env.check()?;
match sys_info::loadavg() { match sys_info::loadavg() {
Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])), Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])),
Err(_) => Ok(json!([0f64, 0f64, 0f64])), Err(_) => Ok(json!([0f64, 0f64, 0f64])),
@ -149,7 +150,7 @@ fn op_hostname(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
super::check_unstable(state, "Deno.hostname"); 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()); let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string());
Ok(json!(hostname)) Ok(json!(hostname))
} }
@ -160,7 +161,7 @@ fn op_os_release(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
super::check_unstable(state, "Deno.osRelease"); 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()); let release = sys_info::os_release().unwrap_or_else(|_| "".to_string());
Ok(json!(release)) Ok(json!(release))
} }
@ -171,7 +172,7 @@ fn op_system_memory_info(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
super::check_unstable(state, "Deno.systemMemoryInfo"); super::check_unstable(state, "Deno.systemMemoryInfo");
state.borrow::<Permissions>().check_env()?; state.borrow::<Permissions>().env.check()?;
match sys_info::mem_info() { match sys_info::mem_info() {
Ok(info) => Ok(json!({ Ok(info) => Ok(json!({
"total": info.total, "total": info.total,
@ -192,7 +193,7 @@ fn op_system_cpu_info(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
super::check_unstable(state, "Deno.systemCpuInfo"); super::check_unstable(state, "Deno.systemCpuInfo");
state.borrow::<Permissions>().check_env()?; state.borrow::<Permissions>().env.check()?;
let cores = sys_info::cpu_num().ok(); let cores = sys_info::cpu_num().ok();
let speed = sys_info::cpu_speed().ok(); let speed = sys_info::cpu_speed().ok();

View file

@ -35,19 +35,19 @@ pub fn op_query_permission(
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.query_read(&path.as_deref().map(Path::new)), "read" => permissions.read.query(path.as_deref().map(Path::new)),
"write" => permissions.query_write(&path.as_deref().map(Path::new)), "write" => permissions.write.query(path.as_deref().map(Path::new)),
"net" => permissions.query_net( "net" => permissions.net.query(
&match args.host.as_deref() { match args.host.as_deref() {
None => None, None => None,
Some(h) => Some(parse_host(h)?), Some(h) => Some(parse_host(h)?),
} }
.as_ref(), .as_ref(),
), ),
"env" => permissions.query_env(), "env" => permissions.env.query(),
"run" => permissions.query_run(), "run" => permissions.run.query(),
"plugin" => permissions.query_plugin(), "plugin" => permissions.plugin.query(),
"hrtime" => permissions.query_hrtime(), "hrtime" => permissions.hrtime.query(),
n => { n => {
return Err(custom_error( return Err(custom_error(
"ReferenceError", "ReferenceError",
@ -67,19 +67,19 @@ pub fn op_revoke_permission(
let permissions = state.borrow_mut::<Permissions>(); let permissions = state.borrow_mut::<Permissions>();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.revoke_read(&path.as_deref().map(Path::new)), "read" => permissions.read.revoke(path.as_deref().map(Path::new)),
"write" => permissions.revoke_write(&path.as_deref().map(Path::new)), "write" => permissions.write.revoke(path.as_deref().map(Path::new)),
"net" => permissions.revoke_net( "net" => permissions.net.revoke(
&match args.host.as_deref() { match args.host.as_deref() {
None => None, None => None,
Some(h) => Some(parse_host(h)?), Some(h) => Some(parse_host(h)?),
} }
.as_ref(), .as_ref(),
), ),
"env" => permissions.revoke_env(), "env" => permissions.env.revoke(),
"run" => permissions.revoke_run(), "run" => permissions.run.revoke(),
"plugin" => permissions.revoke_plugin(), "plugin" => permissions.plugin.revoke(),
"hrtime" => permissions.revoke_hrtime(), "hrtime" => permissions.hrtime.revoke(),
n => { n => {
return Err(custom_error( return Err(custom_error(
"ReferenceError", "ReferenceError",
@ -99,19 +99,19 @@ pub fn op_request_permission(
let permissions = state.borrow_mut::<Permissions>(); let permissions = state.borrow_mut::<Permissions>();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.request_read(&path.as_deref().map(Path::new)), "read" => permissions.read.request(path.as_deref().map(Path::new)),
"write" => permissions.request_write(&path.as_deref().map(Path::new)), "write" => permissions.write.request(path.as_deref().map(Path::new)),
"net" => permissions.request_net( "net" => permissions.net.request(
&match args.host.as_deref() { match args.host.as_deref() {
None => None, None => None,
Some(h) => Some(parse_host(h)?), Some(h) => Some(parse_host(h)?),
} }
.as_ref(), .as_ref(),
), ),
"env" => permissions.request_env(), "env" => permissions.env.request(),
"run" => permissions.request_run(), "run" => permissions.run.request(),
"plugin" => permissions.request_plugin(), "plugin" => permissions.plugin.request(),
"hrtime" => permissions.request_hrtime(), "hrtime" => permissions.hrtime.request(),
n => { n => {
return Err(custom_error( return Err(custom_error(
"ReferenceError", "ReferenceError",

View file

@ -46,7 +46,7 @@ pub fn op_open_plugin(
super::check_unstable(state, "Deno.openPlugin"); super::check_unstable(state, "Deno.openPlugin");
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_plugin(&filename)?; permissions.plugin.check()?;
debug!("Loading Plugin: {:#?}", filename); debug!("Loading Plugin: {:#?}", filename);
let plugin_lib = Library::open(filename).map(Rc::new)?; let plugin_lib = Library::open(filename).map(Rc::new)?;

View file

@ -88,7 +88,7 @@ fn op_run(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let run_args: RunArgs = serde_json::from_value(args)?; 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 args = run_args.cmd;
let env = run_args.env; let env = run_args.env;
@ -193,7 +193,7 @@ async fn op_run_status(
{ {
let s = state.borrow(); let s = state.borrow();
s.borrow::<Permissions>().check_run()?; s.borrow::<Permissions>().run.check()?;
} }
let resource = state let resource = state
@ -285,7 +285,7 @@ fn op_kill(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
super::check_unstable(state, "Deno.kill"); super::check_unstable(state, "Deno.kill");
state.borrow::<Permissions>().check_run()?; state.borrow::<Permissions>().run.check()?;
let args: KillArgs = serde_json::from_value(args)?; let args: KillArgs = serde_json::from_value(args)?;
kill(args.pid, args.signo)?; kill(args.pid, args.signo)?;

View file

@ -32,7 +32,8 @@ fn op_main_module(
let main_path = std::env::current_dir().unwrap().join(main_url.to_string()); let main_path = std::env::current_dir().unwrap().join(main_url.to_string());
state state
.borrow::<Permissions>() .borrow::<Permissions>()
.check_read_blind(&main_path, "main_module")?; .read
.check_blind(&main_path, "main_module")?;
} }
Ok(json!(&main)) Ok(json!(&main))
} }

View file

@ -166,7 +166,7 @@ fn op_now(
// If the permission is not enabled // If the permission is not enabled
// Round the nano result on 2 milliseconds // Round the nano result on 2 milliseconds
// see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision // 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; subsec_nanos -= subsec_nanos % reduced_time_precision;
} }

View file

@ -110,9 +110,9 @@ async fn op_start_tls(
super::check_unstable2(&state, "Deno.startTls"); super::check_unstable2(&state, "Deno.startTls");
let s = state.borrow(); let s = state.borrow();
let permissions = s.borrow::<Permissions>(); let permissions = s.borrow::<Permissions>();
permissions.check_net(&(&domain, Some(0)))?; permissions.net.check(&(&domain, Some(0)))?;
if let Some(path) = &args.cert_file { 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 s = state.borrow();
let permissions = s.borrow::<Permissions>(); 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 { 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(); let mut domain = args.hostname.as_str();
@ -318,9 +318,9 @@ fn op_listen_tls(
let key_file = args.key_file; let key_file = args.key_file;
{ {
let permissions = state.borrow::<Permissions>(); let permissions = state.borrow::<Permissions>();
permissions.check_net(&(&args.hostname, Some(args.port)))?; permissions.net.check(&(&args.hostname, Some(args.port)))?;
permissions.check_read(Path::new(&cert_file))?; permissions.read.check(Path::new(&cert_file))?;
permissions.check_read(Path::new(&key_file))?; permissions.read.check(Path::new(&key_file))?;
} }
let mut config = ServerConfig::new(NoClientAuth::new()); let mut config = ServerConfig::new(NoClientAuth::new());
config config

View file

@ -1,9 +1,14 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. // 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::PermissionState;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::permissions::ReadPermission;
use crate::permissions::UnaryPermission; use crate::permissions::UnaryPermission;
use crate::permissions::WritePermission;
use crate::web_worker::run_web_worker; use crate::web_worker::run_web_worker;
use crate::web_worker::WebWorker; use crate::web_worker::WebWorker;
use crate::web_worker::WebWorkerHandle; use crate::web_worker::WebWorkerHandle;
@ -105,49 +110,54 @@ pub fn init(
); );
} }
fn merge_permission_state( fn merge_boolean_permission(
target: &PermissionState, target: &BooleanPermission,
incoming: Option<PermissionState>, incoming: Option<PermissionState>,
) -> Result<PermissionState, AnyError> { ) -> Result<BooleanPermission, AnyError> {
match target { let mut perm = target.clone();
perm.state = match target.state {
PermissionState::Granted => match incoming { PermissionState::Granted => match incoming {
Some(x) => Ok(x), Some(state) => state,
None => Ok(*target), None => perm.state,
}, },
_ => match incoming { _ => match incoming {
Some(x) => match x { Some(state) => match state {
PermissionState::Denied => Ok(x), PermissionState::Denied => state,
_ => Err(custom_error( _ => {
"PermissionDenied", return Err(custom_error(
"Can't escalate parent thread permissions", "PermissionDenied",
)), "Can't escalate parent thread permissions",
))
}
}, },
None => Ok(*target), None => perm.state,
}, },
} };
Ok(perm)
} }
fn check_net_permission_contains( fn check_net_permission_contains(
a: &HashSet<String>, a: &HashSet<NetPermission>,
b: &HashSet<String>, b: &HashSet<NetPermission>,
) -> bool { ) -> bool {
b.iter().all(|x| a.contains(x)) b.iter().all(|x| a.contains(x))
} }
fn merge_net_permissions( fn merge_net_permissions(
target: &UnaryPermission<String>, target: &UnaryPermission<NetPermission>,
incoming: Option<UnaryPermission<String>>, incoming: Option<UnaryPermission<NetPermission>>,
) -> Result<UnaryPermission<String>, AnyError> { ) -> Result<UnaryPermission<NetPermission>, AnyError> {
if incoming.is_none() { if incoming.is_none() {
return Ok(target.clone()); return Ok(target.clone());
}; };
let new_permissions = incoming.unwrap(); let new_permissions = incoming.unwrap();
match &target.global_state { match &target.global_state {
PermissionState::Granted => Ok(UnaryPermission::<String> { PermissionState::Granted => Ok(UnaryPermission::<NetPermission> {
global_state: new_permissions.global_state, global_state: new_permissions.global_state,
granted_list: new_permissions.granted_list, granted_list: new_permissions.granted_list,
denied_list: new_permissions.denied_list, denied_list: new_permissions.denied_list,
..Permissions::new_net(&None)
}), }),
PermissionState::Prompt => match new_permissions.global_state { PermissionState::Prompt => match new_permissions.global_state {
//Throw //Throw
@ -161,10 +171,11 @@ fn merge_net_permissions(
&target.granted_list, &target.granted_list,
&new_permissions.granted_list, &new_permissions.granted_list,
) { ) {
Ok(UnaryPermission::<String> { Ok(UnaryPermission::<NetPermission> {
global_state: new_permissions.global_state, global_state: new_permissions.global_state,
granted_list: new_permissions.granted_list, granted_list: new_permissions.granted_list,
denied_list: target.denied_list.clone(), denied_list: target.denied_list.clone(),
..Permissions::new_net(&None)
}) })
} else { } else {
Err(custom_error( Err(custom_error(
@ -174,17 +185,19 @@ fn merge_net_permissions(
} }
} }
//Copy //Copy
PermissionState::Denied => Ok(UnaryPermission::<String> { PermissionState::Denied => Ok(UnaryPermission::<NetPermission> {
global_state: new_permissions.global_state, global_state: new_permissions.global_state,
granted_list: new_permissions.granted_list, granted_list: new_permissions.granted_list,
denied_list: new_permissions.denied_list, denied_list: new_permissions.denied_list,
..Permissions::new_net(&None)
}), }),
}, },
PermissionState::Denied => match new_permissions.global_state { PermissionState::Denied => match new_permissions.global_state {
PermissionState::Denied => Ok(UnaryPermission::<String> { PermissionState::Denied => Ok(UnaryPermission::<NetPermission> {
global_state: new_permissions.global_state, global_state: new_permissions.global_state,
granted_list: new_permissions.granted_list, granted_list: new_permissions.granted_list,
denied_list: new_permissions.denied_list, denied_list: new_permissions.denied_list,
..Permissions::new_net(&None)
}), }),
_ => Err(custom_error( _ => Err(custom_error(
"PermissionDenied", "PermissionDenied",
@ -194,45 +207,40 @@ fn merge_net_permissions(
} }
} }
enum WorkerPermissionType {
READ,
WRITE,
}
fn check_read_permissions( fn check_read_permissions(
allow_list: &HashSet<PathBuf>, allow_list: &HashSet<ReadPermission>,
current_permissions: &Permissions, current_permissions: &Permissions,
) -> bool { ) -> bool {
allow_list allow_list
.iter() .iter()
.all(|x| current_permissions.check_read(&x).is_ok()) .all(|x| current_permissions.read.check(&x.0).is_ok())
} }
fn check_write_permissions( fn check_write_permissions(
allow_list: &HashSet<PathBuf>, allow_list: &HashSet<WritePermission>,
current_permissions: &Permissions, current_permissions: &Permissions,
) -> bool { ) -> bool {
allow_list allow_list
.iter() .iter()
.all(|x| current_permissions.check_write(&x).is_ok()) .all(|x| current_permissions.write.check(&x.0).is_ok())
} }
fn merge_read_write_permissions( fn merge_read_permissions(
permission_type: WorkerPermissionType, target: &UnaryPermission<ReadPermission>,
target: &UnaryPermission<PathBuf>, incoming: Option<UnaryPermission<ReadPermission>>,
incoming: Option<UnaryPermission<PathBuf>>,
current_permissions: &Permissions, current_permissions: &Permissions,
) -> Result<UnaryPermission<PathBuf>, AnyError> { ) -> Result<UnaryPermission<ReadPermission>, AnyError> {
if incoming.is_none() { if incoming.is_none() {
return Ok(target.clone()); return Ok(target.clone());
}; };
let new_permissions = incoming.unwrap(); let new_permissions = incoming.unwrap();
match &target.global_state { match &target.global_state {
PermissionState::Granted => Ok(UnaryPermission::<PathBuf> { PermissionState::Granted => Ok(UnaryPermission::<ReadPermission> {
global_state: new_permissions.global_state, global_state: new_permissions.global_state,
granted_list: new_permissions.granted_list, granted_list: new_permissions.granted_list,
denied_list: new_permissions.denied_list, denied_list: new_permissions.denied_list,
..Permissions::new_read(&None)
}), }),
PermissionState::Prompt => match new_permissions.global_state { PermissionState::Prompt => match new_permissions.global_state {
//Throw //Throw
@ -242,20 +250,15 @@ fn merge_read_write_permissions(
)), )),
//Merge //Merge
PermissionState::Prompt => { PermissionState::Prompt => {
if match permission_type { if check_read_permissions(
WorkerPermissionType::READ => check_read_permissions( &new_permissions.granted_list,
&new_permissions.granted_list, current_permissions,
current_permissions, ) {
), Ok(UnaryPermission::<ReadPermission> {
WorkerPermissionType::WRITE => check_write_permissions(
&new_permissions.granted_list,
current_permissions,
),
} {
Ok(UnaryPermission::<PathBuf> {
global_state: new_permissions.global_state, global_state: new_permissions.global_state,
granted_list: new_permissions.granted_list, granted_list: new_permissions.granted_list,
denied_list: target.denied_list.clone(), denied_list: target.denied_list.clone(),
..Permissions::new_read(&None)
}) })
} else { } else {
Err(custom_error( Err(custom_error(
@ -265,17 +268,84 @@ fn merge_read_write_permissions(
} }
} }
//Copy //Copy
PermissionState::Denied => Ok(UnaryPermission::<PathBuf> { PermissionState::Denied => Ok(UnaryPermission::<ReadPermission> {
global_state: new_permissions.global_state, global_state: new_permissions.global_state,
granted_list: new_permissions.granted_list, granted_list: new_permissions.granted_list,
denied_list: new_permissions.denied_list, denied_list: new_permissions.denied_list,
..Permissions::new_read(&None)
}), }),
}, },
PermissionState::Denied => match new_permissions.global_state { PermissionState::Denied => match new_permissions.global_state {
PermissionState::Denied => Ok(UnaryPermission::<PathBuf> { PermissionState::Denied => Ok(UnaryPermission::<ReadPermission> {
global_state: new_permissions.global_state, global_state: new_permissions.global_state,
granted_list: new_permissions.granted_list, granted_list: new_permissions.granted_list,
denied_list: new_permissions.denied_list, denied_list: new_permissions.denied_list,
..Permissions::new_read(&None)
}),
_ => Err(custom_error(
"PermissionDenied",
"Can't escalate parent thread permissions",
)),
},
}
}
fn merge_write_permissions(
target: &UnaryPermission<WritePermission>,
incoming: Option<UnaryPermission<WritePermission>>,
current_permissions: &Permissions,
) -> 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::<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
PermissionState::Granted => Err(custom_error(
"PermissionDenied",
"Can't escalate parent thread permissions",
)),
//Merge
PermissionState::Prompt => {
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(
"PermissionDenied",
"Can't escalate parent thread permissions",
))
}
}
//Copy
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::<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( _ => Err(custom_error(
"PermissionDenied", "PermissionDenied",
@ -290,11 +360,11 @@ fn create_worker_permissions(
permission_args: PermissionsArg, permission_args: PermissionsArg,
) -> Result<Permissions, AnyError> { ) -> Result<Permissions, AnyError> {
Ok(Permissions { Ok(Permissions {
env: merge_permission_state( env: merge_boolean_permission(
&main_thread_permissions.env, &main_thread_permissions.env,
permission_args.env, permission_args.env,
)?, )?,
hrtime: merge_permission_state( hrtime: merge_boolean_permission(
&main_thread_permissions.hrtime, &main_thread_permissions.hrtime,
permission_args.hrtime, permission_args.hrtime,
)?, )?,
@ -302,22 +372,20 @@ fn create_worker_permissions(
&main_thread_permissions.net, &main_thread_permissions.net,
permission_args.net, permission_args.net,
)?, )?,
plugin: merge_permission_state( plugin: merge_boolean_permission(
&main_thread_permissions.plugin, &main_thread_permissions.plugin,
permission_args.plugin, permission_args.plugin,
)?, )?,
read: merge_read_write_permissions( read: merge_read_permissions(
WorkerPermissionType::READ,
&main_thread_permissions.read, &main_thread_permissions.read,
permission_args.read, permission_args.read,
&main_thread_permissions, &main_thread_permissions,
)?, )?,
run: merge_permission_state( run: merge_boolean_permission(
&main_thread_permissions.run, &main_thread_permissions.run,
permission_args.run, permission_args.run,
)?, )?,
write: merge_read_write_permissions( write: merge_write_permissions(
WorkerPermissionType::WRITE,
&main_thread_permissions.write, &main_thread_permissions.write,
permission_args.write, permission_args.write,
&main_thread_permissions, &main_thread_permissions,
@ -331,16 +399,16 @@ struct PermissionsArg {
env: Option<PermissionState>, env: Option<PermissionState>,
#[serde(default, deserialize_with = "as_permission_state")] #[serde(default, deserialize_with = "as_permission_state")]
hrtime: Option<PermissionState>, hrtime: Option<PermissionState>,
#[serde(default, deserialize_with = "as_unary_string_permission")] #[serde(default, deserialize_with = "as_unary_net_permission")]
net: Option<UnaryPermission<String>>, net: Option<UnaryPermission<NetPermission>>,
#[serde(default, deserialize_with = "as_permission_state")] #[serde(default, deserialize_with = "as_permission_state")]
plugin: Option<PermissionState>, plugin: Option<PermissionState>,
#[serde(default, deserialize_with = "as_unary_path_permission")] #[serde(default, deserialize_with = "as_unary_read_permission")]
read: Option<UnaryPermission<PathBuf>>, read: Option<UnaryPermission<ReadPermission>>,
#[serde(default, deserialize_with = "as_permission_state")] #[serde(default, deserialize_with = "as_permission_state")]
run: Option<PermissionState>, run: Option<PermissionState>,
#[serde(default, deserialize_with = "as_unary_path_permission")] #[serde(default, deserialize_with = "as_unary_write_permission")]
write: Option<UnaryPermission<PathBuf>>, write: Option<UnaryPermission<WritePermission>>,
} }
fn as_permission_state<'de, D>( fn as_permission_state<'de, D>(
@ -402,27 +470,31 @@ impl<'de> de::Visitor<'de> for ParseBooleanOrStringVec {
} }
} }
fn as_unary_string_permission<'de, D>( fn as_unary_net_permission<'de, D>(
deserializer: D, deserializer: D,
) -> Result<Option<UnaryPermission<String>>, D::Error> ) -> Result<Option<UnaryPermission<NetPermission>>, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let value: UnaryPermissionBase = let value: UnaryPermissionBase =
deserializer.deserialize_any(ParseBooleanOrStringVec)?; 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, global_state: value.global_state,
granted_list: allowed, granted_list: allowed,
..Default::default() ..Default::default()
})) }))
} }
fn as_unary_path_permission<'de, D>( fn as_unary_read_permission<'de, D>(
deserializer: D, deserializer: D,
) -> Result<Option<UnaryPermission<PathBuf>>, D::Error> ) -> Result<Option<UnaryPermission<ReadPermission>>, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@ -432,9 +504,28 @@ where
let paths: Vec<PathBuf> = let paths: Vec<PathBuf> =
value.paths.into_iter().map(PathBuf::from).collect(); value.paths.into_iter().map(PathBuf::from).collect();
Ok(Some(UnaryPermission::<PathBuf> { Ok(Some(UnaryPermission::<ReadPermission> {
global_state: value.global_state, global_state: value.global_state,
granted_list: resolve_fs_allowlist(&Some(paths)), granted_list: resolve_read_allowlist(&Some(paths)),
..Default::default()
}))
}
fn as_unary_write_permission<'de, D>(
deserializer: D,
) -> Result<Option<UnaryPermission<WritePermission>>, 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::<WritePermission> {
global_state: value.global_state,
granted_list: resolve_write_allowlist(&Some(paths)),
..Default::default() ..Default::default()
})) }))
} }

File diff suppressed because it is too large Load diff