1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-27 16:10:57 -05:00

refactor(runtime/permissions): use concrete error types (#26464)

This commit is contained in:
Leo Kettmeir 2024-11-04 09:17:21 -08:00 committed by GitHub
parent fb1d33a711
commit fe9f0ee593
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 999 additions and 830 deletions

1
Cargo.lock generated
View file

@ -1972,6 +1972,7 @@ dependencies = [
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"serde", "serde",
"thiserror",
"which 4.4.2", "which 4.4.2",
"winapi", "winapi",
] ]

View file

@ -3388,8 +3388,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
.value_name("IP_OR_HOSTNAME") .value_name("IP_OR_HOSTNAME")
.help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary") .help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary")
.value_parser(flags_net::validator) .value_parser(flags_net::validator)
.hide(true) .hide(true);
;
if let Some(requires) = requires { if let Some(requires) = requires {
arg = arg.requires(requires) arg = arg.requires(requires)
} }

View file

@ -51,7 +51,7 @@ pub fn parse(paths: Vec<String>) -> clap::error::Result<Vec<String>> {
} }
} else { } else {
NetDescriptor::parse(&host_and_port).map_err(|e| { NetDescriptor::parse(&host_and_port).map_err(|e| {
clap::Error::raw(clap::error::ErrorKind::InvalidValue, format!("{e:?}")) clap::Error::raw(clap::error::ErrorKind::InvalidValue, e.to_string())
})?; })?;
out.push(host_and_port) out.push(host_and_port)
} }

View file

@ -89,7 +89,7 @@ impl CliNpmResolver for CliByonmNpmResolver {
.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).map_err(Into::into)
} else { } else {
Ok(Cow::Borrowed(path)) Ok(Cow::Borrowed(path))
} }

View file

@ -133,7 +133,7 @@ impl RegistryReadPermissionChecker {
} }
} }
permissions.check_read_path(path) permissions.check_read_path(path).map_err(Into::into)
} }
} }

View file

@ -645,10 +645,12 @@ impl<'a> GraphDisplayContext<'a> {
let message = match err { let message = match err {
HttpsChecksumIntegrity(_) => "(checksum integrity error)", HttpsChecksumIntegrity(_) => "(checksum integrity error)",
Decode(_) => "(loading decode error)", Decode(_) => "(loading decode error)",
Loader(err) => match deno_core::error::get_custom_error_class(err) { Loader(err) => {
Some("NotCapable") => "(not capable, requires --allow-import)", match deno_runtime::errors::get_error_class_name(err) {
_ => "(loading error)", Some("NotCapable") => "(not capable, requires --allow-import)",
}, _ => "(loading error)",
}
}
Jsr(_) => "(loading error)", Jsr(_) => "(loading error)",
NodeUnknownBuiltinModule(_) => "(unknown node built-in error)", NodeUnknownBuiltinModule(_) => "(unknown node built-in error)",
Npm(_) => "(npm loading error)", Npm(_) => "(npm loading error)",

View file

@ -39,6 +39,7 @@ use deno_core::OpState;
use deno_core::RcRef; use deno_core::RcRef;
use deno_core::Resource; use deno_core::Resource;
use deno_core::ResourceId; use deno_core::ResourceId;
use deno_permissions::PermissionCheckError;
use deno_tls::rustls::RootCertStore; use deno_tls::rustls::RootCertStore;
use deno_tls::Proxy; use deno_tls::Proxy;
use deno_tls::RootCertStoreProvider; use deno_tls::RootCertStoreProvider;
@ -149,7 +150,7 @@ pub enum FetchError {
#[error(transparent)] #[error(transparent)]
Resource(deno_core::error::AnyError), Resource(deno_core::error::AnyError),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] PermissionCheckError),
#[error("NetworkError when attempting to fetch resource")] #[error("NetworkError when attempting to fetch resource")]
NetworkError, NetworkError,
#[error("Fetching files only supports the GET method: received {0}")] #[error("Fetching files only supports the GET method: received {0}")]
@ -346,13 +347,13 @@ pub trait FetchPermissions {
&mut self, &mut self,
url: &Url, url: &Url,
api_name: &str, api_name: &str,
) -> Result<(), deno_core::error::AnyError>; ) -> Result<(), PermissionCheckError>;
#[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_read<'a>( fn check_read<'a>(
&mut self, &mut self,
p: &'a Path, p: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, deno_core::error::AnyError>; ) -> Result<Cow<'a, Path>, PermissionCheckError>;
} }
impl FetchPermissions for deno_permissions::PermissionsContainer { impl FetchPermissions for deno_permissions::PermissionsContainer {
@ -361,7 +362,7 @@ impl FetchPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
url: &Url, url: &Url,
api_name: &str, api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name) deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
} }
@ -370,7 +371,7 @@ impl FetchPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &'a Path, path: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, deno_core::error::AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read_path( deno_permissions::PermissionsContainer::check_read_path(
self, self,
path, path,
@ -414,9 +415,7 @@ where
"file" => { "file" => {
let path = url.to_file_path().map_err(|_| FetchError::NetworkError)?; let path = url.to_file_path().map_err(|_| FetchError::NetworkError)?;
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
let path = permissions let path = permissions.check_read(&path, "fetch()")?;
.check_read(&path, "fetch()")
.map_err(FetchError::Permission)?;
let url = match path { let url = match path {
Cow::Owned(path) => Url::from_file_path(path).unwrap(), Cow::Owned(path) => Url::from_file_path(path).unwrap(),
Cow::Borrowed(_) => url, Cow::Borrowed(_) => url,
@ -442,9 +441,7 @@ where
} }
"http" | "https" => { "http" | "https" => {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_net_url(&url, "fetch()")?;
.check_net_url(&url, "fetch()")
.map_err(FetchError::Resource)?;
let maybe_authority = extract_authority(&mut url); let maybe_authority = extract_authority(&mut url);
let uri = url let uri = url
@ -863,9 +860,7 @@ where
if let Some(proxy) = args.proxy.clone() { if let Some(proxy) = args.proxy.clone() {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
let url = Url::parse(&proxy.url)?; let url = Url::parse(&proxy.url)?;
permissions permissions.check_net_url(&url, "Deno.createHttpClient()")?;
.check_net_url(&url, "Deno.createHttpClient()")
.map_err(FetchError::Permission)?;
} }
let options = state.borrow::<Options>(); let options = state.borrow::<Options>();

View file

@ -32,7 +32,9 @@ pub enum CallError {
#[error("Invalid FFI symbol name: '{0}'")] #[error("Invalid FFI symbol name: '{0}'")]
InvalidSymbol(String), InvalidSymbol(String),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error(transparent)]
Resource(deno_core::error::AnyError),
#[error(transparent)] #[error(transparent)]
Callback(#[from] super::CallbackError), Callback(#[from] super::CallbackError),
} }
@ -301,9 +303,7 @@ where
{ {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(CallError::Permission)?;
}; };
let symbol = PtrSymbol::new(pointer, &def)?; let symbol = PtrSymbol::new(pointer, &def)?;
@ -347,7 +347,7 @@ pub fn op_ffi_call_nonblocking(
let resource = state let resource = state
.resource_table .resource_table
.get::<DynamicLibraryResource>(rid) .get::<DynamicLibraryResource>(rid)
.map_err(CallError::Permission)?; .map_err(CallError::Resource)?;
let symbols = &resource.symbols; let symbols = &resource.symbols;
*symbols *symbols
.get(&symbol) .get(&symbol)
@ -401,9 +401,7 @@ where
{ {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(CallError::Permission)?;
}; };
let symbol = PtrSymbol::new(pointer, &def)?; let symbol = PtrSymbol::new(pointer, &def)?;

View file

@ -38,7 +38,7 @@ pub enum CallbackError {
#[error(transparent)] #[error(transparent)]
Resource(deno_core::error::AnyError), Resource(deno_core::error::AnyError),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error(transparent)] #[error(transparent)]
Other(deno_core::error::AnyError), Other(deno_core::error::AnyError),
} }
@ -572,9 +572,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(CallbackError::Permission)?;
let thread_id: u32 = LOCAL_THREAD_ID.with(|s| { let thread_id: u32 = LOCAL_THREAD_ID.with(|s| {
let value = *s.borrow(); let value = *s.borrow();

View file

@ -30,7 +30,7 @@ pub enum DlfcnError {
#[error(transparent)] #[error(transparent)]
Dlopen(#[from] dlopen2::Error), Dlopen(#[from] dlopen2::Error),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error(transparent)] #[error(transparent)]
Other(deno_core::error::AnyError), Other(deno_core::error::AnyError),
} }
@ -133,9 +133,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
let path = permissions let path = permissions.check_partial_with_path(&args.path)?;
.check_partial_with_path(&args.path)
.map_err(DlfcnError::Permission)?;
let lib = Library::open(&path).map_err(|e| { let lib = Library::open(&path).map_err(|e| {
dlopen2::Error::OpeningLibraryError(std::io::Error::new( dlopen2::Error::OpeningLibraryError(std::io::Error::new(

View file

@ -1,7 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use std::mem::size_of; use std::mem::size_of;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::os::raw::c_short; use std::os::raw::c_short;
@ -31,6 +29,7 @@ use symbol::Symbol;
pub use call::CallError; pub use call::CallError;
pub use callback::CallbackError; pub use callback::CallbackError;
use deno_permissions::PermissionCheckError;
pub use dlfcn::DlfcnError; pub use dlfcn::DlfcnError;
pub use ir::IRError; pub use ir::IRError;
pub use r#static::StaticError; pub use r#static::StaticError;
@ -48,17 +47,17 @@ const _: () = {
pub const UNSTABLE_FEATURE_NAME: &str = "ffi"; pub const UNSTABLE_FEATURE_NAME: &str = "ffi";
pub trait FfiPermissions { pub trait FfiPermissions {
fn check_partial_no_path(&mut self) -> Result<(), AnyError>; fn check_partial_no_path(&mut self) -> Result<(), PermissionCheckError>;
#[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_partial_with_path( fn check_partial_with_path(
&mut self, &mut self,
path: &str, path: &str,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
} }
impl FfiPermissions for deno_permissions::PermissionsContainer { impl FfiPermissions for deno_permissions::PermissionsContainer {
#[inline(always)] #[inline(always)]
fn check_partial_no_path(&mut self) -> Result<(), AnyError> { fn check_partial_no_path(&mut self) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_ffi_partial_no_path(self) deno_permissions::PermissionsContainer::check_ffi_partial_no_path(self)
} }
@ -66,7 +65,7 @@ impl FfiPermissions for deno_permissions::PermissionsContainer {
fn check_partial_with_path( fn check_partial_with_path(
&mut self, &mut self,
path: &str, path: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_ffi_partial_with_path( deno_permissions::PermissionsContainer::check_ffi_partial_with_path(
self, path, self, path,
) )

View file

@ -46,7 +46,7 @@ pub enum ReprError {
#[error("Invalid pointer pointer, pointer is null")] #[error("Invalid pointer pointer, pointer is null")]
InvalidPointer, InvalidPointer,
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
} }
#[op2(fast)] #[op2(fast)]
@ -58,9 +58,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
Ok(ptr_number as *mut c_void) Ok(ptr_number as *mut c_void)
} }
@ -75,9 +73,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
Ok(a == b) Ok(a == b)
} }
@ -91,9 +87,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
Ok(buf as *mut c_void) Ok(buf as *mut c_void)
} }
@ -107,9 +101,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
let Some(buf) = buf.get_backing_store() else { let Some(buf) = buf.get_backing_store() else {
return Ok(0 as _); return Ok(0 as _);
@ -130,9 +122,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidOffset); return Err(ReprError::InvalidOffset);
@ -162,9 +152,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
Ok(ptr as usize) Ok(ptr as usize)
} }
@ -181,9 +169,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidArrayBuffer); return Err(ReprError::InvalidArrayBuffer);
@ -215,9 +201,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if src.is_null() { if src.is_null() {
Err(ReprError::InvalidArrayBuffer) Err(ReprError::InvalidArrayBuffer)
@ -246,9 +230,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidCString); return Err(ReprError::InvalidCString);
@ -272,9 +254,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidBool); return Err(ReprError::InvalidBool);
@ -294,9 +274,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidU8); return Err(ReprError::InvalidU8);
@ -318,9 +296,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidI8); return Err(ReprError::InvalidI8);
@ -342,9 +318,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidU16); return Err(ReprError::InvalidU16);
@ -366,9 +340,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidI16); return Err(ReprError::InvalidI16);
@ -390,9 +362,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidU32); return Err(ReprError::InvalidU32);
@ -412,9 +382,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidI32); return Err(ReprError::InvalidI32);
@ -437,9 +405,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidU64); return Err(ReprError::InvalidU64);
@ -465,9 +431,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidI64); return Err(ReprError::InvalidI64);
@ -490,9 +454,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidF32); return Err(ReprError::InvalidF32);
@ -512,9 +474,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidF64); return Err(ReprError::InvalidF64);
@ -534,9 +494,7 @@ where
FP: FfiPermissions + 'static, FP: FfiPermissions + 'static,
{ {
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions permissions.check_partial_no_path()?;
.check_partial_no_path()
.map_err(ReprError::Permission)?;
if ptr.is_null() { if ptr.is_null() {
return Err(ReprError::InvalidPointer); return Err(ReprError::InvalidPointer);

View file

@ -22,8 +22,8 @@ pub use crate::sync::MaybeSync;
use crate::ops::*; use crate::ops::*;
use deno_core::error::AnyError;
use deno_io::fs::FsError; use deno_io::fs::FsError;
use deno_permissions::PermissionCheckError;
use std::borrow::Cow; use std::borrow::Cow;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
@ -42,45 +42,51 @@ pub trait FsPermissions {
&mut self, &mut self,
path: &str, path: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
#[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_read_path<'a>( fn check_read_path<'a>(
&mut self, &mut self,
path: &'a Path, path: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, AnyError>; ) -> Result<Cow<'a, Path>, PermissionCheckError>;
fn check_read_all(&mut self, api_name: &str) -> Result<(), AnyError>; fn check_read_all(
&mut self,
api_name: &str,
) -> Result<(), PermissionCheckError>;
fn check_read_blind( fn check_read_blind(
&mut self, &mut self,
p: &Path, p: &Path,
display: &str, display: &str,
api_name: &str, api_name: &str,
) -> Result<(), AnyError>; ) -> Result<(), PermissionCheckError>;
#[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( fn check_write(
&mut self, &mut self,
path: &str, path: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
#[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_path<'a>( fn check_write_path<'a>(
&mut self, &mut self,
path: &'a Path, path: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, AnyError>; ) -> Result<Cow<'a, Path>, PermissionCheckError>;
#[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_partial( fn check_write_partial(
&mut self, &mut self,
path: &str, path: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
fn check_write_all(&mut self, api_name: &str) -> Result<(), AnyError>; fn check_write_all(
&mut self,
api_name: &str,
) -> Result<(), PermissionCheckError>;
fn check_write_blind( fn check_write_blind(
&mut self, &mut self,
p: &Path, p: &Path,
display: &str, display: &str,
api_name: &str, api_name: &str,
) -> Result<(), AnyError>; ) -> Result<(), PermissionCheckError>;
fn check<'a>( fn check<'a>(
&mut self, &mut self,
@ -140,7 +146,7 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &str, path: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read(self, path, api_name) deno_permissions::PermissionsContainer::check_read(self, path, api_name)
} }
@ -148,7 +154,7 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &'a Path, path: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read_path( deno_permissions::PermissionsContainer::check_read_path(
self, self,
path, path,
@ -160,7 +166,7 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
path: &Path, path: &Path,
display: &str, display: &str,
api_name: &str, api_name: &str,
) -> Result<(), AnyError> { ) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read_blind( deno_permissions::PermissionsContainer::check_read_blind(
self, path, display, api_name, self, path, display, api_name,
) )
@ -170,7 +176,7 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &str, path: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write(self, path, api_name) deno_permissions::PermissionsContainer::check_write(self, path, api_name)
} }
@ -178,7 +184,7 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &'a Path, path: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write_path( deno_permissions::PermissionsContainer::check_write_path(
self, path, api_name, self, path, api_name,
) )
@ -188,7 +194,7 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &str, path: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write_partial( deno_permissions::PermissionsContainer::check_write_partial(
self, path, api_name, self, path, api_name,
) )
@ -199,17 +205,23 @@ impl FsPermissions for deno_permissions::PermissionsContainer {
p: &Path, p: &Path,
display: &str, display: &str,
api_name: &str, api_name: &str,
) -> Result<(), AnyError> { ) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write_blind( deno_permissions::PermissionsContainer::check_write_blind(
self, p, display, api_name, self, p, display, api_name,
) )
} }
fn check_read_all(&mut self, api_name: &str) -> Result<(), AnyError> { fn check_read_all(
&mut self,
api_name: &str,
) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read_all(self, api_name) deno_permissions::PermissionsContainer::check_read_all(self, api_name)
} }
fn check_write_all(&mut self, api_name: &str) -> Result<(), AnyError> { fn check_write_all(
&mut self,
api_name: &str,
) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write_all(self, api_name) deno_permissions::PermissionsContainer::check_write_all(self, api_name)
} }
} }

View file

@ -10,6 +10,12 @@ use std::path::PathBuf;
use std::path::StripPrefixError; use std::path::StripPrefixError;
use std::rc::Rc; use std::rc::Rc;
use crate::interface::AccessCheckFn;
use crate::interface::FileSystemRc;
use crate::interface::FsDirEntry;
use crate::interface::FsFileType;
use crate::FsPermissions;
use crate::OpenOptions;
use deno_core::op2; use deno_core::op2;
use deno_core::CancelFuture; use deno_core::CancelFuture;
use deno_core::CancelHandle; use deno_core::CancelHandle;
@ -20,18 +26,12 @@ use deno_core::ToJsBuffer;
use deno_io::fs::FileResource; use deno_io::fs::FileResource;
use deno_io::fs::FsError; use deno_io::fs::FsError;
use deno_io::fs::FsStat; use deno_io::fs::FsStat;
use deno_permissions::PermissionCheckError;
use rand::rngs::ThreadRng; use rand::rngs::ThreadRng;
use rand::thread_rng; use rand::thread_rng;
use rand::Rng; use rand::Rng;
use serde::Serialize; use serde::Serialize;
use crate::interface::AccessCheckFn;
use crate::interface::FileSystemRc;
use crate::interface::FsDirEntry;
use crate::interface::FsFileType;
use crate::FsPermissions;
use crate::OpenOptions;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum FsOpsError { pub enum FsOpsError {
#[error("{0}")] #[error("{0}")]
@ -39,7 +39,7 @@ pub enum FsOpsError {
#[error("{0}")] #[error("{0}")]
OperationError(#[source] OperationError), OperationError(#[source] OperationError),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] PermissionCheckError),
#[error(transparent)] #[error(transparent)]
Resource(deno_core::error::AnyError), Resource(deno_core::error::AnyError),
#[error("File name or path {0:?} is not valid UTF-8")] #[error("File name or path {0:?} is not valid UTF-8")]
@ -150,8 +150,7 @@ where
let path = fs.cwd()?; let path = fs.cwd()?;
state state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read_blind(&path, "CWD", "Deno.cwd()") .check_read_blind(&path, "CWD", "Deno.cwd()")?;
.map_err(FsOpsError::Permission)?;
let path_str = path_into_string(path.into_os_string())?; let path_str = path_into_string(path.into_os_string())?;
Ok(path_str) Ok(path_str)
} }
@ -166,8 +165,7 @@ where
{ {
let d = state let d = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read(directory, "Deno.chdir()") .check_read(directory, "Deno.chdir()")?;
.map_err(FsOpsError::Permission)?;
state state
.borrow::<FileSystemRc>() .borrow::<FileSystemRc>()
.chdir(&d) .chdir(&d)
@ -253,8 +251,7 @@ where
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write(&path, "Deno.mkdirSync()") .check_write(&path, "Deno.mkdirSync()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.mkdir_sync(&path, recursive, Some(mode)) fs.mkdir_sync(&path, recursive, Some(mode))
@ -277,10 +274,7 @@ where
let (fs, path) = { let (fs, path) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state.borrow_mut::<P>().check_write(&path, "Deno.mkdir()")?;
.borrow_mut::<P>()
.check_write(&path, "Deno.mkdir()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
@ -302,8 +296,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write(&path, "Deno.chmodSync()") .check_write(&path, "Deno.chmodSync()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.chmod_sync(&path, mode).context_path("chmod", &path)?; fs.chmod_sync(&path, mode).context_path("chmod", &path)?;
Ok(()) Ok(())
@ -320,10 +313,7 @@ where
{ {
let (fs, path) = { let (fs, path) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state.borrow_mut::<P>().check_write(&path, "Deno.chmod()")?;
.borrow_mut::<P>()
.check_write(&path, "Deno.chmod()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
fs.chmod_async(path.clone(), mode) fs.chmod_async(path.clone(), mode)
@ -344,8 +334,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write(&path, "Deno.chownSync()") .check_write(&path, "Deno.chownSync()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.chown_sync(&path, uid, gid) fs.chown_sync(&path, uid, gid)
.context_path("chown", &path)?; .context_path("chown", &path)?;
@ -364,10 +353,7 @@ where
{ {
let (fs, path) = { let (fs, path) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state.borrow_mut::<P>().check_write(&path, "Deno.chown()")?;
.borrow_mut::<P>()
.check_write(&path, "Deno.chown()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
fs.chown_async(path.clone(), uid, gid) fs.chown_async(path.clone(), uid, gid)
@ -387,8 +373,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write(path, "Deno.removeSync()") .check_write(path, "Deno.removeSync()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.remove_sync(&path, recursive) fs.remove_sync(&path, recursive)
@ -411,13 +396,11 @@ where
let path = if recursive { let path = if recursive {
state state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write(&path, "Deno.remove()") .check_write(&path, "Deno.remove()")?
.map_err(FsOpsError::Permission)?
} else { } else {
state state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_partial(&path, "Deno.remove()") .check_write_partial(&path, "Deno.remove()")?
.map_err(FsOpsError::Permission)?
}; };
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
@ -440,12 +423,8 @@ where
P: FsPermissions + 'static, P: FsPermissions + 'static,
{ {
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
let from = permissions let from = permissions.check_read(from, "Deno.copyFileSync()")?;
.check_read(from, "Deno.copyFileSync()") let to = permissions.check_write(to, "Deno.copyFileSync()")?;
.map_err(FsOpsError::Permission)?;
let to = permissions
.check_write(to, "Deno.copyFileSync()")
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.copy_file_sync(&from, &to) fs.copy_file_sync(&from, &to)
@ -466,12 +445,8 @@ where
let (fs, from, to) = { let (fs, from, to) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
let from = permissions let from = permissions.check_read(&from, "Deno.copyFile()")?;
.check_read(&from, "Deno.copyFile()") let to = permissions.check_write(&to, "Deno.copyFile()")?;
.map_err(FsOpsError::Permission)?;
let to = permissions
.check_write(&to, "Deno.copyFile()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), from, to) (state.borrow::<FileSystemRc>().clone(), from, to)
}; };
@ -493,8 +468,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read(&path, "Deno.statSync()") .check_read(&path, "Deno.statSync()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
let stat = fs.stat_sync(&path).context_path("stat", &path)?; let stat = fs.stat_sync(&path).context_path("stat", &path)?;
let serializable_stat = SerializableStat::from(stat); let serializable_stat = SerializableStat::from(stat);
@ -514,9 +488,7 @@ where
let (fs, path) = { let (fs, path) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
let path = permissions let path = permissions.check_read(&path, "Deno.stat()")?;
.check_read(&path, "Deno.stat()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
let stat = fs let stat = fs
@ -537,8 +509,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read(&path, "Deno.lstatSync()") .check_read(&path, "Deno.lstatSync()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
let stat = fs.lstat_sync(&path).context_path("lstat", &path)?; let stat = fs.lstat_sync(&path).context_path("lstat", &path)?;
let serializable_stat = SerializableStat::from(stat); let serializable_stat = SerializableStat::from(stat);
@ -558,9 +529,7 @@ where
let (fs, path) = { let (fs, path) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
let path = permissions let path = permissions.check_read(&path, "Deno.lstat()")?;
.check_read(&path, "Deno.lstat()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
let stat = fs let stat = fs
@ -581,13 +550,9 @@ where
{ {
let fs = state.borrow::<FileSystemRc>().clone(); let fs = state.borrow::<FileSystemRc>().clone();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
let path = permissions let path = permissions.check_read(&path, "Deno.realPathSync()")?;
.check_read(&path, "Deno.realPathSync()")
.map_err(FsOpsError::Permission)?;
if path.is_relative() { if path.is_relative() {
permissions permissions.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPathSync()")?;
.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPathSync()")
.map_err(FsOpsError::Permission)?;
} }
let resolved_path = let resolved_path =
@ -610,13 +575,9 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let fs = state.borrow::<FileSystemRc>().clone(); let fs = state.borrow::<FileSystemRc>().clone();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
let path = permissions let path = permissions.check_read(&path, "Deno.realPath()")?;
.check_read(&path, "Deno.realPath()")
.map_err(FsOpsError::Permission)?;
if path.is_relative() { if path.is_relative() {
permissions permissions.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPath()")?;
.check_read_blind(&fs.cwd()?, "CWD", "Deno.realPath()")
.map_err(FsOpsError::Permission)?;
} }
(fs, path) (fs, path)
}; };
@ -640,8 +601,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read(&path, "Deno.readDirSync()") .check_read(&path, "Deno.readDirSync()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
let entries = fs.read_dir_sync(&path).context_path("readdir", &path)?; let entries = fs.read_dir_sync(&path).context_path("readdir", &path)?;
@ -662,8 +622,7 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read(&path, "Deno.readDir()") .check_read(&path, "Deno.readDir()")?;
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
@ -685,15 +644,9 @@ where
P: FsPermissions + 'static, P: FsPermissions + 'static,
{ {
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
let _ = permissions let _ = permissions.check_read(&oldpath, "Deno.renameSync()")?;
.check_read(&oldpath, "Deno.renameSync()") let oldpath = permissions.check_write(&oldpath, "Deno.renameSync()")?;
.map_err(FsOpsError::Permission)?; let newpath = permissions.check_write(&newpath, "Deno.renameSync()")?;
let oldpath = permissions
.check_write(&oldpath, "Deno.renameSync()")
.map_err(FsOpsError::Permission)?;
let newpath = permissions
.check_write(&newpath, "Deno.renameSync()")
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.rename_sync(&oldpath, &newpath) fs.rename_sync(&oldpath, &newpath)
@ -714,15 +667,9 @@ where
let (fs, oldpath, newpath) = { let (fs, oldpath, newpath) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
_ = permissions _ = permissions.check_read(&oldpath, "Deno.rename()")?;
.check_read(&oldpath, "Deno.rename()") let oldpath = permissions.check_write(&oldpath, "Deno.rename()")?;
.map_err(FsOpsError::Permission)?; let newpath = permissions.check_write(&newpath, "Deno.rename()")?;
let oldpath = permissions
.check_write(&oldpath, "Deno.rename()")
.map_err(FsOpsError::Permission)?;
let newpath = permissions
.check_write(&newpath, "Deno.rename()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), oldpath, newpath) (state.borrow::<FileSystemRc>().clone(), oldpath, newpath)
}; };
@ -743,18 +690,10 @@ where
P: FsPermissions + 'static, P: FsPermissions + 'static,
{ {
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
_ = permissions _ = permissions.check_read(oldpath, "Deno.linkSync()")?;
.check_read(oldpath, "Deno.linkSync()") let oldpath = permissions.check_write(oldpath, "Deno.linkSync()")?;
.map_err(FsOpsError::Permission)?; _ = permissions.check_read(newpath, "Deno.linkSync()")?;
let oldpath = permissions let newpath = permissions.check_write(newpath, "Deno.linkSync()")?;
.check_write(oldpath, "Deno.linkSync()")
.map_err(FsOpsError::Permission)?;
_ = permissions
.check_read(newpath, "Deno.linkSync()")
.map_err(FsOpsError::Permission)?;
let newpath = permissions
.check_write(newpath, "Deno.linkSync()")
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.link_sync(&oldpath, &newpath) fs.link_sync(&oldpath, &newpath)
@ -775,18 +714,10 @@ where
let (fs, oldpath, newpath) = { let (fs, oldpath, newpath) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
_ = permissions _ = permissions.check_read(&oldpath, "Deno.link()")?;
.check_read(&oldpath, "Deno.link()") let oldpath = permissions.check_write(&oldpath, "Deno.link()")?;
.map_err(FsOpsError::Permission)?; _ = permissions.check_read(&newpath, "Deno.link()")?;
let oldpath = permissions let newpath = permissions.check_write(&newpath, "Deno.link()")?;
.check_write(&oldpath, "Deno.link()")
.map_err(FsOpsError::Permission)?;
_ = permissions
.check_read(&newpath, "Deno.link()")
.map_err(FsOpsError::Permission)?;
let newpath = permissions
.check_write(&newpath, "Deno.link()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), oldpath, newpath) (state.borrow::<FileSystemRc>().clone(), oldpath, newpath)
}; };
@ -811,12 +742,8 @@ where
let newpath = PathBuf::from(newpath); let newpath = PathBuf::from(newpath);
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
permissions permissions.check_write_all("Deno.symlinkSync()")?;
.check_write_all("Deno.symlinkSync()") permissions.check_read_all("Deno.symlinkSync()")?;
.map_err(FsOpsError::Permission)?;
permissions
.check_read_all("Deno.symlinkSync()")
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.symlink_sync(&oldpath, &newpath, file_type) fs.symlink_sync(&oldpath, &newpath, file_type)
@ -841,12 +768,8 @@ where
let fs = { let fs = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
permissions permissions.check_write_all("Deno.symlink()")?;
.check_write_all("Deno.symlink()") permissions.check_read_all("Deno.symlink()")?;
.map_err(FsOpsError::Permission)?;
permissions
.check_read_all("Deno.symlink()")
.map_err(FsOpsError::Permission)?;
state.borrow::<FileSystemRc>().clone() state.borrow::<FileSystemRc>().clone()
}; };
@ -868,8 +791,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read(&path, "Deno.readLink()") .check_read(&path, "Deno.readLink()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
@ -891,8 +813,7 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read(&path, "Deno.readLink()") .check_read(&path, "Deno.readLink()")?;
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
@ -915,8 +836,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write(path, "Deno.truncateSync()") .check_write(path, "Deno.truncateSync()")?;
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.truncate_sync(&path, len) fs.truncate_sync(&path, len)
@ -938,8 +858,7 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write(&path, "Deno.truncate()") .check_write(&path, "Deno.truncate()")?;
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
@ -962,10 +881,7 @@ pub fn op_fs_utime_sync<P>(
where where
P: FsPermissions + 'static, P: FsPermissions + 'static,
{ {
let path = state let path = state.borrow_mut::<P>().check_write(path, "Deno.utime()")?;
.borrow_mut::<P>()
.check_write(path, "Deno.utime()")
.map_err(FsOpsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.utime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos) fs.utime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)
@ -988,10 +904,7 @@ where
{ {
let (fs, path) = { let (fs, path) = {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state.borrow_mut::<P>().check_write(&path, "Deno.utime()")?;
.borrow_mut::<P>()
.check_write(&path, "Deno.utime()")
.map_err(FsOpsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
@ -1219,16 +1132,12 @@ where
{ {
let fs = state.borrow::<FileSystemRc>().clone(); let fs = state.borrow::<FileSystemRc>().clone();
let dir = match dir { let dir = match dir {
Some(dir) => state Some(dir) => state.borrow_mut::<P>().check_write(dir, api_name)?,
.borrow_mut::<P>()
.check_write(dir, api_name)
.map_err(FsOpsError::Permission)?,
None => { None => {
let dir = fs.tmp_dir().context("tmpdir")?; let dir = fs.tmp_dir().context("tmpdir")?;
state state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_blind(&dir, "TMP", api_name) .check_write_blind(&dir, "TMP", api_name)?;
.map_err(FsOpsError::Permission)?;
dir dir
} }
}; };
@ -1246,16 +1155,12 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let fs = state.borrow::<FileSystemRc>().clone(); let fs = state.borrow::<FileSystemRc>().clone();
let dir = match dir { let dir = match dir {
Some(dir) => state Some(dir) => state.borrow_mut::<P>().check_write(dir, api_name)?,
.borrow_mut::<P>()
.check_write(dir, api_name)
.map_err(FsOpsError::Permission)?,
None => { None => {
let dir = fs.tmp_dir().context("tmpdir")?; let dir = fs.tmp_dir().context("tmpdir")?;
state state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_blind(&dir, "TMP", api_name) .check_write_blind(&dir, "TMP", api_name)?;
.map_err(FsOpsError::Permission)?;
dir dir
} }
}; };

View file

@ -15,6 +15,7 @@ use deno_core::futures::Stream;
use deno_core::OpState; use deno_core::OpState;
use deno_fetch::create_http_client; use deno_fetch::create_http_client;
use deno_fetch::CreateHttpClientOptions; use deno_fetch::CreateHttpClientOptions;
use deno_permissions::PermissionCheckError;
use deno_tls::rustls::RootCertStore; use deno_tls::rustls::RootCertStore;
use deno_tls::Proxy; use deno_tls::Proxy;
use deno_tls::RootCertStoreProvider; use deno_tls::RootCertStoreProvider;
@ -45,17 +46,17 @@ impl HttpOptions {
} }
pub trait RemoteDbHandlerPermissions { pub trait RemoteDbHandlerPermissions {
fn check_env(&mut self, var: &str) -> Result<(), AnyError>; fn check_env(&mut self, var: &str) -> Result<(), PermissionCheckError>;
fn check_net_url( fn check_net_url(
&mut self, &mut self,
url: &Url, url: &Url,
api_name: &str, api_name: &str,
) -> Result<(), AnyError>; ) -> Result<(), PermissionCheckError>;
} }
impl RemoteDbHandlerPermissions for deno_permissions::PermissionsContainer { impl RemoteDbHandlerPermissions for deno_permissions::PermissionsContainer {
#[inline(always)] #[inline(always)]
fn check_env(&mut self, var: &str) -> Result<(), AnyError> { fn check_env(&mut self, var: &str) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_env(self, var) deno_permissions::PermissionsContainer::check_env(self, var)
} }
@ -64,7 +65,7 @@ impl RemoteDbHandlerPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
url: &Url, url: &Url,
api_name: &str, api_name: &str,
) -> Result<(), AnyError> { ) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name) deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
} }
} }
@ -103,7 +104,9 @@ impl<P: RemoteDbHandlerPermissions + 'static> denokv_remote::RemotePermissions
fn check_net_url(&self, url: &Url) -> Result<(), anyhow::Error> { fn check_net_url(&self, url: &Url) -> Result<(), anyhow::Error> {
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
permissions.check_net_url(url, "Deno.openKv") permissions
.check_net_url(url, "Deno.openKv")
.map_err(Into::into)
} }
} }

View file

@ -13,20 +13,20 @@ use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::sync::OnceLock; use std::sync::OnceLock;
use crate::DatabaseHandler;
use async_trait::async_trait; use async_trait::async_trait;
use deno_core::error::type_error; use deno_core::error::type_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::unsync::spawn_blocking; use deno_core::unsync::spawn_blocking;
use deno_core::OpState; use deno_core::OpState;
use deno_path_util::normalize_path; use deno_path_util::normalize_path;
use deno_permissions::PermissionCheckError;
pub use denokv_sqlite::SqliteBackendError; pub use denokv_sqlite::SqliteBackendError;
use denokv_sqlite::SqliteConfig; use denokv_sqlite::SqliteConfig;
use denokv_sqlite::SqliteNotifier; use denokv_sqlite::SqliteNotifier;
use rand::SeedableRng; use rand::SeedableRng;
use rusqlite::OpenFlags; use rusqlite::OpenFlags;
use crate::DatabaseHandler;
static SQLITE_NOTIFIERS_MAP: OnceLock<Mutex<HashMap<PathBuf, SqliteNotifier>>> = static SQLITE_NOTIFIERS_MAP: OnceLock<Mutex<HashMap<PathBuf, SqliteNotifier>>> =
OnceLock::new(); OnceLock::new();
@ -42,13 +42,13 @@ pub trait SqliteDbHandlerPermissions {
&mut self, &mut self,
p: &str, p: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
#[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<'a>( fn check_write<'a>(
&mut self, &mut self,
p: &'a Path, p: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, AnyError>; ) -> Result<Cow<'a, Path>, PermissionCheckError>;
} }
impl SqliteDbHandlerPermissions for deno_permissions::PermissionsContainer { impl SqliteDbHandlerPermissions for deno_permissions::PermissionsContainer {
@ -57,7 +57,7 @@ impl SqliteDbHandlerPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
p: &str, p: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read(self, p, api_name) deno_permissions::PermissionsContainer::check_read(self, p, api_name)
} }
@ -66,7 +66,7 @@ impl SqliteDbHandlerPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
p: &'a Path, p: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write_path(self, p, api_name) deno_permissions::PermissionsContainer::check_write_path(self, p, api_name)
} }
} }

View file

@ -43,7 +43,7 @@ pub enum NApiError {
#[error("Unable to find register Node-API module at {}", .0.display())] #[error("Unable to find register Node-API module at {}", .0.display())]
ModuleNotFound(PathBuf), ModuleNotFound(PathBuf),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] PermissionCheckError),
} }
#[cfg(unix)] #[cfg(unix)]
@ -55,6 +55,7 @@ use libloading::os::windows::*;
// Expose common stuff for ease of use. // Expose common stuff for ease of use.
// `use deno_napi::*` // `use deno_napi::*`
pub use deno_core::v8; pub use deno_core::v8;
use deno_permissions::PermissionCheckError;
pub use std::ffi::CStr; pub use std::ffi::CStr;
pub use std::os::raw::c_char; pub use std::os::raw::c_char;
pub use std::os::raw::c_void; pub use std::os::raw::c_void;
@ -508,20 +509,14 @@ deno_core::extension!(deno_napi,
pub trait NapiPermissions { pub trait NapiPermissions {
#[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( fn check(&mut self, path: &str) -> Result<PathBuf, PermissionCheckError>;
&mut self,
path: &str,
) -> Result<PathBuf, deno_core::error::AnyError>;
} }
// NOTE(bartlomieju): for now, NAPI uses `--allow-ffi` flag, but that might // NOTE(bartlomieju): for now, NAPI uses `--allow-ffi` flag, but that might
// change in the future. // change in the future.
impl NapiPermissions for deno_permissions::PermissionsContainer { impl NapiPermissions for deno_permissions::PermissionsContainer {
#[inline(always)] #[inline(always)]
fn check( fn check(&mut self, path: &str) -> Result<PathBuf, PermissionCheckError> {
&mut self,
path: &str,
) -> Result<PathBuf, deno_core::error::AnyError> {
deno_permissions::PermissionsContainer::check_ffi(self, path) deno_permissions::PermissionsContainer::check_ffi(self, path)
} }
} }
@ -553,7 +548,7 @@ where
let (async_work_sender, cleanup_hooks, external_ops_tracker, path) = { let (async_work_sender, cleanup_hooks, external_ops_tracker, path) = {
let mut op_state = op_state.borrow_mut(); let mut op_state = op_state.borrow_mut();
let permissions = op_state.borrow_mut::<NP>(); let permissions = op_state.borrow_mut::<NP>();
let path = permissions.check(&path).map_err(NApiError::Permission)?; let path = permissions.check(&path)?;
let napi_state = op_state.borrow::<NapiState>(); let napi_state = op_state.borrow::<NapiState>();
( (
op_state.borrow::<V8CrossThreadTaskSpawner>().clone(), op_state.borrow::<V8CrossThreadTaskSpawner>().clone(),

View file

@ -11,6 +11,7 @@ mod tcp;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::OpState; use deno_core::OpState;
use deno_permissions::PermissionCheckError;
use deno_tls::rustls::RootCertStore; use deno_tls::rustls::RootCertStore;
use deno_tls::RootCertStoreProvider; use deno_tls::RootCertStoreProvider;
use std::borrow::Cow; use std::borrow::Cow;
@ -25,25 +26,25 @@ pub trait NetPermissions {
&mut self, &mut self,
host: &(T, Option<u16>), host: &(T, Option<u16>),
api_name: &str, api_name: &str,
) -> Result<(), AnyError>; ) -> Result<(), PermissionCheckError>;
#[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_read( fn check_read(
&mut self, &mut self,
p: &str, p: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
#[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( fn check_write(
&mut self, &mut self,
p: &str, p: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
#[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_path<'a>( fn check_write_path<'a>(
&mut self, &mut self,
p: &'a Path, p: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, AnyError>; ) -> Result<Cow<'a, Path>, PermissionCheckError>;
} }
impl NetPermissions for deno_permissions::PermissionsContainer { impl NetPermissions for deno_permissions::PermissionsContainer {
@ -52,7 +53,7 @@ impl NetPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
host: &(T, Option<u16>), host: &(T, Option<u16>),
api_name: &str, api_name: &str,
) -> Result<(), AnyError> { ) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_net(self, host, api_name) deno_permissions::PermissionsContainer::check_net(self, host, api_name)
} }
@ -61,7 +62,7 @@ impl NetPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &str, path: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read(self, path, api_name) deno_permissions::PermissionsContainer::check_read(self, path, api_name)
} }
@ -70,7 +71,7 @@ impl NetPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &str, path: &str,
api_name: &str, api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write(self, path, api_name) deno_permissions::PermissionsContainer::check_write(self, path, api_name)
} }
@ -79,7 +80,7 @@ impl NetPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &'a Path, path: &'a Path,
api_name: &str, api_name: &str,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write_path( deno_permissions::PermissionsContainer::check_write_path(
self, path, api_name, self, path, api_name,
) )

View file

@ -81,8 +81,8 @@ pub enum NetError {
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
#[error("Another accept task is ongoing")] #[error("Another accept task is ongoing")]
AcceptTaskOngoing, AcceptTaskOngoing,
#[error("{0}")] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error("{0}")] #[error("{0}")]
Resource(deno_core::error::AnyError), Resource(deno_core::error::AnyError),
#[error("No resolved address found")] #[error("No resolved address found")]
@ -195,12 +195,10 @@ where
{ {
{ {
let mut s = state.borrow_mut(); let mut s = state.borrow_mut();
s.borrow_mut::<NP>() s.borrow_mut::<NP>().check_net(
.check_net( &(&addr.hostname, Some(addr.port)),
&(&addr.hostname, Some(addr.port)), "Deno.DatagramConn.send()",
"Deno.DatagramConn.send()", )?;
)
.map_err(NetError::Permission)?;
} }
let addr = resolve_addr(&addr.hostname, addr.port) let addr = resolve_addr(&addr.hostname, addr.port)
.await? .await?
@ -369,8 +367,7 @@ where
let mut state_ = state.borrow_mut(); let mut state_ = state.borrow_mut();
state_ state_
.borrow_mut::<NP>() .borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.connect()") .check_net(&(&addr.hostname, Some(addr.port)), "Deno.connect()")?;
.map_err(NetError::Permission)?;
} }
let addr = resolve_addr(&addr.hostname, addr.port) let addr = resolve_addr(&addr.hostname, addr.port)
@ -420,8 +417,7 @@ where
} }
state state
.borrow_mut::<NP>() .borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.listen()") .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listen()")?;
.map_err(NetError::Permission)?;
let addr = resolve_addr_sync(&addr.hostname, addr.port)? let addr = resolve_addr_sync(&addr.hostname, addr.port)?
.next() .next()
.ok_or_else(|| NetError::NoResolvedAddress)?; .ok_or_else(|| NetError::NoResolvedAddress)?;
@ -449,8 +445,7 @@ where
{ {
state state
.borrow_mut::<NP>() .borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenDatagram()") .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenDatagram()")?;
.map_err(NetError::Permission)?;
let addr = resolve_addr_sync(&addr.hostname, addr.port)? let addr = resolve_addr_sync(&addr.hostname, addr.port)?
.next() .next()
.ok_or_else(|| NetError::NoResolvedAddress)?; .ok_or_else(|| NetError::NoResolvedAddress)?;
@ -647,9 +642,7 @@ where
let socker_addr = &ns.socket_addr; let socker_addr = &ns.socket_addr;
let ip = socker_addr.ip().to_string(); let ip = socker_addr.ip().to_string();
let port = socker_addr.port(); let port = socker_addr.port();
perm perm.check_net(&(ip, Some(port)), "Deno.resolveDns()")?;
.check_net(&(ip, Some(port)), "Deno.resolveDns()")
.map_err(NetError::Permission)?;
} }
} }
@ -834,6 +827,7 @@ mod tests {
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::JsRuntime; use deno_core::JsRuntime;
use deno_core::RuntimeOptions; use deno_core::RuntimeOptions;
use deno_permissions::PermissionCheckError;
use socket2::SockRef; use socket2::SockRef;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::net::Ipv6Addr; use std::net::Ipv6Addr;
@ -1041,7 +1035,7 @@ mod tests {
&mut self, &mut self,
_host: &(T, Option<u16>), _host: &(T, Option<u16>),
_api_name: &str, _api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), PermissionCheckError> {
Ok(()) Ok(())
} }
@ -1049,7 +1043,7 @@ mod tests {
&mut self, &mut self,
p: &str, p: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, deno_core::error::AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
Ok(PathBuf::from(p)) Ok(PathBuf::from(p))
} }
@ -1057,7 +1051,7 @@ mod tests {
&mut self, &mut self,
p: &str, p: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, deno_core::error::AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
Ok(PathBuf::from(p)) Ok(PathBuf::from(p))
} }
@ -1065,7 +1059,7 @@ mod tests {
&mut self, &mut self,
p: &'a Path, p: &'a Path,
_api_name: &str, _api_name: &str,
) -> Result<Cow<'a, Path>, deno_core::error::AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
Ok(Cow::Borrowed(p)) Ok(Cow::Borrowed(p))
} }
} }

View file

@ -24,6 +24,7 @@ pub mod ops;
mod polyfill; mod polyfill;
pub use deno_package_json::PackageJson; pub use deno_package_json::PackageJson;
use deno_permissions::PermissionCheckError;
pub use node_resolver::PathClean; pub use node_resolver::PathClean;
pub use ops::ipc::ChildPipeFd; pub use ops::ipc::ChildPipeFd;
pub use ops::ipc::IpcJsonStreamResource; pub use ops::ipc::IpcJsonStreamResource;
@ -45,10 +46,13 @@ pub trait NodePermissions {
&mut self, &mut self,
url: &Url, url: &Url,
api_name: &str, api_name: &str,
) -> Result<(), AnyError>; ) -> Result<(), PermissionCheckError>;
#[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)]
fn check_read(&mut self, path: &str) -> Result<PathBuf, AnyError> { fn check_read(
&mut self,
path: &str,
) -> Result<PathBuf, PermissionCheckError> {
self.check_read_with_api_name(path, None) self.check_read_with_api_name(path, None)
} }
#[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"]
@ -56,20 +60,24 @@ pub trait NodePermissions {
&mut self, &mut self,
path: &str, path: &str,
api_name: Option<&str>, api_name: Option<&str>,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
#[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_read_path<'a>( fn check_read_path<'a>(
&mut self, &mut self,
path: &'a Path, path: &'a Path,
) -> Result<Cow<'a, Path>, AnyError>; ) -> Result<Cow<'a, Path>, PermissionCheckError>;
fn query_read_all(&mut self) -> bool; 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<(), PermissionCheckError>;
#[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(
&mut self, &mut self,
path: &str, path: &str,
api_name: Option<&str>, api_name: Option<&str>,
) -> Result<PathBuf, AnyError>; ) -> Result<PathBuf, PermissionCheckError>;
} }
impl NodePermissions for deno_permissions::PermissionsContainer { impl NodePermissions for deno_permissions::PermissionsContainer {
@ -78,7 +86,7 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
url: &Url, url: &Url,
api_name: &str, api_name: &str,
) -> Result<(), AnyError> { ) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name) deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
} }
@ -87,7 +95,7 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &str, path: &str,
api_name: Option<&str>, api_name: Option<&str>,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read_with_api_name( deno_permissions::PermissionsContainer::check_read_with_api_name(
self, path, api_name, self, path, api_name,
) )
@ -96,7 +104,7 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
fn check_read_path<'a>( fn check_read_path<'a>(
&mut self, &mut self,
path: &'a Path, path: &'a Path,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_read_path(self, path, None) deno_permissions::PermissionsContainer::check_read_path(self, path, None)
} }
@ -109,13 +117,17 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
path: &str, path: &str,
api_name: Option<&str>, api_name: Option<&str>,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
deno_permissions::PermissionsContainer::check_write_with_api_name( deno_permissions::PermissionsContainer::check_write_with_api_name(
self, path, api_name, self, path, api_name,
) )
} }
fn check_sys(&mut self, kind: &str, api_name: &str) -> Result<(), AnyError> { fn check_sys(
&mut self,
kind: &str,
api_name: &str,
) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_sys(self, kind, api_name) deno_permissions::PermissionsContainer::check_sys(self, kind, api_name)
} }
} }

View file

@ -13,7 +13,7 @@ use crate::NodePermissions;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum FsError { pub enum FsError {
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error("{0}")] #[error("{0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
#[cfg(windows)] #[cfg(windows)]
@ -53,8 +53,7 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read_with_api_name(&path, Some("node:fs.exists()")) .check_read_with_api_name(&path, Some("node:fs.exists()"))?;
.map_err(FsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
@ -72,12 +71,10 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read_with_api_name(path, Some("node:fs.cpSync")) .check_read_with_api_name(path, Some("node:fs.cpSync"))?;
.map_err(FsError::Permission)?;
let new_path = state let new_path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_with_api_name(new_path, Some("node:fs.cpSync")) .check_write_with_api_name(new_path, Some("node:fs.cpSync"))?;
.map_err(FsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.cp_sync(&path, &new_path)?; fs.cp_sync(&path, &new_path)?;
@ -97,12 +94,10 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read_with_api_name(&path, Some("node:fs.cpSync")) .check_read_with_api_name(&path, Some("node:fs.cpSync"))?;
.map_err(FsError::Permission)?;
let new_path = state let new_path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_with_api_name(&new_path, Some("node:fs.cpSync")) .check_write_with_api_name(&new_path, Some("node:fs.cpSync"))?;
.map_err(FsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path, new_path) (state.borrow::<FileSystemRc>().clone(), path, new_path)
}; };
@ -136,12 +131,10 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_read_with_api_name(&path, Some("node:fs.statfs")) .check_read_with_api_name(&path, Some("node:fs.statfs"))?;
.map_err(FsError::Permission)?;
state state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_sys("statfs", "node:fs.statfs") .check_sys("statfs", "node:fs.statfs")?;
.map_err(FsError::Permission)?;
path path
}; };
#[cfg(unix)] #[cfg(unix)]
@ -279,8 +272,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_with_api_name(path, Some("node:fs.lutimes")) .check_write_with_api_name(path, Some("node:fs.lutimes"))?;
.map_err(FsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.lutime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)?; fs.lutime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos)?;
@ -303,8 +295,7 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_with_api_name(&path, Some("node:fs.lutimesSync")) .check_write_with_api_name(&path, Some("node:fs.lutimesSync"))?;
.map_err(FsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
@ -326,8 +317,7 @@ where
{ {
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_with_api_name(&path, Some("node:fs.lchownSync")) .check_write_with_api_name(&path, Some("node:fs.lchownSync"))?;
.map_err(FsError::Permission)?;
let fs = state.borrow::<FileSystemRc>(); let fs = state.borrow::<FileSystemRc>();
fs.lchown_sync(&path, uid, gid)?; fs.lchown_sync(&path, uid, gid)?;
Ok(()) Ok(())
@ -347,8 +337,7 @@ where
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
let path = state let path = state
.borrow_mut::<P>() .borrow_mut::<P>()
.check_write_with_api_name(&path, Some("node:fs.lchown")) .check_write_with_api_name(&path, Some("node:fs.lchown"))?;
.map_err(FsError::Permission)?;
(state.borrow::<FileSystemRc>().clone(), path) (state.borrow::<FileSystemRc>().clone(), path)
}; };
fs.lchown_async(path, uid, gid).await?; fs.lchown_async(path, uid, gid).await?;

View file

@ -78,9 +78,7 @@ where
{ {
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
permissions permissions.check_net_url(&url, "ClientRequest")?;
.check_net_url(&url, "ClientRequest")
.map_err(FetchError::Permission)?;
} }
let mut header_map = HeaderMap::new(); let mut header_map = HeaderMap::new();

View file

@ -14,7 +14,7 @@ pub enum OsError {
#[error(transparent)] #[error(transparent)]
Priority(priority::PriorityError), Priority(priority::PriorityError),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error("Failed to get cpu info")] #[error("Failed to get cpu info")]
FailedToGetCpuInfo, FailedToGetCpuInfo,
#[error("Failed to get user info")] #[error("Failed to get user info")]
@ -31,9 +31,7 @@ where
{ {
{ {
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
permissions permissions.check_sys("getPriority", "node:os.getPriority()")?;
.check_sys("getPriority", "node:os.getPriority()")
.map_err(OsError::Permission)?;
} }
priority::get_priority(pid).map_err(OsError::Priority) priority::get_priority(pid).map_err(OsError::Priority)
@ -50,9 +48,7 @@ where
{ {
{ {
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
permissions permissions.check_sys("setPriority", "node:os.setPriority()")?;
.check_sys("setPriority", "node:os.setPriority()")
.map_err(OsError::Permission)?;
} }
priority::set_priority(pid, priority).map_err(OsError::Priority) priority::set_priority(pid, priority).map_err(OsError::Priority)
@ -266,9 +262,7 @@ where
{ {
{ {
let permissions = state.borrow_mut::<P>(); let permissions = state.borrow_mut::<P>();
permissions permissions.check_sys("cpus", "node:os.cpus()")?;
.check_sys("cpus", "node:os.cpus()")
.map_err(OsError::Permission)?;
} }
cpus::cpu_info().ok_or(OsError::FailedToGetCpuInfo) cpus::cpu_info().ok_or(OsError::FailedToGetCpuInfo)

View file

@ -50,6 +50,7 @@ use tokio::io::ReadHalf;
use tokio::io::WriteHalf; use tokio::io::WriteHalf;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use deno_permissions::PermissionCheckError;
use fastwebsockets::CloseCode; use fastwebsockets::CloseCode;
use fastwebsockets::FragmentCollectorRead; use fastwebsockets::FragmentCollectorRead;
use fastwebsockets::Frame; use fastwebsockets::Frame;
@ -75,7 +76,7 @@ pub enum WebsocketError {
#[error(transparent)] #[error(transparent)]
Url(url::ParseError), Url(url::ParseError),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] PermissionCheckError),
#[error(transparent)] #[error(transparent)]
Resource(deno_core::error::AnyError), Resource(deno_core::error::AnyError),
#[error(transparent)] #[error(transparent)]
@ -112,7 +113,7 @@ pub trait WebSocketPermissions {
&mut self, &mut self,
_url: &url::Url, _url: &url::Url,
_api_name: &str, _api_name: &str,
) -> Result<(), deno_core::error::AnyError>; ) -> Result<(), PermissionCheckError>;
} }
impl WebSocketPermissions for deno_permissions::PermissionsContainer { impl WebSocketPermissions for deno_permissions::PermissionsContainer {
@ -121,7 +122,7 @@ impl WebSocketPermissions for deno_permissions::PermissionsContainer {
&mut self, &mut self,
url: &url::Url, url: &url::Url,
api_name: &str, api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), PermissionCheckError> {
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name) deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
} }
} }
@ -158,13 +159,10 @@ pub fn op_ws_check_permission_and_cancel_handle<WP>(
where where
WP: WebSocketPermissions + 'static, WP: WebSocketPermissions + 'static,
{ {
state state.borrow_mut::<WP>().check_net_url(
.borrow_mut::<WP>() &url::Url::parse(&url).map_err(WebsocketError::Url)?,
.check_net_url( &api_name,
&url::Url::parse(&url).map_err(WebsocketError::Url)?, )?;
&api_name,
)
.map_err(WebsocketError::Permission)?;
if cancel_handle { if cancel_handle {
let rid = state let rid = state

View file

@ -12,6 +12,8 @@
use crate::ops::fs_events::FsEventsError; use crate::ops::fs_events::FsEventsError;
use crate::ops::http::HttpStartError; use crate::ops::http::HttpStartError;
use crate::ops::os::OsError; use crate::ops::os::OsError;
use crate::ops::permissions::PermissionError;
use crate::ops::process::CheckRunPermissionError;
use crate::ops::process::ProcessError; use crate::ops::process::ProcessError;
use crate::ops::signal::SignalError; use crate::ops::signal::SignalError;
use crate::ops::tty::TtyError; use crate::ops::tty::TtyError;
@ -48,6 +50,12 @@ use deno_kv::KvError;
use deno_kv::KvMutationError; use deno_kv::KvMutationError;
use deno_napi::NApiError; use deno_napi::NApiError;
use deno_net::ops::NetError; use deno_net::ops::NetError;
use deno_permissions::ChildPermissionError;
use deno_permissions::NetDescriptorFromUrlParseError;
use deno_permissions::PathResolveError;
use deno_permissions::PermissionCheckError;
use deno_permissions::RunDescriptorParseError;
use deno_permissions::SysDescriptorParseError;
use deno_tls::TlsError; use deno_tls::TlsError;
use deno_web::BlobError; use deno_web::BlobError;
use deno_web::CompressionError; use deno_web::CompressionError;
@ -63,6 +71,54 @@ use std::error::Error;
use std::io; use std::io;
use std::sync::Arc; use std::sync::Arc;
fn get_run_descriptor_parse_error(e: &RunDescriptorParseError) -> &'static str {
match e {
RunDescriptorParseError::Which(_) => "Error",
RunDescriptorParseError::PathResolve(e) => get_path_resolve_error(e),
RunDescriptorParseError::EmptyRunQuery => "Error",
}
}
fn get_sys_descriptor_parse_error(e: &SysDescriptorParseError) -> &'static str {
match e {
SysDescriptorParseError::InvalidKind(_) => "TypeError",
SysDescriptorParseError::Empty => "Error",
}
}
fn get_path_resolve_error(e: &PathResolveError) -> &'static str {
match e {
PathResolveError::CwdResolve(e) => get_io_error_class(e),
PathResolveError::EmptyPath => "Error",
}
}
fn get_permission_error_class(e: &PermissionError) -> &'static str {
match e {
PermissionError::InvalidPermissionName(_) => "ReferenceError",
PermissionError::PathResolve(e) => get_path_resolve_error(e),
PermissionError::NetDescriptorParse(_) => "URIError",
PermissionError::SysDescriptorParse(e) => get_sys_descriptor_parse_error(e),
PermissionError::RunDescriptorParse(e) => get_run_descriptor_parse_error(e),
}
}
fn get_permission_check_error_class(e: &PermissionCheckError) -> &'static str {
match e {
PermissionCheckError::PermissionDenied(_) => "NotCapable",
PermissionCheckError::InvalidFilePath(_) => "URIError",
PermissionCheckError::NetDescriptorForUrlParse(e) => match e {
NetDescriptorFromUrlParseError::MissingHost(_) => "TypeError",
NetDescriptorFromUrlParseError::Host(_) => "URIError",
},
PermissionCheckError::SysDescriptorParse(e) => {
get_sys_descriptor_parse_error(e)
}
PermissionCheckError::PathResolve(e) => get_path_resolve_error(e),
PermissionCheckError::HostParse(_) => "URIError",
}
}
fn get_dlopen_error_class(error: &dlopen2::Error) -> &'static str { fn get_dlopen_error_class(error: &dlopen2::Error) -> &'static str {
use dlopen2::Error::*; use dlopen2::Error::*;
match error { match error {
@ -445,7 +501,7 @@ fn get_napi_error_class(e: &NApiError) -> &'static str {
NApiError::InvalidPath NApiError::InvalidPath
| NApiError::LibLoading(_) | NApiError::LibLoading(_)
| NApiError::ModuleNotFound(_) => "TypeError", | NApiError::ModuleNotFound(_) => "TypeError",
NApiError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), NApiError::Permission(e) => get_permission_check_error_class(e),
} }
} }
@ -523,7 +579,7 @@ fn get_ffi_repr_error_class(e: &ReprError) -> &'static str {
ReprError::InvalidF32 => "TypeError", ReprError::InvalidF32 => "TypeError",
ReprError::InvalidF64 => "TypeError", ReprError::InvalidF64 => "TypeError",
ReprError::InvalidPointer => "TypeError", ReprError::InvalidPointer => "TypeError",
ReprError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), ReprError::Permission(e) => get_permission_check_error_class(e),
} }
} }
@ -531,7 +587,7 @@ fn get_ffi_dlfcn_error_class(e: &DlfcnError) -> &'static str {
match e { match e {
DlfcnError::RegisterSymbol { .. } => "Error", DlfcnError::RegisterSymbol { .. } => "Error",
DlfcnError::Dlopen(_) => "Error", DlfcnError::Dlopen(_) => "Error",
DlfcnError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), DlfcnError::Permission(e) => get_permission_check_error_class(e),
DlfcnError::Other(e) => get_error_class_name(e).unwrap_or("Error"), DlfcnError::Other(e) => get_error_class_name(e).unwrap_or("Error"),
} }
} }
@ -549,7 +605,7 @@ fn get_ffi_callback_error_class(e: &CallbackError) -> &'static str {
match e { match e {
CallbackError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), CallbackError::Resource(e) => get_error_class_name(e).unwrap_or("Error"),
CallbackError::Other(e) => get_error_class_name(e).unwrap_or("Error"), CallbackError::Other(e) => get_error_class_name(e).unwrap_or("Error"),
CallbackError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), CallbackError::Permission(e) => get_permission_check_error_class(e),
} }
} }
@ -558,8 +614,9 @@ fn get_ffi_call_error_class(e: &CallError) -> &'static str {
CallError::IR(_) => "TypeError", CallError::IR(_) => "TypeError",
CallError::NonblockingCallFailure(_) => "Error", CallError::NonblockingCallFailure(_) => "Error",
CallError::InvalidSymbol(_) => "TypeError", CallError::InvalidSymbol(_) => "TypeError",
CallError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), CallError::Permission(e) => get_permission_check_error_class(e),
CallError::Callback(e) => get_ffi_callback_error_class(e), CallError::Callback(e) => get_ffi_callback_error_class(e),
CallError::Resource(e) => get_error_class_name(e).unwrap_or("Error"),
} }
} }
@ -633,9 +690,8 @@ fn get_broadcast_channel_error(error: &BroadcastChannelError) -> &'static str {
fn get_fetch_error(error: &FetchError) -> &'static str { fn get_fetch_error(error: &FetchError) -> &'static str {
match error { match error {
FetchError::Resource(e) | FetchError::Permission(e) => { FetchError::Resource(e) => get_error_class_name(e).unwrap_or("Error"),
get_error_class_name(e).unwrap_or("Error") FetchError::Permission(e) => get_permission_check_error_class(e),
}
FetchError::NetworkError => "TypeError", FetchError::NetworkError => "TypeError",
FetchError::FsNotGet(_) => "TypeError", FetchError::FsNotGet(_) => "TypeError",
FetchError::InvalidUrl(_) => "TypeError", FetchError::InvalidUrl(_) => "TypeError",
@ -669,9 +725,8 @@ fn get_http_client_create_error(error: &HttpClientCreateError) -> &'static str {
fn get_websocket_error(error: &WebsocketError) -> &'static str { fn get_websocket_error(error: &WebsocketError) -> &'static str {
match error { match error {
WebsocketError::Permission(e) | WebsocketError::Resource(e) => { WebsocketError::Resource(e) => get_error_class_name(e).unwrap_or("Error"),
get_error_class_name(e).unwrap_or("Error") WebsocketError::Permission(e) => get_permission_check_error_class(e),
}
WebsocketError::Url(e) => get_url_parse_error_class(e), WebsocketError::Url(e) => get_url_parse_error_class(e),
WebsocketError::Io(e) => get_io_error_class(e), WebsocketError::Io(e) => get_io_error_class(e),
WebsocketError::WebSocket(_) => "TypeError", WebsocketError::WebSocket(_) => "TypeError",
@ -708,9 +763,10 @@ fn get_fs_ops_error(error: &FsOpsError) -> &'static str {
match error { match error {
FsOpsError::Io(e) => get_io_error_class(e), FsOpsError::Io(e) => get_io_error_class(e),
FsOpsError::OperationError(e) => get_fs_error(&e.err), FsOpsError::OperationError(e) => get_fs_error(&e.err),
FsOpsError::Permission(e) FsOpsError::Permission(e) => get_permission_check_error_class(e),
| FsOpsError::Resource(e) FsOpsError::Resource(e) | FsOpsError::Other(e) => {
| FsOpsError::Other(e) => get_error_class_name(e).unwrap_or("Error"), get_error_class_name(e).unwrap_or("Error")
}
FsOpsError::InvalidUtf8(_) => "InvalidData", FsOpsError::InvalidUtf8(_) => "InvalidData",
FsOpsError::StripPrefix(_) => "Error", FsOpsError::StripPrefix(_) => "Error",
FsOpsError::Canceled(e) => { FsOpsError::Canceled(e) => {
@ -777,9 +833,10 @@ fn get_net_error(error: &NetError) -> &'static str {
NetError::SocketBusy => "Busy", NetError::SocketBusy => "Busy",
NetError::Io(e) => get_io_error_class(e), NetError::Io(e) => get_io_error_class(e),
NetError::AcceptTaskOngoing => "Busy", NetError::AcceptTaskOngoing => "Busy",
NetError::RootCertStore(e) NetError::RootCertStore(e) | NetError::Resource(e) => {
| NetError::Permission(e) get_error_class_name(e).unwrap_or("Error")
| NetError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), }
NetError::Permission(e) => get_permission_check_error_class(e),
NetError::NoResolvedAddress => "Error", NetError::NoResolvedAddress => "Error",
NetError::AddrParse(_) => "Error", NetError::AddrParse(_) => "Error",
NetError::Map(e) => get_net_map_error(e), NetError::Map(e) => get_net_map_error(e),
@ -810,12 +867,25 @@ fn get_net_map_error(error: &deno_net::io::MapError) -> &'static str {
} }
} }
fn get_child_permission_error(e: &ChildPermissionError) -> &'static str {
match e {
ChildPermissionError::Escalation => "NotCapable",
ChildPermissionError::PathResolve(e) => get_path_resolve_error(e),
ChildPermissionError::NetDescriptorParse(_) => "URIError",
ChildPermissionError::EnvDescriptorParse(_) => "Error",
ChildPermissionError::SysDescriptorParse(e) => {
get_sys_descriptor_parse_error(e)
}
ChildPermissionError::RunDescriptorParse(e) => {
get_run_descriptor_parse_error(e)
}
}
}
fn get_create_worker_error(error: &CreateWorkerError) -> &'static str { fn get_create_worker_error(error: &CreateWorkerError) -> &'static str {
match error { match error {
CreateWorkerError::ClassicWorkers => "DOMExceptionNotSupportedError", CreateWorkerError::ClassicWorkers => "DOMExceptionNotSupportedError",
CreateWorkerError::Permission(e) => { CreateWorkerError::Permission(e) => get_child_permission_error(e),
get_error_class_name(e).unwrap_or("Error")
}
CreateWorkerError::ModuleResolution(e) => { CreateWorkerError::ModuleResolution(e) => {
get_module_resolution_error_class(e) get_module_resolution_error_class(e)
} }
@ -862,9 +932,8 @@ fn get_signal_error(error: &SignalError) -> &'static str {
fn get_fs_events_error(error: &FsEventsError) -> &'static str { fn get_fs_events_error(error: &FsEventsError) -> &'static str {
match error { match error {
FsEventsError::Resource(e) | FsEventsError::Permission(e) => { FsEventsError::Resource(e) => get_error_class_name(e).unwrap_or("Error"),
get_error_class_name(e).unwrap_or("Error") FsEventsError::Permission(e) => get_permission_check_error_class(e),
}
FsEventsError::Notify(e) => get_notify_error_class(e), FsEventsError::Notify(e) => get_notify_error_class(e),
FsEventsError::Canceled(e) => { FsEventsError::Canceled(e) => {
let io_err: io::Error = e.to_owned().into(); let io_err: io::Error = e.to_owned().into();
@ -892,9 +961,8 @@ fn get_process_error(error: &ProcessError) -> &'static str {
ProcessError::FailedResolvingCwd(e) | ProcessError::Io(e) => { ProcessError::FailedResolvingCwd(e) | ProcessError::Io(e) => {
get_io_error_class(e) get_io_error_class(e)
} }
ProcessError::Permission(e) | ProcessError::Resource(e) => { ProcessError::Permission(e) => get_permission_check_error_class(e),
get_error_class_name(e).unwrap_or("Error") ProcessError::Resource(e) => get_error_class_name(e).unwrap_or("Error"),
}
ProcessError::BorrowMut(_) => "Error", ProcessError::BorrowMut(_) => "Error",
ProcessError::Which(_) => "Error", ProcessError::Which(_) => "Error",
ProcessError::ChildProcessAlreadyTerminated => "TypeError", ProcessError::ChildProcessAlreadyTerminated => "TypeError",
@ -903,6 +971,14 @@ fn get_process_error(error: &ProcessError) -> &'static str {
ProcessError::InvalidPid => "TypeError", ProcessError::InvalidPid => "TypeError",
#[cfg(unix)] #[cfg(unix)]
ProcessError::Nix(e) => get_nix_error_class(e), ProcessError::Nix(e) => get_nix_error_class(e),
ProcessError::RunPermission(e) => match e {
CheckRunPermissionError::Permission(e) => {
get_permission_check_error_class(e)
}
CheckRunPermissionError::Other(e) => {
get_error_class_name(e).unwrap_or("Error")
}
},
} }
} }
@ -971,6 +1047,7 @@ fn get_fs_error(e: &FsError) -> &'static str {
mod node { mod node {
use super::get_error_class_name; use super::get_error_class_name;
use super::get_io_error_class; use super::get_io_error_class;
use super::get_permission_check_error_class;
use super::get_serde_json_error_class; use super::get_serde_json_error_class;
use super::get_url_parse_error_class; use super::get_url_parse_error_class;
pub use deno_node::ops::blocklist::BlocklistError; pub use deno_node::ops::blocklist::BlocklistError;
@ -998,7 +1075,7 @@ mod node {
pub fn get_fs_error(error: &FsError) -> &'static str { pub fn get_fs_error(error: &FsError) -> &'static str {
match error { match error {
FsError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), FsError::Permission(e) => get_permission_check_error_class(e),
FsError::Io(e) => get_io_error_class(e), FsError::Io(e) => get_io_error_class(e),
#[cfg(windows)] #[cfg(windows)]
FsError::PathHasNoRoot => "Error", FsError::PathHasNoRoot => "Error",
@ -1084,7 +1161,7 @@ mod node {
#[cfg(windows)] #[cfg(windows)]
PriorityError::InvalidPriority => "TypeError", PriorityError::InvalidPriority => "TypeError",
}, },
OsError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), OsError::Permission(e) => get_permission_check_error_class(e),
OsError::FailedToGetCpuInfo => "TypeError", OsError::FailedToGetCpuInfo => "TypeError",
OsError::FailedToGetUserInfo(e) => get_io_error_class(e), OsError::FailedToGetUserInfo(e) => get_io_error_class(e),
} }
@ -1116,7 +1193,7 @@ mod node {
fn get_os_error(error: &OsError) -> &'static str { fn get_os_error(error: &OsError) -> &'static str {
match error { match error {
OsError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), OsError::Permission(e) => get_permission_check_error_class(e),
OsError::InvalidUtf8(_) => "InvalidData", OsError::InvalidUtf8(_) => "InvalidData",
OsError::EnvEmptyKey => "TypeError", OsError::EnvEmptyKey => "TypeError",
OsError::EnvInvalidKey(_) => "TypeError", OsError::EnvInvalidKey(_) => "TypeError",
@ -1144,6 +1221,18 @@ fn get_sync_fetch_error(error: &SyncFetchError) -> &'static str {
pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
deno_core::error::get_custom_error_class(e) deno_core::error::get_custom_error_class(e)
.or_else(|| {
e.downcast_ref::<ChildPermissionError>()
.map(get_child_permission_error)
})
.or_else(|| {
e.downcast_ref::<PermissionCheckError>()
.map(get_permission_check_error_class)
})
.or_else(|| {
e.downcast_ref::<PermissionError>()
.map(get_permission_error_class)
})
.or_else(|| e.downcast_ref::<FsError>().map(get_fs_error)) .or_else(|| e.downcast_ref::<FsError>().map(get_fs_error))
.or_else(|| { .or_else(|| {
e.downcast_ref::<node::BlocklistError>() e.downcast_ref::<node::BlocklistError>()

View file

@ -114,7 +114,7 @@ pub enum FsEventsError {
#[error(transparent)] #[error(transparent)]
Resource(deno_core::error::AnyError), Resource(deno_core::error::AnyError),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error(transparent)] #[error(transparent)]
Notify(#[from] NotifyError), Notify(#[from] NotifyError),
#[error(transparent)] #[error(transparent)]
@ -181,8 +181,7 @@ fn op_fs_events_open(
for path in &paths { for path in &paths {
let path = state let path = state
.borrow_mut::<PermissionsContainer>() .borrow_mut::<PermissionsContainer>()
.check_read(path, "Deno.watchFs()") .check_read(path, "Deno.watchFs()")?;
.map_err(FsEventsError::Permission)?;
let watcher = state.borrow_mut::<WatcherState>(); let watcher = state.borrow_mut::<WatcherState>();
watcher.watcher.watch(&path, recursive_mode)?; watcher.watcher.watch(&path, recursive_mode)?;

View file

@ -73,7 +73,7 @@ deno_core::extension!(
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum OsError { pub enum OsError {
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error("File name or path {0:?} is not valid UTF-8")] #[error("File name or path {0:?} is not valid UTF-8")]
InvalidUtf8(std::ffi::OsString), InvalidUtf8(std::ffi::OsString),
#[error("Key is an empty string.")] #[error("Key is an empty string.")]
@ -94,8 +94,7 @@ fn op_exec_path(state: &mut OpState) -> Result<String, OsError> {
let current_exe = env::current_exe().unwrap(); let current_exe = env::current_exe().unwrap();
state state
.borrow_mut::<PermissionsContainer>() .borrow_mut::<PermissionsContainer>()
.check_read_blind(&current_exe, "exec_path", "Deno.execPath()") .check_read_blind(&current_exe, "exec_path", "Deno.execPath()")?;
.map_err(OsError::Permission)?;
// normalize path so it doesn't include '.' or '..' components // normalize path so it doesn't include '.' or '..' components
let path = normalize_path(current_exe); let path = normalize_path(current_exe);
@ -111,10 +110,7 @@ fn op_set_env(
#[string] key: &str, #[string] key: &str,
#[string] value: &str, #[string] value: &str,
) -> Result<(), OsError> { ) -> Result<(), OsError> {
state state.borrow_mut::<PermissionsContainer>().check_env(key)?;
.borrow_mut::<PermissionsContainer>()
.check_env(key)
.map_err(OsError::Permission)?;
if key.is_empty() { if key.is_empty() {
return Err(OsError::EnvEmptyKey); return Err(OsError::EnvEmptyKey);
} }
@ -146,10 +142,7 @@ fn op_get_env(
let skip_permission_check = NODE_ENV_VAR_ALLOWLIST.contains(&key); let skip_permission_check = NODE_ENV_VAR_ALLOWLIST.contains(&key);
if !skip_permission_check { if !skip_permission_check {
state state.borrow_mut::<PermissionsContainer>().check_env(&key)?;
.borrow_mut::<PermissionsContainer>()
.check_env(&key)
.map_err(OsError::Permission)?;
} }
if key.is_empty() { if key.is_empty() {
@ -172,10 +165,7 @@ fn op_delete_env(
state: &mut OpState, state: &mut OpState,
#[string] key: String, #[string] key: String,
) -> Result<(), OsError> { ) -> Result<(), OsError> {
state state.borrow_mut::<PermissionsContainer>().check_env(&key)?;
.borrow_mut::<PermissionsContainer>()
.check_env(&key)
.map_err(OsError::Permission)?;
if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
return Err(OsError::EnvInvalidKey(key.to_string())); return Err(OsError::EnvInvalidKey(key.to_string()));
} }
@ -240,8 +230,7 @@ fn op_network_interfaces(
) -> Result<Vec<NetworkInterface>, OsError> { ) -> Result<Vec<NetworkInterface>, OsError> {
state state
.borrow_mut::<PermissionsContainer>() .borrow_mut::<PermissionsContainer>()
.check_sys("networkInterfaces", "Deno.networkInterfaces()") .check_sys("networkInterfaces", "Deno.networkInterfaces()")?;
.map_err(OsError::Permission)?;
Ok(netif::up()?.map(NetworkInterface::from).collect()) Ok(netif::up()?.map(NetworkInterface::from).collect())
} }

View file

@ -2,8 +2,6 @@
use ::deno_permissions::PermissionState; use ::deno_permissions::PermissionState;
use ::deno_permissions::PermissionsContainer; use ::deno_permissions::PermissionsContainer;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::op2; use deno_core::op2;
use deno_core::OpState; use deno_core::OpState;
use serde::Deserialize; use serde::Deserialize;
@ -47,12 +45,26 @@ impl From<PermissionState> for PermissionStatus {
} }
} }
#[derive(Debug, thiserror::Error)]
pub enum PermissionError {
#[error("No such permission name: {0}")]
InvalidPermissionName(String),
#[error("{0}")]
PathResolve(#[from] ::deno_permissions::PathResolveError),
#[error("{0}")]
NetDescriptorParse(#[from] ::deno_permissions::NetDescriptorParseError),
#[error("{0}")]
SysDescriptorParse(#[from] ::deno_permissions::SysDescriptorParseError),
#[error("{0}")]
RunDescriptorParse(#[from] ::deno_permissions::RunDescriptorParseError),
}
#[op2] #[op2]
#[serde] #[serde]
pub fn op_query_permission( pub fn op_query_permission(
state: &mut OpState, state: &mut OpState,
#[serde] args: PermissionArgs, #[serde] args: PermissionArgs,
) -> Result<PermissionStatus, AnyError> { ) -> Result<PermissionStatus, PermissionError> {
let permissions = state.borrow::<PermissionsContainer>(); let permissions = state.borrow::<PermissionsContainer>();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.query_read(args.path.as_deref())?, "read" => permissions.query_read(args.path.as_deref())?,
@ -62,12 +74,7 @@ pub fn op_query_permission(
"sys" => permissions.query_sys(args.kind.as_deref())?, "sys" => permissions.query_sys(args.kind.as_deref())?,
"run" => permissions.query_run(args.command.as_deref())?, "run" => permissions.query_run(args.command.as_deref())?,
"ffi" => permissions.query_ffi(args.path.as_deref())?, "ffi" => permissions.query_ffi(args.path.as_deref())?,
n => { _ => return Err(PermissionError::InvalidPermissionName(args.name)),
return Err(custom_error(
"ReferenceError",
format!("No such permission name: {n}"),
))
}
}; };
Ok(PermissionStatus::from(perm)) Ok(PermissionStatus::from(perm))
} }
@ -77,7 +84,7 @@ pub fn op_query_permission(
pub fn op_revoke_permission( pub fn op_revoke_permission(
state: &mut OpState, state: &mut OpState,
#[serde] args: PermissionArgs, #[serde] args: PermissionArgs,
) -> Result<PermissionStatus, AnyError> { ) -> Result<PermissionStatus, PermissionError> {
let permissions = state.borrow::<PermissionsContainer>(); let permissions = state.borrow::<PermissionsContainer>();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.revoke_read(args.path.as_deref())?, "read" => permissions.revoke_read(args.path.as_deref())?,
@ -87,12 +94,7 @@ pub fn op_revoke_permission(
"sys" => permissions.revoke_sys(args.kind.as_deref())?, "sys" => permissions.revoke_sys(args.kind.as_deref())?,
"run" => permissions.revoke_run(args.command.as_deref())?, "run" => permissions.revoke_run(args.command.as_deref())?,
"ffi" => permissions.revoke_ffi(args.path.as_deref())?, "ffi" => permissions.revoke_ffi(args.path.as_deref())?,
n => { _ => return Err(PermissionError::InvalidPermissionName(args.name)),
return Err(custom_error(
"ReferenceError",
format!("No such permission name: {n}"),
))
}
}; };
Ok(PermissionStatus::from(perm)) Ok(PermissionStatus::from(perm))
} }
@ -102,7 +104,7 @@ pub fn op_revoke_permission(
pub fn op_request_permission( pub fn op_request_permission(
state: &mut OpState, state: &mut OpState,
#[serde] args: PermissionArgs, #[serde] args: PermissionArgs,
) -> Result<PermissionStatus, AnyError> { ) -> Result<PermissionStatus, PermissionError> {
let permissions = state.borrow::<PermissionsContainer>(); let permissions = state.borrow::<PermissionsContainer>();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.request_read(args.path.as_deref())?, "read" => permissions.request_read(args.path.as_deref())?,
@ -112,12 +114,7 @@ pub fn op_request_permission(
"sys" => permissions.request_sys(args.kind.as_deref())?, "sys" => permissions.request_sys(args.kind.as_deref())?,
"run" => permissions.request_run(args.command.as_deref())?, "run" => permissions.request_run(args.command.as_deref())?,
"ffi" => permissions.request_ffi(args.path.as_deref())?, "ffi" => permissions.request_ffi(args.path.as_deref())?,
n => { _ => return Err(PermissionError::InvalidPermissionName(args.name)),
return Err(custom_error(
"ReferenceError",
format!("No such permission name: {n}"),
))
}
}; };
Ok(PermissionStatus::from(perm)) Ok(PermissionStatus::from(perm))
} }

View file

@ -206,7 +206,9 @@ pub enum ProcessError {
#[error("failed resolving cwd: {0}")] #[error("failed resolving cwd: {0}")]
FailedResolvingCwd(#[source] std::io::Error), FailedResolvingCwd(#[source] std::io::Error),
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(#[from] deno_permissions::PermissionCheckError),
#[error(transparent)]
RunPermission(#[from] CheckRunPermissionError),
#[error(transparent)] #[error(transparent)]
Resource(deno_core::error::AnyError), Resource(deno_core::error::AnyError),
#[error(transparent)] #[error(transparent)]
@ -653,8 +655,7 @@ fn compute_run_cmd_and_check_permissions(
}, },
&run_env, &run_env,
api_name, api_name,
) )?;
.map_err(ProcessError::Permission)?;
Ok((cmd, run_env)) Ok((cmd, run_env))
} }
@ -734,12 +735,20 @@ fn resolve_path(path: &str, cwd: &Path) -> PathBuf {
deno_path_util::normalize_path(cwd.join(path)) deno_path_util::normalize_path(cwd.join(path))
} }
#[derive(Debug, thiserror::Error)]
pub enum CheckRunPermissionError {
#[error(transparent)]
Permission(#[from] deno_permissions::PermissionCheckError),
#[error("{0}")]
Other(deno_core::error::AnyError),
}
fn check_run_permission( fn check_run_permission(
state: &mut OpState, state: &mut OpState,
cmd: &RunQueryDescriptor, cmd: &RunQueryDescriptor,
run_env: &RunEnv, run_env: &RunEnv,
api_name: &str, api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), CheckRunPermissionError> {
let permissions = state.borrow_mut::<PermissionsContainer>(); let permissions = state.borrow_mut::<PermissionsContainer>();
if !permissions.query_run_all(api_name) { if !permissions.query_run_all(api_name) {
// error the same on all platforms // error the same on all platforms
@ -747,14 +756,14 @@ fn check_run_permission(
if !env_var_names.is_empty() { if !env_var_names.is_empty() {
// we don't allow users to launch subprocesses with any LD_ or DYLD_* // we don't allow users to launch subprocesses with any LD_ or DYLD_*
// env vars set because this allows executing code (ex. LD_PRELOAD) // env vars set because this allows executing code (ex. LD_PRELOAD)
return Err(deno_core::error::custom_error( return Err(CheckRunPermissionError::Other(deno_core::error::custom_error(
"NotCapable", "NotCapable",
format!( format!(
"Requires --allow-all permissions to spawn subprocess with {} environment variable{}.", "Requires --allow-all permissions to spawn subprocess with {} environment variable{}.",
env_var_names.join(", "), env_var_names.join(", "),
if env_var_names.len() != 1 { "s" } else { "" } if env_var_names.len() != 1 { "s" } else { "" }
) )
)); )));
} }
permissions.check_run(cmd, api_name)?; permissions.check_run(cmd, api_name)?;
} }
@ -1126,8 +1135,7 @@ mod deprecated {
) -> Result<(), ProcessError> { ) -> Result<(), ProcessError> {
state state
.borrow_mut::<PermissionsContainer>() .borrow_mut::<PermissionsContainer>()
.check_run_all(&api_name) .check_run_all(&api_name)?;
.map_err(ProcessError::Permission)?;
kill(pid, &signal) kill(pid, &signal)
} }
} }

View file

@ -123,7 +123,7 @@ pub enum CreateWorkerError {
#[error("Classic workers are not supported.")] #[error("Classic workers are not supported.")]
ClassicWorkers, ClassicWorkers,
#[error(transparent)] #[error(transparent)]
Permission(deno_core::error::AnyError), Permission(deno_permissions::ChildPermissionError),
#[error(transparent)] #[error(transparent)]
ModuleResolution(#[from] deno_core::ModuleResolutionError), ModuleResolution(#[from] deno_core::ModuleResolutionError),
#[error(transparent)] #[error(transparent)]

View file

@ -3,9 +3,6 @@
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_path_util::normalize_path; use deno_path_util::normalize_path;
use deno_permissions::AllowRunDescriptor; use deno_permissions::AllowRunDescriptor;
use deno_permissions::AllowRunDescriptorParseResult; use deno_permissions::AllowRunDescriptorParseResult;
@ -15,9 +12,12 @@ use deno_permissions::FfiDescriptor;
use deno_permissions::ImportDescriptor; use deno_permissions::ImportDescriptor;
use deno_permissions::NetDescriptor; use deno_permissions::NetDescriptor;
use deno_permissions::PathQueryDescriptor; use deno_permissions::PathQueryDescriptor;
use deno_permissions::PathResolveError;
use deno_permissions::ReadDescriptor; use deno_permissions::ReadDescriptor;
use deno_permissions::RunDescriptorParseError;
use deno_permissions::RunQueryDescriptor; use deno_permissions::RunQueryDescriptor;
use deno_permissions::SysDescriptor; use deno_permissions::SysDescriptor;
use deno_permissions::SysDescriptorParseError;
use deno_permissions::WriteDescriptor; use deno_permissions::WriteDescriptor;
#[derive(Debug)] #[derive(Debug)]
@ -30,9 +30,9 @@ impl RuntimePermissionDescriptorParser {
Self { fs } Self { fs }
} }
fn resolve_from_cwd(&self, path: &str) -> Result<PathBuf, AnyError> { fn resolve_from_cwd(&self, path: &str) -> Result<PathBuf, PathResolveError> {
if path.is_empty() { if path.is_empty() {
bail!("Empty path is not allowed"); return Err(PathResolveError::EmptyPath);
} }
let path = Path::new(path); let path = Path::new(path);
if path.is_absolute() { if path.is_absolute() {
@ -43,12 +43,11 @@ impl RuntimePermissionDescriptorParser {
} }
} }
fn resolve_cwd(&self) -> Result<PathBuf, AnyError> { fn resolve_cwd(&self) -> Result<PathBuf, PathResolveError> {
self self
.fs .fs
.cwd() .cwd()
.map_err(|e| e.into_io_error()) .map_err(|e| PathResolveError::CwdResolve(e.into_io_error()))
.context("failed resolving cwd")
} }
} }
@ -58,37 +57,37 @@ impl deno_permissions::PermissionDescriptorParser
fn parse_read_descriptor( fn parse_read_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<ReadDescriptor, AnyError> { ) -> Result<ReadDescriptor, PathResolveError> {
Ok(ReadDescriptor(self.resolve_from_cwd(text)?)) Ok(ReadDescriptor(self.resolve_from_cwd(text)?))
} }
fn parse_write_descriptor( fn parse_write_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<WriteDescriptor, AnyError> { ) -> Result<WriteDescriptor, PathResolveError> {
Ok(WriteDescriptor(self.resolve_from_cwd(text)?)) Ok(WriteDescriptor(self.resolve_from_cwd(text)?))
} }
fn parse_net_descriptor( fn parse_net_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<NetDescriptor, AnyError> { ) -> Result<NetDescriptor, deno_permissions::NetDescriptorParseError> {
NetDescriptor::parse(text) NetDescriptor::parse(text)
} }
fn parse_import_descriptor( fn parse_import_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<ImportDescriptor, AnyError> { ) -> Result<ImportDescriptor, deno_permissions::NetDescriptorParseError> {
ImportDescriptor::parse(text) ImportDescriptor::parse(text)
} }
fn parse_env_descriptor( fn parse_env_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<EnvDescriptor, AnyError> { ) -> Result<EnvDescriptor, deno_permissions::EnvDescriptorParseError> {
if text.is_empty() { if text.is_empty() {
Err(AnyError::msg("Empty env not allowed")) Err(deno_permissions::EnvDescriptorParseError)
} else { } else {
Ok(EnvDescriptor::new(text)) Ok(EnvDescriptor::new(text))
} }
@ -97,9 +96,9 @@ impl deno_permissions::PermissionDescriptorParser
fn parse_sys_descriptor( fn parse_sys_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<deno_permissions::SysDescriptor, AnyError> { ) -> Result<SysDescriptor, SysDescriptorParseError> {
if text.is_empty() { if text.is_empty() {
Err(AnyError::msg("Empty sys not allowed")) Err(SysDescriptorParseError::Empty)
} else { } else {
Ok(SysDescriptor::parse(text.to_string())?) Ok(SysDescriptor::parse(text.to_string())?)
} }
@ -108,21 +107,21 @@ impl deno_permissions::PermissionDescriptorParser
fn parse_allow_run_descriptor( fn parse_allow_run_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<AllowRunDescriptorParseResult, AnyError> { ) -> Result<AllowRunDescriptorParseResult, RunDescriptorParseError> {
Ok(AllowRunDescriptor::parse(text, &self.resolve_cwd()?)?) Ok(AllowRunDescriptor::parse(text, &self.resolve_cwd()?)?)
} }
fn parse_deny_run_descriptor( fn parse_deny_run_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<DenyRunDescriptor, AnyError> { ) -> Result<DenyRunDescriptor, PathResolveError> {
Ok(DenyRunDescriptor::parse(text, &self.resolve_cwd()?)) Ok(DenyRunDescriptor::parse(text, &self.resolve_cwd()?))
} }
fn parse_ffi_descriptor( fn parse_ffi_descriptor(
&self, &self,
text: &str, text: &str,
) -> Result<deno_permissions::FfiDescriptor, AnyError> { ) -> Result<FfiDescriptor, PathResolveError> {
Ok(FfiDescriptor(self.resolve_from_cwd(text)?)) Ok(FfiDescriptor(self.resolve_from_cwd(text)?))
} }
@ -131,7 +130,7 @@ impl deno_permissions::PermissionDescriptorParser
fn parse_path_query( fn parse_path_query(
&self, &self,
path: &str, path: &str,
) -> Result<PathQueryDescriptor, AnyError> { ) -> Result<PathQueryDescriptor, PathResolveError> {
Ok(PathQueryDescriptor { Ok(PathQueryDescriptor {
resolved: self.resolve_from_cwd(path)?, resolved: self.resolve_from_cwd(path)?,
requested: path.to_string(), requested: path.to_string(),
@ -141,11 +140,12 @@ impl deno_permissions::PermissionDescriptorParser
fn parse_run_query( fn parse_run_query(
&self, &self,
requested: &str, requested: &str,
) -> Result<RunQueryDescriptor, AnyError> { ) -> Result<RunQueryDescriptor, RunDescriptorParseError> {
if requested.is_empty() { if requested.is_empty() {
bail!("Empty run query is not allowed"); return Err(RunDescriptorParseError::EmptyRunQuery);
} }
RunQueryDescriptor::parse(requested) RunQueryDescriptor::parse(requested)
.map_err(RunDescriptorParseError::PathResolve)
} }
} }

View file

@ -23,6 +23,7 @@ log.workspace = true
once_cell.workspace = true once_cell.workspace = true
percent-encoding = { version = "2.3.1", features = [] } percent-encoding = { version = "2.3.1", features = [] }
serde.workspace = true serde.workspace = true
thiserror.workspace = true
which.workspace = true which.workspace = true
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_terminal::colors; use deno_terminal::colors;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -101,8 +100,7 @@ pub struct TtyPrompter;
fn clear_stdin( fn clear_stdin(
_stdin_lock: &mut StdinLock, _stdin_lock: &mut StdinLock,
_stderr_lock: &mut StderrLock, _stderr_lock: &mut StderrLock,
) -> Result<(), AnyError> { ) -> Result<(), std::io::Error> {
use deno_core::anyhow::bail;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
const STDIN_FD: i32 = 0; const STDIN_FD: i32 = 0;
@ -117,7 +115,10 @@ fn clear_stdin(
loop { loop {
let r = libc::tcflush(STDIN_FD, libc::TCIFLUSH); let r = libc::tcflush(STDIN_FD, libc::TCIFLUSH);
if r != 0 { if r != 0 {
bail!("clear_stdin failed (tcflush)"); return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"clear_stdin failed (tcflush)",
));
} }
// Initialize timeout for select to be 100ms // Initialize timeout for select to be 100ms
@ -137,7 +138,10 @@ fn clear_stdin(
// Check if select returned an error // Check if select returned an error
if r < 0 { if r < 0 {
bail!("clear_stdin failed (select)"); return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"clear_stdin failed (select)",
));
} }
// Check if select returned due to timeout (stdin is quiescent) // Check if select returned due to timeout (stdin is quiescent)
@ -156,8 +160,7 @@ fn clear_stdin(
fn clear_stdin( fn clear_stdin(
stdin_lock: &mut StdinLock, stdin_lock: &mut StdinLock,
stderr_lock: &mut StderrLock, stderr_lock: &mut StderrLock,
) -> Result<(), AnyError> { ) -> Result<(), std::io::Error> {
use deno_core::anyhow::bail;
use winapi::shared::minwindef::TRUE; use winapi::shared::minwindef::TRUE;
use winapi::shared::minwindef::UINT; use winapi::shared::minwindef::UINT;
use winapi::shared::minwindef::WORD; use winapi::shared::minwindef::WORD;
@ -194,18 +197,23 @@ fn clear_stdin(
return Ok(()); return Ok(());
unsafe fn flush_input_buffer(stdin: HANDLE) -> Result<(), AnyError> { unsafe fn flush_input_buffer(stdin: HANDLE) -> Result<(), std::io::Error> {
let success = FlushConsoleInputBuffer(stdin); let success = FlushConsoleInputBuffer(stdin);
if success != TRUE { if success != TRUE {
bail!( return Err(std::io::Error::new(
"Could not flush the console input buffer: {}", std::io::ErrorKind::Other,
std::io::Error::last_os_error() format!(
) "Could not flush the console input buffer: {}",
std::io::Error::last_os_error()
),
));
} }
Ok(()) Ok(())
} }
unsafe fn emulate_enter_key_press(stdin: HANDLE) -> Result<(), AnyError> { unsafe fn emulate_enter_key_press(
stdin: HANDLE,
) -> Result<(), std::io::Error> {
// https://github.com/libuv/libuv/blob/a39009a5a9252a566ca0704d02df8dabc4ce328f/src/win/tty.c#L1121-L1131 // https://github.com/libuv/libuv/blob/a39009a5a9252a566ca0704d02df8dabc4ce328f/src/win/tty.c#L1121-L1131
let mut input_record: INPUT_RECORD = std::mem::zeroed(); let mut input_record: INPUT_RECORD = std::mem::zeroed();
input_record.EventType = KEY_EVENT; input_record.EventType = KEY_EVENT;
@ -220,34 +228,43 @@ fn clear_stdin(
let success = let success =
WriteConsoleInputW(stdin, &input_record, 1, &mut record_written); WriteConsoleInputW(stdin, &input_record, 1, &mut record_written);
if success != TRUE { if success != TRUE {
bail!( return Err(std::io::Error::new(
"Could not emulate enter key press: {}", std::io::ErrorKind::Other,
std::io::Error::last_os_error() format!(
); "Could not emulate enter key press: {}",
std::io::Error::last_os_error()
),
));
} }
Ok(()) Ok(())
} }
unsafe fn is_input_buffer_empty(stdin: HANDLE) -> Result<bool, AnyError> { unsafe fn is_input_buffer_empty(
stdin: HANDLE,
) -> Result<bool, std::io::Error> {
let mut buffer = Vec::with_capacity(1); let mut buffer = Vec::with_capacity(1);
let mut events_read = 0; let mut events_read = 0;
let success = let success =
PeekConsoleInputW(stdin, buffer.as_mut_ptr(), 1, &mut events_read); PeekConsoleInputW(stdin, buffer.as_mut_ptr(), 1, &mut events_read);
if success != TRUE { if success != TRUE {
bail!( return Err(std::io::Error::new(
"Could not peek the console input buffer: {}", std::io::ErrorKind::Other,
std::io::Error::last_os_error() format!(
) "Could not peek the console input buffer: {}",
std::io::Error::last_os_error()
),
));
} }
Ok(events_read == 0) Ok(events_read == 0)
} }
fn move_cursor_up(stderr_lock: &mut StderrLock) -> Result<(), AnyError> { fn move_cursor_up(
write!(stderr_lock, "\x1B[1A")?; stderr_lock: &mut StderrLock,
Ok(()) ) -> Result<(), std::io::Error> {
write!(stderr_lock, "\x1B[1A")
} }
fn read_stdin_line(stdin_lock: &mut StdinLock) -> Result<(), AnyError> { fn read_stdin_line(stdin_lock: &mut StdinLock) -> Result<(), std::io::Error> {
let mut input = String::new(); let mut input = String::new();
stdin_lock.read_line(&mut input)?; stdin_lock.read_line(&mut input)?;
Ok(()) Ok(())

View file

@ -5,12 +5,12 @@ use crate::ops::bootstrap::SnapshotOptions;
use crate::shared::maybe_transpile_source; use crate::shared::maybe_transpile_source;
use crate::shared::runtime; use crate::shared::runtime;
use deno_cache::SqliteBackedCache; use deno_cache::SqliteBackedCache;
use deno_core::error::AnyError;
use deno_core::snapshot::*; use deno_core::snapshot::*;
use deno_core::v8; use deno_core::v8;
use deno_core::Extension; use deno_core::Extension;
use deno_http::DefaultHttpPropertyExtractor; use deno_http::DefaultHttpPropertyExtractor;
use deno_io::fs::FsError; use deno_io::fs::FsError;
use deno_permissions::PermissionCheckError;
use std::borrow::Cow; use std::borrow::Cow;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
@ -26,7 +26,7 @@ impl deno_websocket::WebSocketPermissions for Permissions {
&mut self, &mut self,
_url: &deno_core::url::Url, _url: &deno_core::url::Url,
_api_name: &str, _api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
} }
@ -42,7 +42,7 @@ impl deno_fetch::FetchPermissions for Permissions {
&mut self, &mut self,
_url: &deno_core::url::Url, _url: &deno_core::url::Url,
_api_name: &str, _api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -50,28 +50,26 @@ impl deno_fetch::FetchPermissions for Permissions {
&mut self, &mut self,
_p: &'a Path, _p: &'a Path,
_api_name: &str, _api_name: &str,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
} }
impl deno_ffi::FfiPermissions for Permissions { impl deno_ffi::FfiPermissions for Permissions {
fn check_partial_no_path( fn check_partial_no_path(&mut self) -> Result<(), PermissionCheckError> {
&mut self,
) -> Result<(), deno_core::error::AnyError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn check_partial_with_path( fn check_partial_with_path(
&mut self, &mut self,
_path: &str, _path: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
} }
impl deno_napi::NapiPermissions for Permissions { impl deno_napi::NapiPermissions for Permissions {
fn check(&mut self, _path: &str) -> std::result::Result<PathBuf, AnyError> { fn check(&mut self, _path: &str) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
} }
@ -81,20 +79,20 @@ impl deno_node::NodePermissions for Permissions {
&mut self, &mut self,
_url: &deno_core::url::Url, _url: &deno_core::url::Url,
_api_name: &str, _api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn check_read_path<'a>( fn check_read_path<'a>(
&mut self, &mut self,
_path: &'a Path, _path: &'a Path,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn check_read_with_api_name( fn check_read_with_api_name(
&mut self, &mut self,
_p: &str, _p: &str,
_api_name: Option<&str>, _api_name: Option<&str>,
) -> Result<PathBuf, deno_core::error::AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn query_read_all(&mut self) -> bool { fn query_read_all(&mut self) -> bool {
@ -104,14 +102,14 @@ impl deno_node::NodePermissions for Permissions {
&mut self, &mut self,
_p: &str, _p: &str,
_api_name: Option<&str>, _api_name: Option<&str>,
) -> Result<PathBuf, deno_core::error::AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn check_sys( fn check_sys(
&mut self, &mut self,
_kind: &str, _kind: &str,
_api_name: &str, _api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
} }
@ -121,7 +119,7 @@ impl deno_net::NetPermissions for Permissions {
&mut self, &mut self,
_host: &(T, Option<u16>), _host: &(T, Option<u16>),
_api_name: &str, _api_name: &str,
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -129,7 +127,7 @@ impl deno_net::NetPermissions for Permissions {
&mut self, &mut self,
_p: &str, _p: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, deno_core::error::AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -137,7 +135,7 @@ impl deno_net::NetPermissions for Permissions {
&mut self, &mut self,
_p: &str, _p: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, deno_core::error::AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -145,7 +143,7 @@ impl deno_net::NetPermissions for Permissions {
&mut self, &mut self,
_p: &'a Path, _p: &'a Path,
_api_name: &str, _api_name: &str,
) -> Result<std::borrow::Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
} }
@ -158,7 +156,7 @@ impl deno_fs::FsPermissions for Permissions {
_write: bool, _write: bool,
_path: &'a Path, _path: &'a Path,
_api_name: &str, _api_name: &str,
) -> Result<std::borrow::Cow<'a, Path>, FsError> { ) -> Result<Cow<'a, Path>, FsError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -166,11 +164,14 @@ impl deno_fs::FsPermissions for Permissions {
&mut self, &mut self,
_path: &str, _path: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn check_read_all(&mut self, _api_name: &str) -> Result<(), AnyError> { fn check_read_all(
&mut self,
_api_name: &str,
) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -179,7 +180,7 @@ impl deno_fs::FsPermissions for Permissions {
_path: &Path, _path: &Path,
_display: &str, _display: &str,
_api_name: &str, _api_name: &str,
) -> Result<(), AnyError> { ) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -187,7 +188,7 @@ impl deno_fs::FsPermissions for Permissions {
&mut self, &mut self,
_path: &str, _path: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -195,11 +196,14 @@ impl deno_fs::FsPermissions for Permissions {
&mut self, &mut self,
_path: &str, _path: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn check_write_all(&mut self, _api_name: &str) -> Result<(), AnyError> { fn check_write_all(
&mut self,
_api_name: &str,
) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -208,7 +212,7 @@ impl deno_fs::FsPermissions for Permissions {
_path: &Path, _path: &Path,
_display: &str, _display: &str,
_api_name: &str, _api_name: &str,
) -> Result<(), AnyError> { ) -> Result<(), PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -216,7 +220,7 @@ impl deno_fs::FsPermissions for Permissions {
&mut self, &mut self,
_path: &'a Path, _path: &'a Path,
_api_name: &str, _api_name: &str,
) -> Result<std::borrow::Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -224,7 +228,7 @@ impl deno_fs::FsPermissions for Permissions {
&mut self, &mut self,
_path: &'a Path, _path: &'a Path,
_api_name: &str, _api_name: &str,
) -> Result<std::borrow::Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
} }
@ -234,7 +238,7 @@ impl deno_kv::sqlite::SqliteDbHandlerPermissions for Permissions {
&mut self, &mut self,
_path: &str, _path: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
@ -242,7 +246,7 @@ impl deno_kv::sqlite::SqliteDbHandlerPermissions for Permissions {
&mut self, &mut self,
_path: &'a Path, _path: &'a Path,
_api_name: &str, _api_name: &str,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, PermissionCheckError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
} }