diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/args/flags.rs | 615 | ||||
-rw-r--r-- | cli/args/flags_net.rs (renamed from cli/args/flags_allow_net.rs) | 0 | ||||
-rw-r--r-- | cli/args/mod.rs | 10 | ||||
-rw-r--r-- | cli/tests/integration/run_tests.rs | 70 | ||||
-rw-r--r-- | cli/tests/testdata/run/deny_all_permission_args.js | 8 | ||||
-rw-r--r-- | cli/tests/testdata/run/deny_all_permission_args.out | 8 | ||||
-rw-r--r-- | cli/tests/testdata/run/deny_some_permission_args.js | 22 | ||||
-rw-r--r-- | cli/tests/testdata/run/deny_some_permission_args.out | 22 | ||||
-rw-r--r-- | cli/tests/testdata/run/permissions_cache.ts | 5 | ||||
-rw-r--r-- | cli/tsc/dts/lib.deno.ns.d.ts | 34 |
10 files changed, 756 insertions, 38 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 9674c68a6..790a9d83f 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -24,7 +24,7 @@ use std::str::FromStr; use crate::util::fs::canonicalize_path; -use super::flags_allow_net; +use super::flags_net; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct FileFlags { @@ -364,13 +364,21 @@ pub struct Flags { pub allow_all: bool, pub allow_env: Option<Vec<String>>, + pub deny_env: Option<Vec<String>>, pub allow_hrtime: bool, + pub deny_hrtime: bool, pub allow_net: Option<Vec<String>>, + pub deny_net: Option<Vec<String>>, pub allow_ffi: Option<Vec<PathBuf>>, + pub deny_ffi: Option<Vec<PathBuf>>, pub allow_read: Option<Vec<PathBuf>>, + pub deny_read: Option<Vec<PathBuf>>, pub allow_run: Option<Vec<String>>, + pub deny_run: Option<Vec<String>>, pub allow_sys: Option<Vec<String>>, + pub deny_sys: Option<Vec<String>>, pub allow_write: Option<Vec<PathBuf>>, + pub deny_write: Option<Vec<PathBuf>>, pub ca_stores: Option<Vec<String>>, pub ca_data: Option<CaData>, pub cache_blocklist: Vec<String>, @@ -434,6 +442,17 @@ impl Flags { _ => {} } + match &self.deny_read { + Some(read_denylist) if read_denylist.is_empty() => { + args.push("--deny-read".to_string()); + } + Some(read_denylist) => { + let s = format!("--deny-read={}", join_paths(read_denylist, ",")); + args.push(s); + } + _ => {} + } + match &self.allow_write { Some(write_allowlist) if write_allowlist.is_empty() => { args.push("--allow-write".to_string()); @@ -445,6 +464,17 @@ impl Flags { _ => {} } + match &self.deny_write { + Some(write_denylist) if write_denylist.is_empty() => { + args.push("--deny-write".to_string()); + } + Some(write_denylist) => { + let s = format!("--deny-write={}", join_paths(write_denylist, ",")); + args.push(s); + } + _ => {} + } + match &self.allow_net { Some(net_allowlist) if net_allowlist.is_empty() => { args.push("--allow-net".to_string()); @@ -456,6 +486,17 @@ impl Flags { _ => {} } + match &self.deny_net { + Some(net_denylist) if net_denylist.is_empty() => { + args.push("--deny-net".to_string()); + } + Some(net_denylist) => { + let s = format!("--deny-net={}", net_denylist.join(",")); + args.push(s); + } + _ => {} + } + match &self.unsafely_ignore_certificate_errors { Some(ic_allowlist) if ic_allowlist.is_empty() => { args.push("--unsafely-ignore-certificate-errors".to_string()); @@ -481,6 +522,17 @@ impl Flags { _ => {} } + match &self.deny_env { + Some(env_denylist) if env_denylist.is_empty() => { + args.push("--deny-env".to_string()); + } + Some(env_denylist) => { + let s = format!("--deny-env={}", env_denylist.join(",")); + args.push(s); + } + _ => {} + } + match &self.allow_run { Some(run_allowlist) if run_allowlist.is_empty() => { args.push("--allow-run".to_string()); @@ -492,6 +544,17 @@ impl Flags { _ => {} } + match &self.deny_run { + Some(run_denylist) if run_denylist.is_empty() => { + args.push("--deny-run".to_string()); + } + Some(run_denylist) => { + let s = format!("--deny-run={}", run_denylist.join(",")); + args.push(s); + } + _ => {} + } + match &self.allow_sys { Some(sys_allowlist) if sys_allowlist.is_empty() => { args.push("--allow-sys".to_string()); @@ -503,6 +566,17 @@ impl Flags { _ => {} } + match &self.deny_sys { + Some(sys_denylist) if sys_denylist.is_empty() => { + args.push("--deny-sys".to_string()); + } + Some(sys_denylist) => { + let s = format!("--deny-sys={}", sys_denylist.join(",")); + args.push(s) + } + _ => {} + } + match &self.allow_ffi { Some(ffi_allowlist) if ffi_allowlist.is_empty() => { args.push("--allow-ffi".to_string()); @@ -514,10 +588,25 @@ impl Flags { _ => {} } + match &self.deny_ffi { + Some(ffi_denylist) if ffi_denylist.is_empty() => { + args.push("--deny-ffi".to_string()); + } + Some(ffi_denylist) => { + let s = format!("--deny-ffi={}", join_paths(ffi_denylist, ",")); + args.push(s); + } + _ => {} + } + if self.allow_hrtime { args.push("--allow-hrtime".to_string()); } + if self.deny_hrtime { + args.push("--deny-hrtime".to_string()); + } + args } @@ -607,26 +696,42 @@ impl Flags { pub fn has_permission(&self) -> bool { self.allow_all || self.allow_hrtime + || self.deny_hrtime || self.allow_env.is_some() + || self.deny_env.is_some() || self.allow_ffi.is_some() + || self.deny_ffi.is_some() || self.allow_net.is_some() + || self.deny_net.is_some() || self.allow_read.is_some() + || self.deny_read.is_some() || self.allow_run.is_some() + || self.deny_run.is_some() || self.allow_sys.is_some() + || self.deny_sys.is_some() || self.allow_write.is_some() + || self.deny_write.is_some() } pub fn has_permission_in_argv(&self) -> bool { self.argv.iter().any(|arg| { arg == "--allow-all" || arg == "--allow-hrtime" + || arg == "--deny-hrtime" || arg.starts_with("--allow-env") + || arg.starts_with("--deny-env") || arg.starts_with("--allow-ffi") + || arg.starts_with("--deny-ffi") || arg.starts_with("--allow-net") + || arg.starts_with("--deny-net") || arg.starts_with("--allow-read") + || arg.starts_with("--deny-read") || arg.starts_with("--allow-run") + || arg.starts_with("--deny-run") || arg.starts_with("--allow-sys") + || arg.starts_with("--deny-sys") || arg.starts_with("--allow-write") + || arg.starts_with("--deny-write") }) } } @@ -2037,6 +2142,16 @@ static ALLOW_READ_HELP: &str = concat!( " --allow-read=\"/etc,/var/log.txt\"" ); +static DENY_READ_HELP: &str = concat!( + "Deny file system read access. Optionally specify denied paths.\n", + "Docs: https://deno.land/manual@v", + env!("CARGO_PKG_VERSION"), + "/basics/permissions\n", + "Examples:\n", + " --deny-read\n", + " --deny-read=\"/etc,/var/log.txt\"" +); + static ALLOW_WRITE_HELP: &str = concat!( "Allow file system write access. Optionally specify allowed paths.\n", "Docs: https://deno.land/manual@v", @@ -2047,6 +2162,16 @@ static ALLOW_WRITE_HELP: &str = concat!( " --allow-write=\"/etc,/var/log.txt\"" ); +static DENY_WRITE_HELP: &str = concat!( + "Deny file system write access. Optionally specify denied paths.\n", + "Docs: https://deno.land/manual@v", + env!("CARGO_PKG_VERSION"), + "/basics/permissions\n", + "Examples:\n", + " --deny-write\n", + " --deny-write=\"/etc,/var/log.txt\"" +); + static ALLOW_NET_HELP: &str = concat!( "Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary.\n", "Docs: https://deno.land/manual@v", @@ -2057,6 +2182,16 @@ static ALLOW_NET_HELP: &str = concat!( " --allow-net=\"localhost:8080,deno.land\"" ); +static DENY_NET_HELP: &str = concat!( + "Deny network access. Optionally specify denied IP addresses and host names, with ports as necessary.\n", + "Docs: https://deno.land/manual@v", + env!("CARGO_PKG_VERSION"), + "/basics/permissions\n", + "Examples:\n", + " --deny-net\n", + " --deny-net=\"localhost:8080,deno.land\"" +); + static ALLOW_ENV_HELP: &str = concat!( "Allow access to system environment information. Optionally specify accessible environment variables.\n", "Docs: https://deno.land/manual@v", @@ -2067,6 +2202,16 @@ static ALLOW_ENV_HELP: &str = concat!( " --allow-env=\"PORT,HOME,PATH\"" ); +static DENY_ENV_HELP: &str = concat!( + "Deny access to system environment information. Optionally specify accessible environment variables.\n", + "Docs: https://deno.land/manual@v", + env!("CARGO_PKG_VERSION"), + "/basics/permissions\n", + "Examples:\n", + " --deny-env\n", + " --deny-env=\"PORT,HOME,PATH\"" +); + static ALLOW_SYS_HELP: &str = concat!( "Allow access to OS information. Optionally allow specific APIs by function name.\n", "Docs: https://deno.land/manual@v", @@ -2077,6 +2222,16 @@ static ALLOW_SYS_HELP: &str = concat!( " --allow-sys=\"systemMemoryInfo,osRelease\"" ); +static DENY_SYS_HELP: &str = concat!( + "Deny access to OS information. Optionally deny specific APIs by function name.\n", + "Docs: https://deno.land/manual@v", + env!("CARGO_PKG_VERSION"), + "/basics/permissions\n", + "Examples:\n", + " --deny-sys\n", + " --deny-sys=\"systemMemoryInfo,osRelease\"" +); + static ALLOW_RUN_HELP: &str = concat!( "Allow running subprocesses. Optionally specify allowed runnable program names.\n", "Docs: https://deno.land/manual@v", @@ -2087,6 +2242,16 @@ static ALLOW_RUN_HELP: &str = concat!( " --allow-run=\"whoami,ps\"" ); +static DENY_RUN_HELP: &str = concat!( + "Deny running subprocesses. Optionally specify denied runnable program names.\n", + "Docs: https://deno.land/manual@v", + env!("CARGO_PKG_VERSION"), + "/basics/permissions\n", + "Examples:\n", + " --deny-run\n", + " --deny-run=\"whoami,ps\"" +); + static ALLOW_FFI_HELP: &str = concat!( "(Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files.\n", "Docs: https://deno.land/manual@v", @@ -2097,6 +2262,16 @@ static ALLOW_FFI_HELP: &str = concat!( " --allow-ffi=\"./libfoo.so\"" ); +static DENY_FFI_HELP: &str = concat!( + "(Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.\n", + "Docs: https://deno.land/manual@v", + env!("CARGO_PKG_VERSION"), + "/basics/permissions\n", + "Examples:\n", + " --deny-ffi\n", + " --deny-ffi=\"./libfoo.so\"" +); + static ALLOW_HRTIME_HELP: &str = concat!( "Allow high-resolution time measurement. Note: this can enable timing attacks and fingerprinting.\n", "Docs: https://deno.land/manual@v", @@ -2104,6 +2279,13 @@ static ALLOW_HRTIME_HELP: &str = concat!( "/basics/permissions\n" ); +static DENY_HRTIME_HELP: &str = concat!( + "Deny high-resolution time measurement. Note: this can prevent timing attacks and fingerprinting.\n", + "Docs: https://deno.land/manual@v", + env!("CARGO_PKG_VERSION"), + "/basics/permissions\n" +); + static ALLOW_ALL_HELP: &str = concat!( "Allow all permissions. Learn more about permissions in Deno:\n", "https://deno.land/manual@v", @@ -2125,6 +2307,17 @@ fn permission_args(app: Command) -> Command { .value_hint(ValueHint::AnyPath), ) .arg( + Arg::new("deny-read") + .long("deny-read") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help(DENY_READ_HELP) + .value_parser(value_parser!(PathBuf)) + .value_hint(ValueHint::AnyPath), + ) + .arg( Arg::new("allow-write") .long("allow-write") .num_args(0..) @@ -2136,6 +2329,17 @@ fn permission_args(app: Command) -> Command { .value_hint(ValueHint::AnyPath), ) .arg( + Arg::new("deny-write") + .long("deny-write") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help(DENY_WRITE_HELP) + .value_parser(value_parser!(PathBuf)) + .value_hint(ValueHint::AnyPath), + ) + .arg( Arg::new("allow-net") .long("allow-net") .num_args(0..) @@ -2143,7 +2347,17 @@ fn permission_args(app: Command) -> Command { .require_equals(true) .value_name("IP_OR_HOSTNAME") .help(ALLOW_NET_HELP) - .value_parser(flags_allow_net::validator), + .value_parser(flags_net::validator), + ) + .arg( + Arg::new("deny-net") + .long("deny-net") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("IP_OR_HOSTNAME") + .help(DENY_NET_HELP) + .value_parser(flags_net::validator), ) .arg(unsafely_ignore_certificate_errors_arg()) .arg( @@ -2167,6 +2381,26 @@ fn permission_args(app: Command) -> Command { }), ) .arg( + Arg::new("deny-env") + .long("deny-env") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("VARIABLE_NAME") + .help(DENY_ENV_HELP) + .value_parser(|key: &str| { + if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { + return Err(format!("invalid key \"{key}\"")); + } + + Ok(if cfg!(windows) { + key.to_uppercase() + } else { + key.to_string() + }) + }), + ) + .arg( Arg::new("allow-sys") .long("allow-sys") .num_args(0..) @@ -2177,6 +2411,16 @@ fn permission_args(app: Command) -> Command { .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)), ) .arg( + Arg::new("deny-sys") + .long("deny-sys") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("API_NAME") + .help(DENY_SYS_HELP) + .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)), + ) + .arg( Arg::new("allow-run") .long("allow-run") .num_args(0..) @@ -2186,6 +2430,15 @@ fn permission_args(app: Command) -> Command { .help(ALLOW_RUN_HELP), ) .arg( + Arg::new("deny-run") + .long("deny-run") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PROGRAM_NAME") + .help(DENY_RUN_HELP), + ) + .arg( Arg::new("allow-ffi") .long("allow-ffi") .num_args(0..) @@ -2197,12 +2450,29 @@ fn permission_args(app: Command) -> Command { .value_hint(ValueHint::AnyPath), ) .arg( + Arg::new("deny-ffi") + .long("deny-ffi") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help(DENY_FFI_HELP) + .value_parser(value_parser!(PathBuf)) + .value_hint(ValueHint::AnyPath), + ) + .arg( Arg::new("allow-hrtime") .long("allow-hrtime") .action(ArgAction::SetTrue) .help(ALLOW_HRTIME_HELP), ) .arg( + Arg::new("deny-hrtime") + .long("deny-hrtime") + .action(ArgAction::SetTrue) + .help(DENY_HRTIME_HELP), + ) + .arg( Arg::new("allow-all") .short('A') .long("allow-all") @@ -2594,7 +2864,7 @@ fn unsafely_ignore_certificate_errors_arg() -> Arg { .require_equals(true) .value_name("HOSTNAMES") .help("DANGER: Disables verification of TLS certificates") - .value_parser(flags_allow_net::validator) + .value_parser(flags_net::validator) } fn bench_parse(flags: &mut Flags, matches: &mut ArgMatches) { @@ -3189,38 +3459,76 @@ fn permission_args_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.allow_read = Some(read_wl.collect()); } + if let Some(read_wl) = matches.remove_many::<PathBuf>("deny-read") { + flags.deny_read = Some(read_wl.collect()); + } + if let Some(write_wl) = matches.remove_many::<PathBuf>("allow-write") { flags.allow_write = Some(write_wl.collect()); } + if let Some(write_wl) = matches.remove_many::<PathBuf>("deny-write") { + flags.deny_write = Some(write_wl.collect()); + } + if let Some(net_wl) = matches.remove_many::<String>("allow-net") { - let net_allowlist = flags_allow_net::parse(net_wl.collect()).unwrap(); + let net_allowlist = flags_net::parse(net_wl.collect()).unwrap(); flags.allow_net = Some(net_allowlist); } + if let Some(net_wl) = matches.remove_many::<String>("deny-net") { + let net_denylist = flags_net::parse(net_wl.collect()).unwrap(); + flags.deny_net = Some(net_denylist); + } + if let Some(env_wl) = matches.remove_many::<String>("allow-env") { flags.allow_env = Some(env_wl.collect()); debug!("env allowlist: {:#?}", &flags.allow_env); } + if let Some(env_wl) = matches.remove_many::<String>("deny-env") { + flags.deny_env = Some(env_wl.collect()); + debug!("env denylist: {:#?}", &flags.deny_env); + } + if let Some(run_wl) = matches.remove_many::<String>("allow-run") { flags.allow_run = Some(run_wl.collect()); debug!("run allowlist: {:#?}", &flags.allow_run); } + if let Some(run_wl) = matches.remove_many::<String>("deny-run") { + flags.deny_run = Some(run_wl.collect()); + debug!("run denylist: {:#?}", &flags.deny_run); + } + if let Some(sys_wl) = matches.remove_many::<String>("allow-sys") { flags.allow_sys = Some(sys_wl.collect()); debug!("sys info allowlist: {:#?}", &flags.allow_sys); } + if let Some(sys_wl) = matches.remove_many::<String>("deny-sys") { + flags.deny_sys = Some(sys_wl.collect()); + debug!("sys info denylist: {:#?}", &flags.deny_sys); + } + if let Some(ffi_wl) = matches.remove_many::<PathBuf>("allow-ffi") { flags.allow_ffi = Some(ffi_wl.collect()); debug!("ffi allowlist: {:#?}", &flags.allow_ffi); } + if let Some(ffi_wl) = matches.remove_many::<PathBuf>("deny-ffi") { + flags.deny_ffi = Some(ffi_wl.collect()); + debug!("ffi denylist: {:#?}", &flags.deny_ffi); + } + if matches.get_flag("allow-hrtime") { flags.allow_hrtime = true; } + + if matches.get_flag("deny-hrtime") { + flags.deny_hrtime = true; + } + if matches.get_flag("allow-all") { flags.allow_all = true; flags.allow_read = Some(vec![]); @@ -3232,6 +3540,7 @@ fn permission_args_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.allow_ffi = Some(vec![]); flags.allow_hrtime = true; } + if matches.get_flag("no-prompt") { flags.no_prompt = true; } @@ -3243,7 +3552,7 @@ fn unsafely_ignore_certificate_errors_parse( if let Some(ic_wl) = matches.remove_many::<String>("unsafely-ignore-certificate-errors") { - let ic_allowlist = flags_allow_net::parse(ic_wl.collect()).unwrap(); + let ic_allowlist = flags_net::parse(ic_wl.collect()).unwrap(); flags.unsafely_ignore_certificate_errors = Some(ic_allowlist); } } @@ -3694,6 +4003,9 @@ mod tests { let r = flags_from_vec(svec!["deno", "run", "--allow-read", "x.ts"]); assert_eq!(r.unwrap().has_permission(), true); + let r = flags_from_vec(svec!["deno", "run", "--deny-read", "x.ts"]); + assert_eq!(r.unwrap().has_permission(), true); + let r = flags_from_vec(svec!["deno", "run", "x.ts"]); assert_eq!(r.unwrap().has_permission(), false); } @@ -3703,6 +4015,9 @@ mod tests { let r = flags_from_vec(svec!["deno", "run", "x.ts", "--allow-read"]); assert_eq!(r.unwrap().has_permission_in_argv(), true); + let r = flags_from_vec(svec!["deno", "run", "x.ts", "--deny-read"]); + assert_eq!(r.unwrap().has_permission_in_argv(), true); + let r = flags_from_vec(svec!["deno", "run", "x.ts"]); assert_eq!(r.unwrap().has_permission_in_argv(), false); } @@ -3772,6 +4087,22 @@ mod tests { } #[test] + fn deny_read() { + let r = flags_from_vec(svec!["deno", "run", "--deny-read", "gist.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "gist.ts".to_string(), + }), + deny_read: Some(vec![]), + ..Flags::default() + } + ); + } + + #[test] fn allow_hrtime() { let r = flags_from_vec(svec!["deno", "run", "--allow-hrtime", "gist.ts"]); assert_eq!( @@ -3788,6 +4119,22 @@ mod tests { } #[test] + fn deny_hrtime() { + let r = flags_from_vec(svec!["deno", "run", "--deny-hrtime", "gist.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "gist.ts".to_string(), + }), + deny_hrtime: true, + ..Flags::default() + } + ); + } + + #[test] fn double_hyphen() { // notice that flags passed after double dash will not // be parsed to Flags but instead forwarded to @@ -4687,11 +5034,17 @@ mod tests { allow_net: Some(vec![]), unsafely_ignore_certificate_errors: None, allow_env: Some(vec![]), + deny_env: None, allow_run: Some(vec![]), + deny_run: None, allow_read: Some(vec![]), + deny_read: None, allow_sys: Some(vec![]), + deny_sys: None, allow_write: Some(vec![]), + deny_write: None, allow_ffi: Some(vec![]), + deny_ffi: None, allow_hrtime: true, ..Flags::default() } @@ -4805,6 +5158,31 @@ mod tests { } #[test] + fn deny_read_denylist() { + use test_util::TempDir; + let temp_dir_guard = TempDir::new(); + let temp_dir = temp_dir_guard.path().to_path_buf(); + + let r = flags_from_vec(svec![ + "deno", + "run", + format!("--deny-read=.,{}", temp_dir.to_str().unwrap()), + "script.ts" + ]); + assert_eq!( + r.unwrap(), + Flags { + deny_read: Some(vec![PathBuf::from("."), temp_dir]), + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + ..Flags::default() + } + ); + } + + #[test] fn allow_write_allowlist() { use test_util::TempDir; let temp_dir_guard = TempDir::new(); @@ -4830,6 +5208,31 @@ mod tests { } #[test] + fn deny_write_denylist() { + use test_util::TempDir; + let temp_dir_guard = TempDir::new(); + let temp_dir = temp_dir_guard.path().to_path_buf(); + + let r = flags_from_vec(svec![ + "deno", + "run", + format!("--deny-write=.,{}", temp_dir.to_str().unwrap()), + "script.ts" + ]); + assert_eq!( + r.unwrap(), + Flags { + deny_write: Some(vec![PathBuf::from("."), temp_dir]), + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + ..Flags::default() + } + ); + } + + #[test] fn allow_net_allowlist() { let r = flags_from_vec(svec![ "deno", @@ -4851,6 +5254,23 @@ mod tests { } #[test] + fn deny_net_denylist() { + let r = + flags_from_vec(svec!["deno", "run", "--deny-net=127.0.0.1", "script.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + deny_net: Some(svec!["127.0.0.1"]), + ..Flags::default() + } + ); + } + + #[test] fn allow_env_allowlist() { let r = flags_from_vec(svec!["deno", "run", "--allow-env=HOME", "script.ts"]); @@ -4868,6 +5288,23 @@ mod tests { } #[test] + fn deny_env_denylist() { + let r = + flags_from_vec(svec!["deno", "run", "--deny-env=HOME", "script.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + deny_env: Some(svec!["HOME"]), + ..Flags::default() + } + ); + } + + #[test] fn allow_env_allowlist_multiple() { let r = flags_from_vec(svec![ "deno", @@ -4889,6 +5326,23 @@ mod tests { } #[test] + fn deny_env_denylist_multiple() { + let r = + flags_from_vec(svec!["deno", "run", "--deny-env=HOME,PATH", "script.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + deny_env: Some(svec!["HOME", "PATH"]), + ..Flags::default() + } + ); + } + + #[test] fn allow_env_allowlist_validator() { let r = flags_from_vec(svec!["deno", "run", "--allow-env=HOME", "script.ts"]); @@ -4902,6 +5356,19 @@ mod tests { } #[test] + fn deny_env_denylist_validator() { + let r = + flags_from_vec(svec!["deno", "run", "--deny-env=HOME", "script.ts"]); + assert!(r.is_ok()); + let r = + flags_from_vec(svec!["deno", "run", "--deny-env=H=ME", "script.ts"]); + assert!(r.is_err()); + let r = + flags_from_vec(svec!["deno", "run", "--deny-env=H\0ME", "script.ts"]); + assert!(r.is_err()); + } + + #[test] fn allow_sys() { let r = flags_from_vec(svec!["deno", "run", "--allow-sys", "script.ts"]); assert_eq!( @@ -4918,6 +5385,22 @@ mod tests { } #[test] + fn deny_sys() { + let r = flags_from_vec(svec!["deno", "run", "--deny-sys", "script.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + deny_sys: Some(vec![]), + ..Flags::default() + } + ); + } + + #[test] fn allow_sys_allowlist() { let r = flags_from_vec(svec!["deno", "run", "--allow-sys=hostname", "script.ts"]); @@ -4935,6 +5418,23 @@ mod tests { } #[test] + fn deny_sys_denylist() { + let r = + flags_from_vec(svec!["deno", "run", "--deny-sys=hostname", "script.ts"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + deny_sys: Some(svec!["hostname"]), + ..Flags::default() + } + ); + } + + #[test] fn allow_sys_allowlist_multiple() { let r = flags_from_vec(svec![ "deno", @@ -4956,6 +5456,27 @@ mod tests { } #[test] + fn deny_sys_denylist_multiple() { + let r = flags_from_vec(svec![ + "deno", + "run", + "--deny-sys=hostname,osRelease", + "script.ts" + ]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + deny_sys: Some(svec!["hostname", "osRelease"]), + ..Flags::default() + } + ); + } + + #[test] fn allow_sys_allowlist_validator() { let r = flags_from_vec(svec!["deno", "run", "--allow-sys=hostname", "script.ts"]); @@ -4980,6 +5501,29 @@ mod tests { } #[test] + fn deny_sys_denylist_validator() { + let r = + flags_from_vec(svec!["deno", "run", "--deny-sys=hostname", "script.ts"]); + assert!(r.is_ok()); + let r = flags_from_vec(svec![ + "deno", + "run", + "--deny-sys=hostname,osRelease", + "script.ts" + ]); + assert!(r.is_ok()); + let r = flags_from_vec(svec!["deno", "run", "--deny-sys=foo", "script.ts"]); + assert!(r.is_err()); + let r = flags_from_vec(svec![ + "deno", + "run", + "--deny-sys=hostname,foo", + "script.ts" + ]); + assert!(r.is_err()); + } + + #[test] fn reload_validator() { let r = flags_from_vec(svec![ "deno", @@ -5851,6 +6395,35 @@ mod tests { } #[test] + fn deny_net_denylist_with_ports() { + let r = flags_from_vec(svec![ + "deno", + "run", + "--deny-net=deno.land,:8000,:4545", + "script.ts" + ]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + deny_net: Some(svec![ + "deno.land", + "0.0.0.0:8000", + "127.0.0.1:8000", + "localhost:8000", + "0.0.0.0:4545", + "127.0.0.1:4545", + "localhost:4545" + ]), + ..Flags::default() + } + ); + } + + #[test] fn allow_net_allowlist_with_ipv6_address() { let r = flags_from_vec(svec![ "deno", @@ -5883,6 +6456,38 @@ mod tests { } #[test] + fn deny_net_denylist_with_ipv6_address() { + let r = flags_from_vec(svec![ + "deno", + "run", + "--deny-net=deno.land,deno.land:80,::,127.0.0.1,[::1],1.2.3.4:5678,:5678,[::1]:8080", + "script.ts" + ]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Run(RunFlags { + watch: None, + script: "script.ts".to_string(), + }), + deny_net: Some(svec![ + "deno.land", + "deno.land:80", + "::", + "127.0.0.1", + "[::1]", + "1.2.3.4:5678", + "0.0.0.0:5678", + "127.0.0.1:5678", + "localhost:5678", + "[::1]:8080" + ]), + ..Flags::default() + } + ); + } + + #[test] fn lock_write() { let r = flags_from_vec(svec![ "deno", diff --git a/cli/args/flags_allow_net.rs b/cli/args/flags_net.rs index 9f8a6b9f9..9f8a6b9f9 100644 --- a/cli/args/flags_allow_net.rs +++ b/cli/args/flags_net.rs diff --git a/cli/args/mod.rs b/cli/args/mod.rs index cea0c0ca1..7b3b0aa83 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -2,7 +2,7 @@ mod config_file; mod flags; -mod flags_allow_net; +mod flags_net; mod import_map; mod lockfile; pub mod package_json; @@ -1105,13 +1105,21 @@ impl CliOptions { pub fn permissions_options(&self) -> PermissionsOptions { PermissionsOptions { allow_env: self.flags.allow_env.clone(), + deny_env: self.flags.deny_env.clone(), allow_hrtime: self.flags.allow_hrtime, + deny_hrtime: self.flags.deny_hrtime, allow_net: self.flags.allow_net.clone(), + deny_net: self.flags.deny_net.clone(), allow_ffi: self.flags.allow_ffi.clone(), + deny_ffi: self.flags.deny_ffi.clone(), allow_read: self.flags.allow_read.clone(), + deny_read: self.flags.deny_read.clone(), allow_run: self.flags.allow_run.clone(), + deny_run: self.flags.deny_run.clone(), allow_sys: self.flags.allow_sys.clone(), + deny_sys: self.flags.deny_sys.clone(), allow_write: self.flags.allow_write.clone(), + deny_write: self.flags.deny_write.clone(), prompt: !self.no_prompt(), } } diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs index 9720f2577..e83932011 100644 --- a/cli/tests/integration/run_tests.rs +++ b/cli/tests/integration/run_tests.rs @@ -601,7 +601,7 @@ fn _090_run_permissions_request() { .with_pty(|mut console| { console.expect(concat!( "┌ ⚠️ Deno requests run access to \"ls\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-run to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)", )); @@ -609,7 +609,7 @@ fn _090_run_permissions_request() { console.expect("Granted run access to \"ls\"."); console.expect(concat!( "┌ ⚠️ Deno requests run access to \"cat\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-run to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)", )); @@ -628,7 +628,7 @@ fn _090_run_permissions_request_sync() { .with_pty(|mut console| { console.expect(concat!( "┌ ⚠️ Deno requests run access to \"ls\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-run to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)", )); @@ -636,7 +636,7 @@ fn _090_run_permissions_request_sync() { console.expect("Granted run access to \"ls\"."); console.expect(concat!( "┌ ⚠️ Deno requests run access to \"cat\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-run to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)", )); @@ -656,7 +656,7 @@ fn permissions_prompt_allow_all() { // "run" permissions console.expect(concat!( "┌ ⚠️ Deno requests run access to \"FOO\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-run to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)", )); @@ -665,7 +665,7 @@ fn permissions_prompt_allow_all() { // "read" permissions console.expect(concat!( "┌ ⚠️ Deno requests read access to \"FOO\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-read to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)", )); @@ -674,7 +674,7 @@ fn permissions_prompt_allow_all() { // "write" permissions console.expect(concat!( "┌ ⚠️ Deno requests write access to \"FOO\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-write to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all write permissions)", )); @@ -682,8 +682,8 @@ fn permissions_prompt_allow_all() { console.expect("✅ Granted all write access."); // "net" permissions console.expect(concat!( - "┌ ⚠️ Deno requests network access to \"foo\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "┌ ⚠️ Deno requests net access to \"foo\".\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-net to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all net permissions)", )); @@ -692,7 +692,7 @@ fn permissions_prompt_allow_all() { // "env" permissions console.expect(concat!( "┌ ⚠️ Deno requests env access to \"FOO\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-env to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions)", )); @@ -701,7 +701,7 @@ fn permissions_prompt_allow_all() { // "sys" permissions console.expect(concat!( "┌ ⚠️ Deno requests sys access to \"loadavg\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-sys to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all sys permissions)", )); @@ -710,7 +710,7 @@ fn permissions_prompt_allow_all() { // "ffi" permissions console.expect(concat!( "┌ ⚠️ Deno requests ffi access to \"FOO\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-ffi to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all ffi permissions)", )); @@ -766,7 +766,7 @@ fn permissions_prompt_allow_all_lowercase_a() { // "run" permissions console.expect(concat!( "┌ ⚠️ Deno requests run access to \"FOO\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-run to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions)", )); @@ -775,6 +775,36 @@ fn permissions_prompt_allow_all_lowercase_a() { }); } +itest!(deny_all_permission_args { + args: "run --deny-env --deny-read --deny-write --deny-ffi --deny-run --deny-sys --deny-net --deny-hrtime run/deny_all_permission_args.js", + output: "run/deny_all_permission_args.out", +}); + +itest!(deny_some_permission_args { + args: "run --allow-env --deny-env=FOO --allow-read --deny-read=/foo --allow-write --deny-write=/foo --allow-ffi --deny-ffi=/foo --allow-run --deny-run=foo --allow-sys --deny-sys=hostname --allow-net --deny-net=127.0.0.1 --allow-hrtime --deny-hrtime run/deny_some_permission_args.js", + output: "run/deny_some_permission_args.out", +}); + +#[test] +fn permissions_cache() { + TestContext::default() + .new_command() + .args_vec(["run", "--quiet", "run/permissions_cache.ts"]) + .with_pty(|mut console| { + console.expect(concat!( + "prompt\r\n", + "┌ ⚠️ Deno requests read access to \"foo\".\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", + "├ Run again with --allow-read to bypass this prompt.\r\n", + "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)", + )); + console.write_line_raw("y"); + console.expect("✅ Granted read access to \"foo\"."); + console.expect("granted"); + console.expect("prompt"); + }); +} + itest!(_091_use_define_for_class_fields { args: "run --check run/091_use_define_for_class_fields.ts", output: "run/091_use_define_for_class_fields.ts.out", @@ -2541,14 +2571,14 @@ mod permissions { .with_pty(|mut console| { console.expect(concat!( "┌ ⚠️ Deno requests read access to \"foo\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-read to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)", )); console.write_line_raw("y"); console.expect(concat!( "┌ ⚠️ Deno requests read access to \"bar\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-read to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)", )); @@ -2567,14 +2597,14 @@ mod permissions { .with_pty(|mut console| { console.expect(concat!( "┌ ⚠️ Deno requests read access to \"foo\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-read to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)", )); console.write_line_raw("y"); console.expect(concat!( "┌ ⚠️ Deno requests read access to \"bar\".\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-read to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)", )); @@ -2593,7 +2623,7 @@ mod permissions { .with_pty(|mut console| { console.expect(concat!( "┌ ⚠️ Deno requests read access.\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-read to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)", )); @@ -2615,7 +2645,7 @@ mod permissions { .with_pty(|mut console| { console.expect(concat!( "┌ ⚠️ Deno requests read access.\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-read to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions)", )); @@ -2756,7 +2786,7 @@ fn issue9750() { console.write_line_raw("yy"); console.expect(concat!( "┌ ⚠️ Deno requests env access.\r\n", - "├ Requested by `Deno.permissions.query()` API.\r\n", + "├ Requested by `Deno.permissions.request()` API.\r\n", "├ Run again with --allow-env to bypass this prompt.\r\n", "└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions)", )); diff --git a/cli/tests/testdata/run/deny_all_permission_args.js b/cli/tests/testdata/run/deny_all_permission_args.js new file mode 100644 index 000000000..b0ca864fb --- /dev/null +++ b/cli/tests/testdata/run/deny_all_permission_args.js @@ -0,0 +1,8 @@ +console.log(Deno.permissions.querySync({ name: "env" })); +console.log(Deno.permissions.querySync({ name: "read" })); +console.log(Deno.permissions.querySync({ name: "write" })); +console.log(Deno.permissions.querySync({ name: "ffi" })); +console.log(Deno.permissions.querySync({ name: "run" })); +console.log(Deno.permissions.querySync({ name: "sys" })); +console.log(Deno.permissions.querySync({ name: "net" })); +console.log(Deno.permissions.querySync({ name: "hrtime" })); diff --git a/cli/tests/testdata/run/deny_all_permission_args.out b/cli/tests/testdata/run/deny_all_permission_args.out new file mode 100644 index 000000000..2a5228d62 --- /dev/null +++ b/cli/tests/testdata/run/deny_all_permission_args.out @@ -0,0 +1,8 @@ +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "denied", onchange: null } diff --git a/cli/tests/testdata/run/deny_some_permission_args.js b/cli/tests/testdata/run/deny_some_permission_args.js new file mode 100644 index 000000000..320376b6f --- /dev/null +++ b/cli/tests/testdata/run/deny_some_permission_args.js @@ -0,0 +1,22 @@ +console.log(Deno.permissions.querySync({ name: "env" })); +console.log(Deno.permissions.querySync({ name: "env", variable: "FOO" })); +console.log(Deno.permissions.querySync({ name: "env", variable: "BAR" })); +console.log(Deno.permissions.querySync({ name: "read" })); +console.log(Deno.permissions.querySync({ name: "read", path: "/foo" })); +console.log(Deno.permissions.querySync({ name: "read", path: "/bar" })); +console.log(Deno.permissions.querySync({ name: "write" })); +console.log(Deno.permissions.querySync({ name: "write", path: "/foo" })); +console.log(Deno.permissions.querySync({ name: "write", path: "/bar" })); +console.log(Deno.permissions.querySync({ name: "ffi" })); +console.log(Deno.permissions.querySync({ name: "ffi", path: "/foo" })); +console.log(Deno.permissions.querySync({ name: "ffi", path: "/bar" })); +console.log(Deno.permissions.querySync({ name: "run" })); +console.log(Deno.permissions.querySync({ name: "run", command: "foo" })); +console.log(Deno.permissions.querySync({ name: "run", command: "bar" })); +console.log(Deno.permissions.querySync({ name: "sys" })); +console.log(Deno.permissions.querySync({ name: "sys", kind: "hostname" })); +console.log(Deno.permissions.querySync({ name: "sys", kind: "loadavg" })); +console.log(Deno.permissions.querySync({ name: "net" })); +console.log(Deno.permissions.querySync({ name: "net", host: "127.0.0.1" })); +console.log(Deno.permissions.querySync({ name: "net", host: "192.168.0.1" })); +console.log(Deno.permissions.querySync({ name: "hrtime" })); diff --git a/cli/tests/testdata/run/deny_some_permission_args.out b/cli/tests/testdata/run/deny_some_permission_args.out new file mode 100644 index 000000000..80c37159b --- /dev/null +++ b/cli/tests/testdata/run/deny_some_permission_args.out @@ -0,0 +1,22 @@ +PermissionStatus { state: "granted", onchange: null, partial: true } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "granted", onchange: null, partial: true } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "granted", onchange: null, partial: true } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "granted", onchange: null, partial: true } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "granted", onchange: null, partial: true } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "granted", onchange: null, partial: true } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "granted", onchange: null, partial: true } +PermissionStatus { state: "denied", onchange: null } +PermissionStatus { state: "granted", onchange: null } +PermissionStatus { state: "denied", onchange: null } diff --git a/cli/tests/testdata/run/permissions_cache.ts b/cli/tests/testdata/run/permissions_cache.ts new file mode 100644 index 000000000..c77ee0f36 --- /dev/null +++ b/cli/tests/testdata/run/permissions_cache.ts @@ -0,0 +1,5 @@ +const status = await Deno.permissions.query({ name: "read", path: "foo" }); +console.log(status.state); +status.onchange = () => console.log(status.state); +await Deno.permissions.request({ name: "read", path: "foo" }); // y +await Deno.permissions.revoke({ name: "read", path: "foo" }); diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index 1c8d9db63..436387eba 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -4403,9 +4403,12 @@ declare namespace Deno { * * @category Permissions */ - export type PermissionState = "granted" | "denied" | "prompt"; + export type PermissionState = + | "granted" + | "denied" + | "prompt"; - /** The permission descriptor for the `allow-run` permission, which controls + /** The permission descriptor for the `allow-run` and `deny-run` permissions, which controls * access to what sub-processes can be executed by Deno. The option `command` * allows scoping the permission to a specific executable. * @@ -4416,12 +4419,12 @@ declare namespace Deno { * @category Permissions */ export interface RunPermissionDescriptor { name: "run"; - /** The `allow-run` permission can be scoped to a specific executable, + /** An `allow-run` or `deny-run` permission can be scoped to a specific executable, * which would be relative to the start-up CWD of the Deno CLI. */ command?: string | URL; } - /** The permission descriptor for the `allow-read` permissions, which controls + /** The permission descriptor for the `allow-read` and `deny-read` permissions, which controls * access to reading resources from the local host. The option `path` allows * scoping the permission to a specific path (and if the path is a directory * any sub paths). @@ -4432,12 +4435,12 @@ declare namespace Deno { * @category Permissions */ export interface ReadPermissionDescriptor { name: "read"; - /** The `allow-read` permission can be scoped to a specific path (and if + /** An `allow-read` or `deny-read` permission can be scoped to a specific path (and if * the path is a directory, any sub paths). */ path?: string | URL; } - /** The permission descriptor for the `allow-write` permissions, which + /** The permission descriptor for the `allow-write` and `deny-write` permissions, which * controls access to writing to resources from the local host. The option * `path` allow scoping the permission to a specific path (and if the path is * a directory any sub paths). @@ -4448,12 +4451,12 @@ declare namespace Deno { * @category Permissions */ export interface WritePermissionDescriptor { name: "write"; - /** The `allow-write` permission can be scoped to a specific path (and if + /** An `allow-write` or `deny-write` permission can be scoped to a specific path (and if * the path is a directory, any sub paths). */ path?: string | URL; } - /** The permission descriptor for the `allow-net` permissions, which controls + /** The permission descriptor for the `allow-net` and `deny-net` permissions, which controls * access to opening network ports and connecting to remote hosts via the * network. The option `host` allows scoping the permission for outbound * connection to a specific host and port. @@ -4469,7 +4472,7 @@ declare namespace Deno { host?: string; } - /** The permission descriptor for the `allow-env` permissions, which controls + /** The permission descriptor for the `allow-env` and `deny-env` permissions, which controls * access to being able to read and write to the process environment variables * as well as access other information about the environment. The option * `variable` allows scoping the permission to a specific environment @@ -4482,7 +4485,7 @@ declare namespace Deno { variable?: string; } - /** The permission descriptor for the `allow-sys` permissions, which controls + /** The permission descriptor for the `allow-sys` and `deny-sys` permissions, which controls * access to sensitive host system information, which malicious code might * attempt to exploit. The option `kind` allows scoping the permission to a * specific piece of information. @@ -4502,7 +4505,7 @@ declare namespace Deno { | "gid"; } - /** The permission descriptor for the `allow-ffi` permissions, which controls + /** The permission descriptor for the `allow-ffi` and `deny-ffi` permissions, which controls * access to loading _foreign_ code and interfacing with it via the * [Foreign Function Interface API](https://deno.land/manual/runtime/ffi_api) * available in Deno. The option `path` allows scoping the permission to a @@ -4515,7 +4518,7 @@ declare namespace Deno { path?: string | URL; } - /** The permission descriptor for the `allow-hrtime` permission, which + /** The permission descriptor for the `allow-hrtime` and `deny-hrtime` permissions, which * controls if the runtime code has access to high resolution time. High * resolution time is considered sensitive information, because it can be used * by malicious code to gain information about the host that it might not @@ -4560,6 +4563,13 @@ declare namespace Deno { // deno-lint-ignore no-explicit-any onchange: ((this: PermissionStatus, ev: Event) => any) | null; readonly state: PermissionState; + /** + * Describes if permission is only granted partially, eg. an access + * might be granted to "/foo" directory, but denied for "/foo/bar". + * In such case this field will be set to `true` when querying for + * read permissions of "/foo" directory. + */ + readonly partial: boolean; addEventListener<K extends keyof PermissionStatusEventMap>( type: K, listener: ( |