mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
refactor: improve node permission checks (#26028)
Does less work when requesting permissions with `-A`
This commit is contained in:
parent
f288730c38
commit
2de4faa483
11 changed files with 207 additions and 121 deletions
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -32,18 +33,19 @@ pub type CliByonmNpmResolver = ByonmNpmResolver<CliDenoResolverFs>;
|
||||||
struct CliByonmWrapper(Arc<CliByonmNpmResolver>);
|
struct CliByonmWrapper(Arc<CliByonmNpmResolver>);
|
||||||
|
|
||||||
impl NodeRequireResolver for CliByonmWrapper {
|
impl NodeRequireResolver for CliByonmWrapper {
|
||||||
fn ensure_read_permission(
|
fn ensure_read_permission<'a>(
|
||||||
&self,
|
&self,
|
||||||
permissions: &mut dyn NodePermissions,
|
permissions: &mut dyn NodePermissions,
|
||||||
path: &Path,
|
path: &'a Path,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<Cow<'a, Path>, AnyError> {
|
||||||
if !path
|
if !path
|
||||||
.components()
|
.components()
|
||||||
.any(|c| c.as_os_str().to_ascii_lowercase() == "node_modules")
|
.any(|c| c.as_os_str().to_ascii_lowercase() == "node_modules")
|
||||||
{
|
{
|
||||||
_ = permissions.check_read_path(path)?;
|
permissions.check_read_path(path)
|
||||||
|
} else {
|
||||||
|
Ok(Cow::Borrowed(path))
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -593,11 +594,11 @@ impl NpmResolver for ManagedCliNpmResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeRequireResolver for ManagedCliNpmResolver {
|
impl NodeRequireResolver for ManagedCliNpmResolver {
|
||||||
fn ensure_read_permission(
|
fn ensure_read_permission<'a>(
|
||||||
&self,
|
&self,
|
||||||
permissions: &mut dyn NodePermissions,
|
permissions: &mut dyn NodePermissions,
|
||||||
path: &Path,
|
path: &'a Path,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<Cow<'a, Path>, AnyError> {
|
||||||
self.fs_resolver.ensure_read_permission(permissions, path)
|
self.fs_resolver.ensure_read_permission(permissions, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
pub mod bin_entries;
|
pub mod bin_entries;
|
||||||
pub mod lifecycle_scripts;
|
pub mod lifecycle_scripts;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -62,11 +63,12 @@ pub trait NpmPackageFsResolver: Send + Sync {
|
||||||
|
|
||||||
async fn cache_packages(&self) -> Result<(), AnyError>;
|
async fn cache_packages(&self) -> Result<(), AnyError>;
|
||||||
|
|
||||||
fn ensure_read_permission(
|
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||||
|
fn ensure_read_permission<'a>(
|
||||||
&self,
|
&self,
|
||||||
permissions: &mut dyn NodePermissions,
|
permissions: &mut dyn NodePermissions,
|
||||||
path: &Path,
|
path: &'a Path,
|
||||||
) -> Result<(), AnyError>;
|
) -> Result<Cow<'a, Path>, AnyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -85,11 +87,15 @@ impl RegistryReadPermissionChecker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_registry_read_permission(
|
pub fn ensure_registry_read_permission<'a>(
|
||||||
&self,
|
&self,
|
||||||
permissions: &mut dyn NodePermissions,
|
permissions: &mut dyn NodePermissions,
|
||||||
path: &Path,
|
path: &'a Path,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<Cow<'a, Path>, AnyError> {
|
||||||
|
if permissions.query_read_all() {
|
||||||
|
return Ok(Cow::Borrowed(path)); // skip permissions checks below
|
||||||
|
}
|
||||||
|
|
||||||
// allow reading if it's in the node_modules
|
// allow reading if it's in the node_modules
|
||||||
let is_path_in_node_modules = path.starts_with(&self.registry_path)
|
let is_path_in_node_modules = path.starts_with(&self.registry_path)
|
||||||
&& path
|
&& path
|
||||||
|
@ -118,20 +124,20 @@ impl RegistryReadPermissionChecker {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let Some(registry_path_canon) = canonicalize(&self.registry_path)? else {
|
if let Some(registry_path_canon) = canonicalize(&self.registry_path)? {
|
||||||
return Ok(()); // not exists, allow reading
|
if let Some(path_canon) = canonicalize(path)? {
|
||||||
};
|
if path_canon.starts_with(registry_path_canon) {
|
||||||
let Some(path_canon) = canonicalize(path)? else {
|
return Ok(Cow::Owned(path_canon));
|
||||||
return Ok(()); // not exists, allow reading
|
}
|
||||||
};
|
} else if path.starts_with(registry_path_canon)
|
||||||
|
|| path.starts_with(&self.registry_path)
|
||||||
if path_canon.starts_with(registry_path_canon) {
|
{
|
||||||
return Ok(());
|
return Ok(Cow::Borrowed(path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = permissions.check_read_path(path)?;
|
permissions.check_read_path(path)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,11 +183,11 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_read_permission(
|
fn ensure_read_permission<'a>(
|
||||||
&self,
|
&self,
|
||||||
permissions: &mut dyn NodePermissions,
|
permissions: &mut dyn NodePermissions,
|
||||||
path: &Path,
|
path: &'a Path,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<Cow<'a, Path>, AnyError> {
|
||||||
self
|
self
|
||||||
.registry_read_permission_checker
|
.registry_read_permission_checker
|
||||||
.ensure_registry_read_permission(permissions, path)
|
.ensure_registry_read_permission(permissions, path)
|
||||||
|
|
|
@ -257,11 +257,11 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_read_permission(
|
fn ensure_read_permission<'a>(
|
||||||
&self,
|
&self,
|
||||||
permissions: &mut dyn NodePermissions,
|
permissions: &mut dyn NodePermissions,
|
||||||
path: &Path,
|
path: &'a Path,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<Cow<'a, Path>, AnyError> {
|
||||||
self
|
self
|
||||||
.registry_read_permission_checker
|
.registry_read_permission_checker
|
||||||
.ensure_registry_read_permission(permissions, path)
|
.ensure_registry_read_permission(permissions, path)
|
||||||
|
|
|
@ -66,6 +66,7 @@ pub trait NodePermissions {
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
) -> Result<Cow<'a, Path>, AnyError>;
|
) -> Result<Cow<'a, Path>, AnyError>;
|
||||||
|
fn query_read_all(&mut self) -> bool;
|
||||||
fn check_sys(&mut self, kind: &str, api_name: &str) -> Result<(), AnyError>;
|
fn check_sys(&mut self, kind: &str, api_name: &str) -> Result<(), AnyError>;
|
||||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||||
fn check_write_with_api_name(
|
fn check_write_with_api_name(
|
||||||
|
@ -103,6 +104,10 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
|
||||||
deno_permissions::PermissionsContainer::check_read_path(self, path, None)
|
deno_permissions::PermissionsContainer::check_read_path(self, path, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn query_read_all(&mut self) -> bool {
|
||||||
|
deno_permissions::PermissionsContainer::query_read_all(self)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn check_write_with_api_name(
|
fn check_write_with_api_name(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -124,11 +129,12 @@ pub type NodeRequireResolverRc =
|
||||||
deno_fs::sync::MaybeArc<dyn NodeRequireResolver>;
|
deno_fs::sync::MaybeArc<dyn NodeRequireResolver>;
|
||||||
|
|
||||||
pub trait NodeRequireResolver: std::fmt::Debug + MaybeSend + MaybeSync {
|
pub trait NodeRequireResolver: std::fmt::Debug + MaybeSend + MaybeSync {
|
||||||
fn ensure_read_permission(
|
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||||
|
fn ensure_read_permission<'a>(
|
||||||
&self,
|
&self,
|
||||||
permissions: &mut dyn NodePermissions,
|
permissions: &mut dyn NodePermissions,
|
||||||
path: &Path,
|
path: &'a Path,
|
||||||
) -> Result<(), AnyError>;
|
) -> Result<Cow<'a, Path>, AnyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static NODE_ENV_VAR_ALLOWLIST: Lazy<HashSet<String>> = Lazy::new(|| {
|
pub static NODE_ENV_VAR_ALLOWLIST: Lazy<HashSet<String>> = Lazy::new(|| {
|
||||||
|
|
|
@ -15,6 +15,7 @@ use deno_path_util::normalize_path;
|
||||||
use node_resolver::NodeModuleKind;
|
use node_resolver::NodeModuleKind;
|
||||||
use node_resolver::NodeResolutionMode;
|
use node_resolver::NodeResolutionMode;
|
||||||
use node_resolver::REQUIRE_CONDITIONS;
|
use node_resolver::REQUIRE_CONDITIONS;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -25,10 +26,11 @@ use crate::NodeRequireResolverRc;
|
||||||
use crate::NodeResolverRc;
|
use crate::NodeResolverRc;
|
||||||
use crate::NpmResolverRc;
|
use crate::NpmResolverRc;
|
||||||
|
|
||||||
fn ensure_read_permission<P>(
|
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||||
|
fn ensure_read_permission<'a, P>(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
file_path: &Path,
|
file_path: &'a Path,
|
||||||
) -> Result<(), AnyError>
|
) -> Result<Cow<'a, Path>, AnyError>
|
||||||
where
|
where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
|
@ -107,7 +109,7 @@ where
|
||||||
deno_path_util::normalize_path(current_dir.join(from))
|
deno_path_util::normalize_path(current_dir.join(from))
|
||||||
};
|
};
|
||||||
|
|
||||||
ensure_read_permission::<P>(state, &from)?;
|
let from = ensure_read_permission::<P>(state, &from)?;
|
||||||
|
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
// return root node_modules when path is 'D:\\'.
|
// return root node_modules when path is 'D:\\'.
|
||||||
|
@ -129,7 +131,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut paths = Vec::with_capacity(from.components().count());
|
let mut paths = Vec::with_capacity(from.components().count());
|
||||||
let mut current_path = from.as_path();
|
let mut current_path = from.as_ref();
|
||||||
let mut maybe_parent = Some(current_path);
|
let mut maybe_parent = Some(current_path);
|
||||||
while let Some(parent) = maybe_parent {
|
while let Some(parent) = maybe_parent {
|
||||||
if !parent.ends_with("node_modules") {
|
if !parent.ends_with("node_modules") {
|
||||||
|
@ -267,7 +269,7 @@ where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
let path = PathBuf::from(path);
|
let path = PathBuf::from(path);
|
||||||
ensure_read_permission::<P>(state, &path)?;
|
let path = ensure_read_permission::<P>(state, &path)?;
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
if let Ok(metadata) = fs.stat_sync(&path) {
|
if let Ok(metadata) = fs.stat_sync(&path) {
|
||||||
if metadata.is_file {
|
if metadata.is_file {
|
||||||
|
@ -290,7 +292,7 @@ where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
let path = PathBuf::from(request);
|
let path = PathBuf::from(request);
|
||||||
ensure_read_permission::<P>(state, &path)?;
|
let path = ensure_read_permission::<P>(state, &path)?;
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
let canonicalized_path =
|
let canonicalized_path =
|
||||||
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
||||||
|
@ -362,7 +364,7 @@ where
|
||||||
if parent_id == "<repl>" || parent_id == "internal/preload" {
|
if parent_id == "<repl>" || parent_id == "internal/preload" {
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
if let Ok(cwd) = fs.cwd() {
|
if let Ok(cwd) = fs.cwd() {
|
||||||
ensure_read_permission::<P>(state, &cwd)?;
|
let cwd = ensure_read_permission::<P>(state, &cwd)?;
|
||||||
return Ok(Some(cwd.to_string_lossy().into_owned()));
|
return Ok(Some(cwd.to_string_lossy().into_owned()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,7 +445,7 @@ where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
let file_path = PathBuf::from(file_path);
|
let file_path = PathBuf::from(file_path);
|
||||||
ensure_read_permission::<P>(state, &file_path)?;
|
let file_path = ensure_read_permission::<P>(state, &file_path)?;
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
Ok(fs.read_text_file_lossy_sync(&file_path, None)?)
|
Ok(fs.read_text_file_lossy_sync(&file_path, None)?)
|
||||||
}
|
}
|
||||||
|
@ -528,7 +530,7 @@ where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
let filename = PathBuf::from(filename);
|
let filename = PathBuf::from(filename);
|
||||||
ensure_read_permission::<P>(state, filename.parent().unwrap())?;
|
// permissions: allow reading the closest package.json files
|
||||||
let node_resolver = state.borrow::<NodeResolverRc>().clone();
|
let node_resolver = state.borrow::<NodeResolverRc>().clone();
|
||||||
node_resolver
|
node_resolver
|
||||||
.get_closest_package_json_from_path(&filename)
|
.get_closest_package_json_from_path(&filename)
|
||||||
|
@ -567,7 +569,7 @@ where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
let referrer_path = PathBuf::from(&referrer_filename);
|
let referrer_path = PathBuf::from(&referrer_filename);
|
||||||
ensure_read_permission::<P>(state, &referrer_path)?;
|
let referrer_path = ensure_read_permission::<P>(state, &referrer_path)?;
|
||||||
let node_resolver = state.borrow::<NodeResolverRc>();
|
let node_resolver = state.borrow::<NodeResolverRc>();
|
||||||
let Some(pkg) =
|
let Some(pkg) =
|
||||||
node_resolver.get_closest_package_json_from_path(&referrer_path)?
|
node_resolver.get_closest_package_json_from_path(&referrer_path)?
|
||||||
|
|
|
@ -7,6 +7,7 @@ use deno_core::url::Url;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_fs::FileSystemRc;
|
use deno_fs::FileSystemRc;
|
||||||
use node_resolver::NodeResolution;
|
use node_resolver::NodeResolution;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -14,10 +15,11 @@ use crate::NodePermissions;
|
||||||
use crate::NodeRequireResolverRc;
|
use crate::NodeRequireResolverRc;
|
||||||
use crate::NodeResolverRc;
|
use crate::NodeResolverRc;
|
||||||
|
|
||||||
fn ensure_read_permission<P>(
|
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||||
|
fn ensure_read_permission<'a, P>(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
file_path: &Path,
|
file_path: &'a Path,
|
||||||
) -> Result<(), AnyError>
|
) -> Result<Cow<'a, Path>, AnyError>
|
||||||
where
|
where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
|
@ -47,7 +49,7 @@ where
|
||||||
"Relative path entries must start with '.' or '..'",
|
"Relative path entries must start with '.' or '..'",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ensure_read_permission::<P>(state, &path)?;
|
let path = ensure_read_permission::<P>(state, &path)?;
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
let canonicalized_path =
|
let canonicalized_path =
|
||||||
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
||||||
|
@ -57,7 +59,7 @@ where
|
||||||
let url_path = url
|
let url_path = url
|
||||||
.to_file_path()
|
.to_file_path()
|
||||||
.map_err(|e| generic_error(format!("URL to Path-String: {:#?}", e)))?;
|
.map_err(|e| generic_error(format!("URL to Path-String: {:#?}", e)))?;
|
||||||
ensure_read_permission::<P>(state, &url_path)?;
|
let url_path = ensure_read_permission::<P>(state, &url_path)?;
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
if !fs.exists_sync(&url_path) {
|
if !fs.exists_sync(&url_path) {
|
||||||
return Err(generic_error(format!("File not found [{:?}]", url_path)));
|
return Err(generic_error(format!("File not found [{:?}]", url_path)));
|
||||||
|
|
|
@ -2285,6 +2285,11 @@ impl PermissionsContainer {
|
||||||
self.inner.lock().read.check_all(Some(api_name))
|
self.inner.lock().read.check_all(Some(api_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn query_read_all(&self) -> bool {
|
||||||
|
self.inner.lock().read.query(None) == PermissionState::Granted
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn check_write(
|
pub fn check_write(
|
||||||
|
@ -2614,8 +2619,13 @@ impl PermissionsContainer {
|
||||||
&self,
|
&self,
|
||||||
path: Option<&str>,
|
path: Option<&str>,
|
||||||
) -> Result<PermissionState, AnyError> {
|
) -> Result<PermissionState, AnyError> {
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let permission = &inner.read;
|
||||||
|
if permission.is_allow_all() {
|
||||||
|
return Ok(PermissionState::Granted);
|
||||||
|
}
|
||||||
Ok(
|
Ok(
|
||||||
self.inner.lock().read.query(
|
permission.query(
|
||||||
path
|
path
|
||||||
.map(|path| {
|
.map(|path| {
|
||||||
Result::<_, AnyError>::Ok(
|
Result::<_, AnyError>::Ok(
|
||||||
|
@ -2633,8 +2643,13 @@ impl PermissionsContainer {
|
||||||
&self,
|
&self,
|
||||||
path: Option<&str>,
|
path: Option<&str>,
|
||||||
) -> Result<PermissionState, AnyError> {
|
) -> Result<PermissionState, AnyError> {
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let permission = &inner.write;
|
||||||
|
if permission.is_allow_all() {
|
||||||
|
return Ok(PermissionState::Granted);
|
||||||
|
}
|
||||||
Ok(
|
Ok(
|
||||||
self.inner.lock().write.query(
|
permission.query(
|
||||||
path
|
path
|
||||||
.map(|path| {
|
.map(|path| {
|
||||||
Result::<_, AnyError>::Ok(
|
Result::<_, AnyError>::Ok(
|
||||||
|
@ -2652,8 +2667,13 @@ impl PermissionsContainer {
|
||||||
&self,
|
&self,
|
||||||
host: Option<&str>,
|
host: Option<&str>,
|
||||||
) -> Result<PermissionState, AnyError> {
|
) -> Result<PermissionState, AnyError> {
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let permission = &inner.net;
|
||||||
|
if permission.is_allow_all() {
|
||||||
|
return Ok(PermissionState::Granted);
|
||||||
|
}
|
||||||
Ok(
|
Ok(
|
||||||
self.inner.lock().net.query(
|
permission.query(
|
||||||
match host {
|
match host {
|
||||||
None => None,
|
None => None,
|
||||||
Some(h) => Some(self.descriptor_parser.parse_net_descriptor(h)?),
|
Some(h) => Some(self.descriptor_parser.parse_net_descriptor(h)?),
|
||||||
|
@ -2665,7 +2685,12 @@ impl PermissionsContainer {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn query_env(&self, var: Option<&str>) -> PermissionState {
|
pub fn query_env(&self, var: Option<&str>) -> PermissionState {
|
||||||
self.inner.lock().env.query(var)
|
let inner = self.inner.lock();
|
||||||
|
let permission = &inner.env;
|
||||||
|
if permission.is_allow_all() {
|
||||||
|
return PermissionState::Granted;
|
||||||
|
}
|
||||||
|
permission.query(var)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -2673,8 +2698,13 @@ impl PermissionsContainer {
|
||||||
&self,
|
&self,
|
||||||
kind: Option<&str>,
|
kind: Option<&str>,
|
||||||
) -> Result<PermissionState, AnyError> {
|
) -> Result<PermissionState, AnyError> {
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let permission = &inner.sys;
|
||||||
|
if permission.is_allow_all() {
|
||||||
|
return Ok(PermissionState::Granted);
|
||||||
|
}
|
||||||
Ok(
|
Ok(
|
||||||
self.inner.lock().sys.query(
|
permission.query(
|
||||||
kind
|
kind
|
||||||
.map(|kind| self.descriptor_parser.parse_sys_descriptor(kind))
|
.map(|kind| self.descriptor_parser.parse_sys_descriptor(kind))
|
||||||
.transpose()?
|
.transpose()?
|
||||||
|
@ -2688,8 +2718,13 @@ impl PermissionsContainer {
|
||||||
&self,
|
&self,
|
||||||
cmd: Option<&str>,
|
cmd: Option<&str>,
|
||||||
) -> Result<PermissionState, AnyError> {
|
) -> Result<PermissionState, AnyError> {
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let permission = &inner.run;
|
||||||
|
if permission.is_allow_all() {
|
||||||
|
return Ok(PermissionState::Granted);
|
||||||
|
}
|
||||||
Ok(
|
Ok(
|
||||||
self.inner.lock().run.query(
|
permission.query(
|
||||||
cmd
|
cmd
|
||||||
.map(|request| self.descriptor_parser.parse_run_query(request))
|
.map(|request| self.descriptor_parser.parse_run_query(request))
|
||||||
.transpose()?
|
.transpose()?
|
||||||
|
@ -2703,8 +2738,13 @@ impl PermissionsContainer {
|
||||||
&self,
|
&self,
|
||||||
path: Option<&str>,
|
path: Option<&str>,
|
||||||
) -> Result<PermissionState, AnyError> {
|
) -> Result<PermissionState, AnyError> {
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let permission = &inner.ffi;
|
||||||
|
if permission.is_allow_all() {
|
||||||
|
return Ok(PermissionState::Granted);
|
||||||
|
}
|
||||||
Ok(
|
Ok(
|
||||||
self.inner.lock().ffi.query(
|
permission.query(
|
||||||
path
|
path
|
||||||
.map(|path| {
|
.map(|path| {
|
||||||
Result::<_, AnyError>::Ok(
|
Result::<_, AnyError>::Ok(
|
||||||
|
|
|
@ -97,6 +97,9 @@ impl deno_node::NodePermissions for Permissions {
|
||||||
) -> Result<PathBuf, deno_core::error::AnyError> {
|
) -> Result<PathBuf, deno_core::error::AnyError> {
|
||||||
unreachable!("snapshotting!")
|
unreachable!("snapshotting!")
|
||||||
}
|
}
|
||||||
|
fn query_read_all(&mut self) -> bool {
|
||||||
|
unreachable!("snapshotting!")
|
||||||
|
}
|
||||||
fn check_write_with_api_name(
|
fn check_write_with_api_name(
|
||||||
&mut self,
|
&mut self,
|
||||||
_p: &str,
|
_p: &str,
|
||||||
|
|
|
@ -20,54 +20,72 @@ Deno.test(function permissionInvalidNameSync() {
|
||||||
}, TypeError);
|
}, TypeError);
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test(async function permissionNetInvalidHost() {
|
Deno.test(
|
||||||
await assertRejects(async () => {
|
{ permissions: { net: [] } },
|
||||||
await Deno.permissions.query({ name: "net", host: ":" });
|
async function permissionNetInvalidHost() {
|
||||||
}, URIError);
|
await assertRejects(async () => {
|
||||||
});
|
await Deno.permissions.query({ name: "net", host: ":" });
|
||||||
|
}, URIError);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Deno.test(function permissionNetInvalidHostSync() {
|
Deno.test(
|
||||||
assertThrows(() => {
|
{ permissions: { net: [] } },
|
||||||
Deno.permissions.querySync({ name: "net", host: ":" });
|
function permissionNetInvalidHostSync() {
|
||||||
}, URIError);
|
assertThrows(() => {
|
||||||
});
|
Deno.permissions.querySync({ name: "net", host: ":" });
|
||||||
|
}, URIError);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Deno.test(async function permissionSysValidKind() {
|
Deno.test(
|
||||||
await Deno.permissions.query({ name: "sys", kind: "loadavg" });
|
{ permissions: { sys: [] } },
|
||||||
await Deno.permissions.query({ name: "sys", kind: "osRelease" });
|
async function permissionSysValidKind() {
|
||||||
await Deno.permissions.query({ name: "sys", kind: "osUptime" });
|
await Deno.permissions.query({ name: "sys", kind: "loadavg" });
|
||||||
await Deno.permissions.query({ name: "sys", kind: "networkInterfaces" });
|
await Deno.permissions.query({ name: "sys", kind: "osRelease" });
|
||||||
await Deno.permissions.query({ name: "sys", kind: "systemMemoryInfo" });
|
await Deno.permissions.query({ name: "sys", kind: "osUptime" });
|
||||||
await Deno.permissions.query({ name: "sys", kind: "hostname" });
|
await Deno.permissions.query({ name: "sys", kind: "networkInterfaces" });
|
||||||
await Deno.permissions.query({ name: "sys", kind: "uid" });
|
await Deno.permissions.query({ name: "sys", kind: "systemMemoryInfo" });
|
||||||
await Deno.permissions.query({ name: "sys", kind: "gid" });
|
await Deno.permissions.query({ name: "sys", kind: "hostname" });
|
||||||
await Deno.permissions.query({ name: "sys", kind: "cpus" });
|
await Deno.permissions.query({ name: "sys", kind: "uid" });
|
||||||
});
|
await Deno.permissions.query({ name: "sys", kind: "gid" });
|
||||||
|
await Deno.permissions.query({ name: "sys", kind: "cpus" });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Deno.test(function permissionSysValidKindSync() {
|
Deno.test(
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "loadavg" });
|
{ permissions: { sys: [] } },
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "osRelease" });
|
function permissionSysValidKindSync() {
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "networkInterfaces" });
|
Deno.permissions.querySync({ name: "sys", kind: "loadavg" });
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "systemMemoryInfo" });
|
Deno.permissions.querySync({ name: "sys", kind: "osRelease" });
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "hostname" });
|
Deno.permissions.querySync({ name: "sys", kind: "networkInterfaces" });
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "uid" });
|
Deno.permissions.querySync({ name: "sys", kind: "systemMemoryInfo" });
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "gid" });
|
Deno.permissions.querySync({ name: "sys", kind: "hostname" });
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "cpus" });
|
Deno.permissions.querySync({ name: "sys", kind: "uid" });
|
||||||
});
|
Deno.permissions.querySync({ name: "sys", kind: "gid" });
|
||||||
|
Deno.permissions.querySync({ name: "sys", kind: "cpus" });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Deno.test(async function permissionSysInvalidKind() {
|
Deno.test(
|
||||||
await assertRejects(async () => {
|
{ permissions: { sys: [] } },
|
||||||
// deno-lint-ignore no-explicit-any
|
async function permissionSysInvalidKind() {
|
||||||
await Deno.permissions.query({ name: "sys", kind: "abc" as any });
|
await assertRejects(async () => {
|
||||||
}, TypeError);
|
// deno-lint-ignore no-explicit-any
|
||||||
});
|
await Deno.permissions.query({ name: "sys", kind: "abc" as any });
|
||||||
|
}, TypeError);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Deno.test(function permissionSysInvalidKindSync() {
|
Deno.test(
|
||||||
assertThrows(() => {
|
{ permissions: { sys: [] } },
|
||||||
// deno-lint-ignore no-explicit-any
|
function permissionSysInvalidKindSync() {
|
||||||
Deno.permissions.querySync({ name: "sys", kind: "abc" as any });
|
assertThrows(() => {
|
||||||
}, TypeError);
|
// deno-lint-ignore no-explicit-any
|
||||||
});
|
Deno.permissions.querySync({ name: "sys", kind: "abc" as any });
|
||||||
|
}, TypeError);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Deno.test(async function permissionQueryReturnsEventTarget() {
|
Deno.test(async function permissionQueryReturnsEventTarget() {
|
||||||
const status = await Deno.permissions.query({ name: "read", path: "." });
|
const status = await Deno.permissions.query({ name: "read", path: "." });
|
||||||
|
@ -134,29 +152,35 @@ Deno.test(function permissionStatusIllegalConstructor() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Regression test for https://github.com/denoland/deno/issues/17020
|
// Regression test for https://github.com/denoland/deno/issues/17020
|
||||||
Deno.test(async function permissionURL() {
|
Deno.test(
|
||||||
const path = new URL(".", import.meta.url);
|
{ permissions: { read: [], write: [], ffi: [], run: [] } },
|
||||||
|
async function permissionURL() {
|
||||||
|
const path = new URL(".", import.meta.url);
|
||||||
|
|
||||||
await Deno.permissions.query({ name: "read", path });
|
await Deno.permissions.query({ name: "read", path });
|
||||||
await Deno.permissions.query({ name: "write", path });
|
await Deno.permissions.query({ name: "write", path });
|
||||||
await Deno.permissions.query({ name: "ffi", path });
|
await Deno.permissions.query({ name: "ffi", path });
|
||||||
await Deno.permissions.query({ name: "run", command: path });
|
await Deno.permissions.query({ name: "run", command: path });
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Deno.test(function permissionURLSync() {
|
Deno.test(
|
||||||
Deno.permissions.querySync({
|
{ permissions: { read: [], write: [], ffi: [], run: [] } },
|
||||||
name: "read",
|
function permissionURLSync() {
|
||||||
path: new URL(".", import.meta.url),
|
Deno.permissions.querySync({
|
||||||
});
|
name: "read",
|
||||||
Deno.permissions.querySync({
|
path: new URL(".", import.meta.url),
|
||||||
name: "write",
|
});
|
||||||
path: new URL(".", import.meta.url),
|
Deno.permissions.querySync({
|
||||||
});
|
name: "write",
|
||||||
Deno.permissions.querySync({
|
path: new URL(".", import.meta.url),
|
||||||
name: "run",
|
});
|
||||||
command: new URL(".", import.meta.url),
|
Deno.permissions.querySync({
|
||||||
});
|
name: "run",
|
||||||
});
|
command: new URL(".", import.meta.url),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Deno.test(async function permissionDescriptorValidation() {
|
Deno.test(async function permissionDescriptorValidation() {
|
||||||
for (const value of [undefined, null, {}]) {
|
for (const value of [undefined, null, {}]) {
|
||||||
|
|
Loading…
Reference in a new issue