diff options
| author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-01-10 14:35:44 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-10 14:35:44 +0100 |
| commit | 636352e0ca1e611c7673f2ab68538e1ddb2dc5b7 (patch) | |
| tree | c250c7a74917cef683999e06283ea9f7182f372c /ext | |
| parent | 45768f0e832e54d61ddb5a62d62239aef0e597b5 (diff) | |
fix(npm): allow to read package.json if permissions are granted (#17209)
This commit changes signature of "deno_core::ModuleLoader::resolve" to pass
an enum indicating whether or not we're resolving a specifier for dynamic import.
Additionally "CliModuleLoader" was changes to store both "parent permissions" (or
"root permissions") as well as "dynamic permissions" that allow to check for permissions
in top-level module load an dynamic imports.
Then all code paths that have anything to do with Node/npm compat are now checking
for permissions which are passed from module loader instance associated with given
worker.
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/node/lib.rs | 59 | ||||
| -rw-r--r-- | ext/node/package_json.rs | 4 | ||||
| -rw-r--r-- | ext/node/resolution.rs | 31 |
3 files changed, 71 insertions, 23 deletions
diff --git a/ext/node/lib.rs b/ext/node/lib.rs index a670586d1..8a36e95fa 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -53,7 +53,11 @@ pub trait RequireNpmResolver { fn in_npm_package(&self, path: &Path) -> bool; - fn ensure_read_permission(&self, path: &Path) -> Result<(), AnyError>; + fn ensure_read_permission( + &self, + permissions: &mut dyn NodePermissions, + path: &Path, + ) -> Result<(), AnyError>; } pub const MODULE_ES_SHIM: &str = include_str!("./module_es_shim.js"); @@ -95,7 +99,7 @@ pub fn init<P: NodePermissions + 'static>( op_require_is_request_relative::decl(), op_require_resolve_lookup_paths::decl(), op_require_try_self_parent_path::decl::<P>(), - op_require_try_self::decl(), + op_require_try_self::decl::<P>(), op_require_real_path::decl::<P>(), op_require_path_is_absolute::decl(), op_require_path_dirname::decl(), @@ -104,9 +108,9 @@ pub fn init<P: NodePermissions + 'static>( op_require_path_basename::decl(), op_require_read_file::decl::<P>(), op_require_as_file_path::decl(), - op_require_resolve_exports::decl(), + op_require_resolve_exports::decl::<P>(), op_require_read_closest_package_json::decl::<P>(), - op_require_read_package_scope::decl(), + op_require_read_package_scope::decl::<P>(), op_require_package_imports_resolve::decl::<P>(), op_require_break_on_next_statement::decl(), ]) @@ -130,11 +134,8 @@ where let resolver = state.borrow::<Rc<dyn RequireNpmResolver>>(); resolver.clone() }; - if resolver.ensure_read_permission(file_path).is_ok() { - return Ok(()); - } - - state.borrow_mut::<P>().check_read(file_path) + let permissions = state.borrow_mut::<P>(); + resolver.ensure_read_permission(permissions, file_path) } #[op] @@ -459,19 +460,24 @@ where } #[op] -fn op_require_try_self( +fn op_require_try_self<P>( state: &mut OpState, parent_path: Option<String>, request: String, -) -> Result<Option<String>, AnyError> { +) -> Result<Option<String>, AnyError> +where + P: NodePermissions + 'static, +{ if parent_path.is_none() { return Ok(None); } let resolver = state.borrow::<Rc<dyn RequireNpmResolver>>().clone(); + let permissions = state.borrow_mut::<P>(); let pkg = resolution::get_package_scope_config( &Url::from_file_path(parent_path.unwrap()).unwrap(), &*resolver, + permissions, ) .ok(); if pkg.is_none() { @@ -508,6 +514,7 @@ fn op_require_try_self( resolution::REQUIRE_CONDITIONS, NodeResolutionMode::Execution, &*resolver, + permissions, ) .map(|r| Some(r.to_string_lossy().to_string())) } else { @@ -540,7 +547,7 @@ pub fn op_require_as_file_path(file_or_url: String) -> String { } #[op] -fn op_require_resolve_exports( +fn op_require_resolve_exports<P>( state: &mut OpState, uses_local_node_modules_dir: bool, modules_path: String, @@ -548,8 +555,12 @@ fn op_require_resolve_exports( name: String, expansion: String, parent_path: String, -) -> Result<Option<String>, AnyError> { +) -> Result<Option<String>, AnyError> +where + P: NodePermissions + 'static, +{ let resolver = state.borrow::<Rc<dyn RequireNpmResolver>>().clone(); + let permissions = state.borrow_mut::<P>(); let pkg_path = if resolver.in_npm_package(&PathBuf::from(&modules_path)) && !uses_local_node_modules_dir @@ -560,6 +571,7 @@ fn op_require_resolve_exports( }; let pkg = PackageJson::load( &*resolver, + permissions, PathBuf::from(&pkg_path).join("package.json"), )?; @@ -574,6 +586,7 @@ fn op_require_resolve_exports( resolution::REQUIRE_CONDITIONS, NodeResolutionMode::Execution, &*resolver, + permissions, ) .map(|r| Some(r.to_string_lossy().to_string())) } else { @@ -594,20 +607,26 @@ where PathBuf::from(&filename).parent().unwrap(), )?; let resolver = state.borrow::<Rc<dyn RequireNpmResolver>>().clone(); + let permissions = state.borrow_mut::<P>(); resolution::get_closest_package_json( &Url::from_file_path(filename).unwrap(), &*resolver, + permissions, ) } #[op] -fn op_require_read_package_scope( +fn op_require_read_package_scope<P>( state: &mut OpState, package_json_path: String, -) -> Option<PackageJson> { +) -> Option<PackageJson> +where + P: NodePermissions + 'static, +{ let resolver = state.borrow::<Rc<dyn RequireNpmResolver>>().clone(); + let permissions = state.borrow_mut::<P>(); let package_json_path = PathBuf::from(package_json_path); - PackageJson::load(&*resolver, package_json_path).ok() + PackageJson::load(&*resolver, permissions, package_json_path).ok() } #[op] @@ -622,7 +641,12 @@ where let parent_path = PathBuf::from(&parent_filename); ensure_read_permission::<P>(state, &parent_path)?; let resolver = state.borrow::<Rc<dyn RequireNpmResolver>>().clone(); - let pkg = PackageJson::load(&*resolver, parent_path.join("package.json"))?; + let permissions = state.borrow_mut::<P>(); + let pkg = PackageJson::load( + &*resolver, + permissions, + parent_path.join("package.json"), + )?; if pkg.imports.is_some() { let referrer = @@ -634,6 +658,7 @@ where resolution::REQUIRE_CONDITIONS, NodeResolutionMode::Execution, &*resolver, + permissions, ) .map(|r| Some(Url::from_file_path(r).unwrap().to_string())); state.put(resolver); diff --git a/ext/node/package_json.rs b/ext/node/package_json.rs index f0a2b4f4d..5894b8831 100644 --- a/ext/node/package_json.rs +++ b/ext/node/package_json.rs @@ -1,6 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use crate::NodeModuleKind; +use crate::NodePermissions; use super::RequireNpmResolver; use deno_core::anyhow; @@ -47,9 +48,10 @@ impl PackageJson { pub fn load( resolver: &dyn RequireNpmResolver, + permissions: &mut dyn NodePermissions, path: PathBuf, ) -> Result<PackageJson, AnyError> { - resolver.ensure_read_permission(&path)?; + resolver.ensure_read_permission(permissions, &path)?; Self::load_skip_read_permission(path) } diff --git a/ext/node/resolution.rs b/ext/node/resolution.rs index 7500f0f31..e930215fd 100644 --- a/ext/node/resolution.rs +++ b/ext/node/resolution.rs @@ -15,6 +15,7 @@ use regex::Regex; use crate::errors; use crate::package_json::PackageJson; use crate::path::PathClean; +use crate::NodePermissions; use crate::RequireNpmResolver; pub static DEFAULT_CONDITIONS: &[&str] = &["deno", "node", "import"]; @@ -188,6 +189,7 @@ pub fn package_imports_resolve( conditions: &[&str], mode: NodeResolutionMode, npm_resolver: &dyn RequireNpmResolver, + permissions: &mut dyn NodePermissions, ) -> Result<PathBuf, AnyError> { if name == "#" || name.starts_with("#/") || name.ends_with('/') { let reason = "is not a valid internal imports specifier name"; @@ -198,7 +200,8 @@ pub fn package_imports_resolve( )); } - let package_config = get_package_scope_config(referrer, npm_resolver)?; + let package_config = + get_package_scope_config(referrer, npm_resolver, permissions)?; let mut package_json_path = None; if package_config.exists { package_json_path = Some(package_config.path.clone()); @@ -216,6 +219,7 @@ pub fn package_imports_resolve( conditions, mode, npm_resolver, + permissions, )?; if let Some(resolved) = maybe_resolved { return Ok(resolved); @@ -258,6 +262,7 @@ pub fn package_imports_resolve( conditions, mode, npm_resolver, + permissions, )?; if let Some(resolved) = maybe_resolved { return Ok(resolved); @@ -322,6 +327,7 @@ fn resolve_package_target_string( conditions: &[&str], mode: NodeResolutionMode, npm_resolver: &dyn RequireNpmResolver, + permissions: &mut dyn NodePermissions, ) -> Result<PathBuf, AnyError> { if !subpath.is_empty() && !pattern && !target.ends_with('/') { return Err(throw_invalid_package_target( @@ -355,6 +361,7 @@ fn resolve_package_target_string( conditions, mode, npm_resolver, + permissions, ) { Ok(Some(path)) => Ok(path), Ok(None) => Err(generic_error("not found")), @@ -430,6 +437,7 @@ fn resolve_package_target( conditions: &[&str], mode: NodeResolutionMode, npm_resolver: &dyn RequireNpmResolver, + permissions: &mut dyn NodePermissions, ) -> Result<Option<PathBuf>, AnyError> { if let Some(target) = target.as_str() { return resolve_package_target_string( @@ -444,6 +452,7 @@ fn resolve_package_target( conditions, mode, npm_resolver, + permissions, ) .map(|path| { if mode.is_types() { @@ -471,6 +480,7 @@ fn resolve_package_target( conditions, mode, npm_resolver, + permissions, ); match resolved_result { @@ -520,6 +530,7 @@ fn resolve_package_target( conditions, mode, npm_resolver, + permissions, )?; match resolved { Some(resolved) => return Ok(Some(resolved)), @@ -564,6 +575,7 @@ pub fn package_exports_resolve( conditions: &[&str], mode: NodeResolutionMode, npm_resolver: &dyn RequireNpmResolver, + permissions: &mut dyn NodePermissions, ) -> Result<PathBuf, AnyError> { if package_exports.contains_key(&package_subpath) && package_subpath.find('*').is_none() @@ -582,6 +594,7 @@ pub fn package_exports_resolve( conditions, mode, npm_resolver, + permissions, )?; if resolved.is_none() { return Err(throw_exports_not_found( @@ -641,6 +654,7 @@ pub fn package_exports_resolve( conditions, mode, npm_resolver, + permissions, )?; if let Some(resolved) = maybe_resolved { return Ok(resolved); @@ -718,12 +732,14 @@ pub fn package_resolve( conditions: &[&str], mode: NodeResolutionMode, npm_resolver: &dyn RequireNpmResolver, + permissions: &mut dyn NodePermissions, ) -> Result<Option<PathBuf>, AnyError> { let (package_name, package_subpath, _is_scoped) = parse_package_name(specifier, referrer)?; // ResolveSelf - let package_config = get_package_scope_config(referrer, npm_resolver)?; + let package_config = + get_package_scope_config(referrer, npm_resolver, permissions)?; if package_config.exists && package_config.name.as_ref() == Some(&package_name) { @@ -737,6 +753,7 @@ pub fn package_resolve( conditions, mode, npm_resolver, + permissions, ) .map(Some); } @@ -763,7 +780,8 @@ pub fn package_resolve( // )) // Package match. - let package_json = PackageJson::load(npm_resolver, package_json_path)?; + let package_json = + PackageJson::load(npm_resolver, permissions, package_json_path)?; if let Some(exports) = &package_json.exports { return package_exports_resolve( &package_json.path, @@ -774,6 +792,7 @@ pub fn package_resolve( conditions, mode, npm_resolver, + permissions, ) .map(Some); } @@ -795,19 +814,21 @@ pub fn package_resolve( pub fn get_package_scope_config( referrer: &ModuleSpecifier, npm_resolver: &dyn RequireNpmResolver, + permissions: &mut dyn NodePermissions, ) -> Result<PackageJson, AnyError> { let root_folder = npm_resolver .resolve_package_folder_from_path(&referrer.to_file_path().unwrap())?; let package_json_path = root_folder.join("package.json"); - PackageJson::load(npm_resolver, package_json_path) + PackageJson::load(npm_resolver, permissions, package_json_path) } pub fn get_closest_package_json( url: &ModuleSpecifier, npm_resolver: &dyn RequireNpmResolver, + permissions: &mut dyn NodePermissions, ) -> Result<PackageJson, AnyError> { let package_json_path = get_closest_package_json_path(url, npm_resolver)?; - PackageJson::load(npm_resolver, package_json_path) + PackageJson::load(npm_resolver, permissions, package_json_path) } fn get_closest_package_json_path( |
