1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-21 23:04:45 -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");
^
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]

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");
^
at async file:///[WILDCARD]/error_015_dynamic_import_permissions.js:2:3

View file

@ -1,3 +1,3 @@
[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]

View file

@ -1,3 +1,3 @@
[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]

View file

@ -5520,7 +5520,7 @@ console.log("finish");
assert_eq!(util::strip_ansi_codes(&stdout_str), "0.147205063401058\n");
let stderr_str = String::from_utf8(output.stderr).unwrap();
assert!(util::strip_ansi_codes(&stderr_str)
.contains("PermissionDenied: write access"));
.contains("PermissionDenied: Requires write access"));
}
#[test]
@ -5784,7 +5784,7 @@ console.log("finish");
let out = String::from_utf8_lossy(&output.stdout);
assert!(!output.status.success());
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());
}
@ -5806,7 +5806,7 @@ console.log("finish");
let out = String::from_utf8_lossy(&output.stdout);
assert!(!output.status.success());
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());
}

View file

@ -44,7 +44,7 @@ unitTest({ perms: { read: false } }, function dirCwdPermError(): void {
Deno.cwd();
},
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.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;
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(&current_dir()?, "CWD")?;
permissions.read.check_blind(&current_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(&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 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))
}

View file

@ -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 {

View file

@ -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)))?;
}
}

View file

@ -34,7 +34,8 @@ fn op_exec_path(
let current_exe = env::current_exe().unwrap();
state
.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
// 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();

View file

@ -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",

View file

@ -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)?;

View file

@ -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)?;

View file

@ -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))
}

View file

@ -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;
}

View file

@ -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

View file

@ -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,40 @@ 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_write_permissions(
permission_type: WorkerPermissionType,
target: &UnaryPermission<PathBuf>,
incoming: Option<UnaryPermission<PathBuf>>,
fn merge_read_permissions(
target: &UnaryPermission<ReadPermission>,
incoming: Option<UnaryPermission<ReadPermission>>,
current_permissions: &Permissions,
) -> Result<UnaryPermission<PathBuf>, AnyError> {
) -> 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::<PathBuf> {
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
@ -242,20 +250,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_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(
@ -265,17 +268,84 @@ fn merge_read_write_permissions(
}
}
//Copy
PermissionState::Denied => Ok(UnaryPermission::<PathBuf> {
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::<PathBuf> {
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_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(
"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,31 @@ 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<PathBuf>>, D::Error>
) -> Result<Option<UnaryPermission<ReadPermission>>, D::Error>
where
D: Deserializer<'de>,
{
@ -432,9 +504,28 @@ where
let paths: Vec<PathBuf> =
value.paths.into_iter().map(PathBuf::from).collect();
Ok(Some(UnaryPermission::<PathBuf> {
Ok(Some(UnaryPermission::<ReadPermission> {
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()
}))
}

File diff suppressed because it is too large Load diff