mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
feat(permissions): add "--deny-*" flags (#19070)
This commit adds new "--deny-*" permission flags. These are complimentary to "--allow-*" flags. These flags can be used to restrict access to certain resources, even if they were granted using "--allow-*" flags or the "--allow-all" ("-A") flag. Eg. specifying "--allow-read --deny-read" will result in a permission error, while "--allow-read --deny-read=/etc" will allow read access to all FS but the "/etc" directory. Runtime permissions APIs ("Deno.permissions") were adjusted as well, mainly by adding, a new "PermissionStatus.partial" field. This field denotes that while permission might be granted to requested resource, it's only partial (ie. a "--deny-*" flag was specified that excludes some of the requested resources). Eg. specifying "--allow-read=foo/ --deny-read=foo/bar" and then querying for permissions like "Deno.permissions.query({ name: "read", path: "foo/" })" will return "PermissionStatus { state: "granted", onchange: null, partial: true }", denoting that some of the subpaths don't have read access. Closes #18804. --------- Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com> Co-authored-by: Nayeem Rahman <nayeemrmn99@gmail.com>
This commit is contained in:
parent
db287e216d
commit
6fb7e8d93b
21 changed files with 1805 additions and 1456 deletions
|
@ -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",
|
||||
|
@ -2124,6 +2306,17 @@ fn permission_args(app: Command) -> Command {
|
|||
.value_parser(value_parser!(PathBuf))
|
||||
.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")
|
||||
|
@ -2135,6 +2328,17 @@ fn permission_args(app: Command) -> Command {
|
|||
.value_parser(value_parser!(PathBuf))
|
||||
.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")
|
||||
|
@ -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(
|
||||
|
@ -2166,6 +2380,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")
|
||||
|
@ -2176,6 +2410,16 @@ fn permission_args(app: Command) -> Command {
|
|||
.help(ALLOW_SYS_HELP)
|
||||
.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")
|
||||
|
@ -2185,6 +2429,15 @@ fn permission_args(app: Command) -> Command {
|
|||
.value_name("PROGRAM_NAME")
|
||||
.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")
|
||||
|
@ -2196,12 +2449,29 @@ fn permission_args(app: Command) -> Command {
|
|||
.value_parser(value_parser!(PathBuf))
|
||||
.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')
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -3771,6 +4086,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"]);
|
||||
|
@ -3787,6 +4118,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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -4804,6 +5157,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;
|
||||
|
@ -4829,6 +5207,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![
|
||||
|
@ -4850,6 +5253,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 =
|
||||
|
@ -4867,6 +5287,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![
|
||||
|
@ -4888,6 +5325,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 =
|
||||
|
@ -4901,6 +5355,19 @@ mod tests {
|
|||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[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"]);
|
||||
|
@ -4917,6 +5384,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 =
|
||||
|
@ -4934,6 +5417,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![
|
||||
|
@ -4955,6 +5455,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 =
|
||||
|
@ -4979,6 +5500,29 @@ mod tests {
|
|||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[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![
|
||||
|
@ -5850,6 +6394,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![
|
||||
|
@ -5882,6 +6455,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![
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)",
|
||||
));
|
||||
|
|
8
cli/tests/testdata/run/deny_all_permission_args.js
vendored
Normal file
8
cli/tests/testdata/run/deny_all_permission_args.js
vendored
Normal file
|
@ -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" }));
|
8
cli/tests/testdata/run/deny_all_permission_args.out
vendored
Normal file
8
cli/tests/testdata/run/deny_all_permission_args.out
vendored
Normal file
|
@ -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 }
|
22
cli/tests/testdata/run/deny_some_permission_args.js
vendored
Normal file
22
cli/tests/testdata/run/deny_some_permission_args.js
vendored
Normal file
|
@ -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" }));
|
22
cli/tests/testdata/run/deny_some_permission_args.out
vendored
Normal file
22
cli/tests/testdata/run/deny_some_permission_args.out
vendored
Normal file
|
@ -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 }
|
5
cli/tests/testdata/run/permissions_cache.ts
vendored
Normal file
5
cli/tests/testdata/run/permissions_cache.ts
vendored
Normal file
|
@ -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" });
|
34
cli/tsc/dts/lib.deno.ns.d.ts
vendored
34
cli/tsc/dts/lib.deno.ns.d.ts
vendored
|
@ -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: (
|
||||
|
|
|
@ -289,7 +289,7 @@ where
|
|||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
};
|
||||
|
||||
let symbol = PtrSymbol::new(pointer, &def)?;
|
||||
|
@ -389,7 +389,7 @@ where
|
|||
{
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
};
|
||||
|
||||
let symbol = PtrSymbol::new(pointer, &def)?;
|
||||
|
|
|
@ -546,7 +546,7 @@ where
|
|||
{
|
||||
check_unstable(state, "Deno.UnsafeCallback");
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
let v8_value = cb.v8_value;
|
||||
let cb = v8::Local::<v8::Function>::try_from(v8_value)?;
|
||||
|
|
|
@ -144,7 +144,7 @@ where
|
|||
|
||||
check_unstable(state, "Deno.dlopen");
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(Some(&PathBuf::from(&path)))?;
|
||||
permissions.check_partial(Some(&PathBuf::from(&path)))?;
|
||||
|
||||
let lib = Library::open(&path).map_err(|e| {
|
||||
dlopen::Error::OpeningLibraryError(std::io::Error::new(
|
||||
|
|
|
@ -64,7 +64,7 @@ pub fn check_unstable2(state: &Rc<RefCell<OpState>>, api_name: &str) {
|
|||
}
|
||||
|
||||
pub trait FfiPermissions {
|
||||
fn check(&mut self, path: Option<&Path>) -> Result<(), AnyError>;
|
||||
fn check_partial(&mut self, path: Option<&Path>) -> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
pub(crate) type PendingFfiAsyncWork = Box<dyn FnOnce()>;
|
||||
|
|
|
@ -24,7 +24,7 @@ where
|
|||
{
|
||||
check_unstable(state, "Deno.UnsafePointer#create");
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
Ok(ptr_number as *mut c_void)
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ where
|
|||
{
|
||||
check_unstable(state, "Deno.UnsafePointer#equals");
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
Ok(a == b)
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ where
|
|||
{
|
||||
check_unstable(state, "Deno.UnsafePointer#of");
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
Ok(buf as *mut c_void)
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ where
|
|||
{
|
||||
check_unstable(state, "Deno.UnsafePointer#offset");
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid pointer to offset, pointer is null"));
|
||||
|
@ -99,7 +99,7 @@ where
|
|||
{
|
||||
check_unstable(state, "Deno.UnsafePointer#value");
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
let outptr = out.as_ptr() as *mut usize;
|
||||
let length = out.len();
|
||||
|
@ -129,7 +129,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getArrayBuffer");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid ArrayBuffer pointer, pointer is null"));
|
||||
|
@ -164,7 +164,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#copyInto");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if src.is_null() {
|
||||
Err(type_error("Invalid ArrayBuffer pointer, pointer is null"))
|
||||
|
@ -197,7 +197,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getCString");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid CString pointer, pointer is null"));
|
||||
|
@ -227,7 +227,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getBool");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid bool pointer, pointer is null"));
|
||||
|
@ -249,7 +249,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getUint8");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid u8 pointer, pointer is null"));
|
||||
|
@ -273,7 +273,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getInt8");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid i8 pointer, pointer is null"));
|
||||
|
@ -297,7 +297,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getUint16");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid u16 pointer, pointer is null"));
|
||||
|
@ -321,7 +321,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getInt16");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid i16 pointer, pointer is null"));
|
||||
|
@ -345,7 +345,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getUint32");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid u32 pointer, pointer is null"));
|
||||
|
@ -367,7 +367,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getInt32");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid i32 pointer, pointer is null"));
|
||||
|
@ -390,7 +390,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getBigUint64");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
let outptr = out.as_mut_ptr() as *mut u64;
|
||||
|
||||
|
@ -425,7 +425,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getBigUint64");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
let outptr = out.as_mut_ptr() as *mut i64;
|
||||
|
||||
|
@ -458,7 +458,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getFloat32");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid f32 pointer, pointer is null"));
|
||||
|
@ -480,7 +480,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getFloat64");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid f64 pointer, pointer is null"));
|
||||
|
@ -502,7 +502,7 @@ where
|
|||
check_unstable(state, "Deno.UnsafePointerView#getPointer");
|
||||
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(None)?;
|
||||
permissions.check_partial(None)?;
|
||||
|
||||
if ptr.is_null() {
|
||||
return Err(type_error("Invalid pointer pointer, pointer is null"));
|
||||
|
|
|
@ -23,7 +23,8 @@ use std::path::Path;
|
|||
use std::rc::Rc;
|
||||
|
||||
pub trait FsPermissions {
|
||||
fn check_read(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_read(&mut self, path: &Path, api_name: &str)
|
||||
-> Result<(), AnyError>;
|
||||
fn check_read_all(&mut self, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_read_blind(
|
||||
&mut self,
|
||||
|
@ -31,7 +32,16 @@ pub trait FsPermissions {
|
|||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_write(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_write_partial(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_write_all(&mut self, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write_blind(
|
||||
&mut self,
|
||||
|
|
|
@ -294,9 +294,16 @@ where
|
|||
|
||||
let fs = {
|
||||
let mut state = state.borrow_mut();
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.remove()")?;
|
||||
if recursive {
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_write(&path, "Deno.remove()")?;
|
||||
} else {
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_write_partial(&path, "Deno.remove()")?;
|
||||
}
|
||||
|
||||
state.borrow::<FileSystemRc>().clone()
|
||||
};
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ mod startup_snapshot {
|
|||
}
|
||||
|
||||
impl deno_ffi::FfiPermissions for Permissions {
|
||||
fn check(
|
||||
fn check_partial(
|
||||
&mut self,
|
||||
_path: Option<&Path>,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
|
@ -204,6 +204,14 @@ mod startup_snapshot {
|
|||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_write_partial(
|
||||
&mut self,
|
||||
_path: &Path,
|
||||
_api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
||||
fn check_write_all(&mut self, _api_name: &str) -> Result<(), AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ const illegalConstructorKey = Symbol("illegalConstructorKey");
|
|||
* @typedef StatusCacheValue
|
||||
* @property {PermissionState} state
|
||||
* @property {PermissionStatus} status
|
||||
* @property {boolean} partial
|
||||
*/
|
||||
|
||||
/** @type {ReadonlyArray<"read" | "write" | "net" | "env" | "sys" | "run" | "ffi" | "hrtime">} */
|
||||
|
@ -69,27 +70,32 @@ function opRequest(desc) {
|
|||
}
|
||||
|
||||
class PermissionStatus extends EventTarget {
|
||||
/** @type {{ state: Deno.PermissionState }} */
|
||||
#state;
|
||||
/** @type {{ state: Deno.PermissionState, partial: boolean }} */
|
||||
#status;
|
||||
|
||||
/** @type {((this: PermissionStatus, event: Event) => any) | null} */
|
||||
onchange = null;
|
||||
|
||||
/** @returns {Deno.PermissionState} */
|
||||
get state() {
|
||||
return this.#state.state;
|
||||
return this.#status.state;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
get partial() {
|
||||
return this.#status.partial;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ state: Deno.PermissionState }} state
|
||||
* @param {{ state: Deno.PermissionState, partial: boolean }} status
|
||||
* @param {unknown} key
|
||||
*/
|
||||
constructor(state = null, key = null) {
|
||||
constructor(status = null, key = null) {
|
||||
if (key != illegalConstructorKey) {
|
||||
throw new TypeError("Illegal constructor.");
|
||||
}
|
||||
super();
|
||||
this.#state = state;
|
||||
this.#status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,9 +112,9 @@ class PermissionStatus extends EventTarget {
|
|||
}
|
||||
|
||||
[SymbolFor("Deno.privateCustomInspect")](inspect) {
|
||||
return `${this.constructor.name} ${
|
||||
inspect({ state: this.state, onchange: this.onchange })
|
||||
}`;
|
||||
const object = { state: this.state, onchange: this.onchange };
|
||||
if (this.partial) object.partial = this.partial;
|
||||
return `${this.constructor.name} ${inspect(object)}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,10 +123,10 @@ const statusCache = new SafeMap();
|
|||
|
||||
/**
|
||||
* @param {Deno.PermissionDescriptor} desc
|
||||
* @param {Deno.PermissionState} state
|
||||
* @param {{ state: Deno.PermissionState, partial: boolean }} rawStatus
|
||||
* @returns {PermissionStatus}
|
||||
*/
|
||||
function cache(desc, state) {
|
||||
function cache(desc, rawStatus) {
|
||||
let { name: key } = desc;
|
||||
if (
|
||||
(desc.name === "read" || desc.name === "write" || desc.name === "ffi") &&
|
||||
|
@ -139,18 +145,24 @@ function cache(desc, state) {
|
|||
key += "$";
|
||||
}
|
||||
if (MapPrototypeHas(statusCache, key)) {
|
||||
const status = MapPrototypeGet(statusCache, key);
|
||||
if (status.state !== state) {
|
||||
status.state = state;
|
||||
status.status.dispatchEvent(new Event("change", { cancelable: false }));
|
||||
const cachedObj = MapPrototypeGet(statusCache, key);
|
||||
if (
|
||||
cachedObj.state !== rawStatus.state ||
|
||||
cachedObj.partial !== rawStatus.partial
|
||||
) {
|
||||
cachedObj.state = rawStatus.state;
|
||||
cachedObj.partial = rawStatus.partial;
|
||||
cachedObj.status.dispatchEvent(
|
||||
new Event("change", { cancelable: false }),
|
||||
);
|
||||
}
|
||||
return status.status;
|
||||
return cachedObj.status;
|
||||
}
|
||||
/** @type {{ state: Deno.PermissionState; status?: PermissionStatus }} */
|
||||
const status = { state };
|
||||
status.status = new PermissionStatus(status, illegalConstructorKey);
|
||||
MapPrototypeSet(statusCache, key, status);
|
||||
return status.status;
|
||||
/** @type {{ state: Deno.PermissionState, partial: boolean, status?: PermissionStatus }} */
|
||||
const obj = rawStatus;
|
||||
obj.status = new PermissionStatus(obj, illegalConstructorKey);
|
||||
MapPrototypeSet(statusCache, key, obj);
|
||||
return obj.status;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,8 +212,8 @@ class Permissions {
|
|||
|
||||
formDescriptor(desc);
|
||||
|
||||
const state = opQuery(desc);
|
||||
return cache(desc, state);
|
||||
const status = opQuery(desc);
|
||||
return cache(desc, status);
|
||||
}
|
||||
|
||||
revoke(desc) {
|
||||
|
@ -221,8 +233,8 @@ class Permissions {
|
|||
|
||||
formDescriptor(desc);
|
||||
|
||||
const state = opRevoke(desc);
|
||||
return cache(desc, state);
|
||||
const status = opRevoke(desc);
|
||||
return cache(desc, status);
|
||||
}
|
||||
|
||||
request(desc) {
|
||||
|
@ -242,8 +254,8 @@ class Permissions {
|
|||
|
||||
formDescriptor(desc);
|
||||
|
||||
const state = opRequest(desc);
|
||||
return cache(desc, state);
|
||||
const status = opRequest(desc);
|
||||
return cache(desc, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::permissions::parse_sys_kind;
|
||||
use crate::permissions::PermissionState;
|
||||
use crate::permissions::PermissionsContainer;
|
||||
use deno_core::error::custom_error;
|
||||
use deno_core::error::uri_error;
|
||||
|
@ -9,6 +10,7 @@ use deno_core::op;
|
|||
use deno_core::url;
|
||||
use deno_core::OpState;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::path::Path;
|
||||
|
||||
deno_core::extension!(
|
||||
|
@ -30,11 +32,30 @@ pub struct PermissionArgs {
|
|||
command: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct PermissionStatus {
|
||||
state: String,
|
||||
partial: bool,
|
||||
}
|
||||
|
||||
impl From<PermissionState> for PermissionStatus {
|
||||
fn from(state: PermissionState) -> Self {
|
||||
PermissionStatus {
|
||||
state: if state == PermissionState::GrantedPartial {
|
||||
PermissionState::Granted.to_string()
|
||||
} else {
|
||||
state.to_string()
|
||||
},
|
||||
partial: state == PermissionState::GrantedPartial,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_query_permission(
|
||||
state: &mut OpState,
|
||||
args: PermissionArgs,
|
||||
) -> Result<String, AnyError> {
|
||||
) -> Result<PermissionStatus, AnyError> {
|
||||
let permissions = state.borrow::<PermissionsContainer>().0.lock();
|
||||
let path = args.path.as_deref();
|
||||
let perm = match args.name.as_ref() {
|
||||
|
@ -61,14 +82,14 @@ pub fn op_query_permission(
|
|||
))
|
||||
}
|
||||
};
|
||||
Ok(perm.to_string())
|
||||
Ok(PermissionStatus::from(perm))
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_revoke_permission(
|
||||
state: &mut OpState,
|
||||
args: PermissionArgs,
|
||||
) -> Result<String, AnyError> {
|
||||
) -> Result<PermissionStatus, AnyError> {
|
||||
let mut permissions = state.borrow_mut::<PermissionsContainer>().0.lock();
|
||||
let path = args.path.as_deref();
|
||||
let perm = match args.name.as_ref() {
|
||||
|
@ -95,14 +116,14 @@ pub fn op_revoke_permission(
|
|||
))
|
||||
}
|
||||
};
|
||||
Ok(perm.to_string())
|
||||
Ok(PermissionStatus::from(perm))
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_request_permission(
|
||||
state: &mut OpState,
|
||||
args: PermissionArgs,
|
||||
) -> Result<String, AnyError> {
|
||||
) -> Result<PermissionStatus, AnyError> {
|
||||
let mut permissions = state.borrow_mut::<PermissionsContainer>().0.lock();
|
||||
let path = args.path.as_deref();
|
||||
let perm = match args.name.as_ref() {
|
||||
|
@ -129,7 +150,7 @@ pub fn op_request_permission(
|
|||
))
|
||||
}
|
||||
};
|
||||
Ok(perm.to_string())
|
||||
Ok(PermissionStatus::from(perm))
|
||||
}
|
||||
|
||||
fn parse_host(host_str: &str) -> Result<(String, Option<u16>), AnyError> {
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue