0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-07 23:06:50 -05:00

Merge branch 'main' into cjs_suggestions_for_mjs

This commit is contained in:
Mohammad Sulaiman 2024-11-05 08:04:03 +02:00 committed by GitHub
commit 63115d2960
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
96 changed files with 1467 additions and 962 deletions

View file

@ -68,7 +68,7 @@
"third_party" "third_party"
], ],
"plugins": [ "plugins": [
"https://plugins.dprint.dev/typescript-0.93.1.wasm", "https://plugins.dprint.dev/typescript-0.93.2.wasm",
"https://plugins.dprint.dev/json-0.19.4.wasm", "https://plugins.dprint.dev/json-0.19.4.wasm",
"https://plugins.dprint.dev/markdown-0.17.8.wasm", "https://plugins.dprint.dev/markdown-0.17.8.wasm",
"https://plugins.dprint.dev/toml-0.6.3.wasm", "https://plugins.dprint.dev/toml-0.6.3.wasm",

View file

@ -14,6 +14,7 @@ const windowsX86Runner = "windows-2022";
const windowsX86XlRunner = "windows-2022-xl"; const windowsX86XlRunner = "windows-2022-xl";
const macosX86Runner = "macos-13"; const macosX86Runner = "macos-13";
const macosArmRunner = "macos-14"; const macosArmRunner = "macos-14";
const selfHostedMacosArmRunner = "self-hosted";
const Runners = { const Runners = {
linuxX86: { linuxX86: {
@ -40,7 +41,8 @@ const Runners = {
macosArm: { macosArm: {
os: "macos", os: "macos",
arch: "aarch64", arch: "aarch64",
runner: macosArmRunner, runner:
`\${{ github.repository == 'denoland/deno' && startsWith(github.ref, 'refs/tags/') && '${selfHostedMacosArmRunner}' || '${macosArmRunner}' }}`,
}, },
windowsX86: { windowsX86: {
os: "windows", os: "windows",

View file

@ -68,12 +68,12 @@ jobs:
skip: '${{ !contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'') }}' skip: '${{ !contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'') }}'
- os: macos - os: macos
arch: aarch64 arch: aarch64
runner: macos-14 runner: '${{ github.repository == ''denoland/deno'' && startsWith(github.ref, ''refs/tags/'') && ''self-hosted'' || ''macos-14'' }}'
job: test job: test
profile: debug profile: debug
- os: macos - os: macos
arch: aarch64 arch: aarch64
runner: '${{ (!contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'')) && ''ubuntu-24.04'' || ''macos-14'' }}' runner: '${{ (!contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'')) && ''ubuntu-24.04'' || github.repository == ''denoland/deno'' && startsWith(github.ref, ''refs/tags/'') && ''self-hosted'' || ''macos-14'' }}'
job: test job: test
profile: release profile: release
skip: '${{ !contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'') }}' skip: '${{ !contains(github.event.pull_request.labels.*.name, ''ci-full'') && (github.event_name == ''pull_request'') }}'

21
Cargo.lock generated
View file

@ -1387,9 +1387,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_config" name = "deno_config"
version = "0.37.2" version = "0.38.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5900bfb37538d83b19ba0b157cdc785770e38422ee4632411e3bd3d90ac0f537" checksum = "966825073480a6ac7e01977a3879d13edc8d6ea2d65ea164b37156a5fb206e9a"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"deno_package_json", "deno_package_json",
@ -1418,9 +1418,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_core" name = "deno_core"
version = "0.316.0" version = "0.318.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94f68061c88ced959c6b0417f0f0d0b3dbeaeb18013b55f86c505e9fba705cf8" checksum = "10cae2393219ff9278123f7b24799cdfab37c7d6561b69ca06ced115cac92111"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1921,9 +1921,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_ops" name = "deno_ops"
version = "0.192.0" version = "0.194.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdb7096887508456349d7e7e09e326d157d4dba46ef1f5849bc544592ea3042a" checksum = "f760b492bd638c1dc3e992d11672c259fbe9a233162099a8347591c9e22d0391"
dependencies = [ dependencies = [
"proc-macro-rules", "proc-macro-rules",
"proc-macro2", "proc-macro2",
@ -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",
] ]
@ -2608,9 +2609,9 @@ dependencies = [
[[package]] [[package]]
name = "dprint-plugin-typescript" name = "dprint-plugin-typescript"
version = "0.93.1" version = "0.93.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5abfd78fe3cde4f5a6699d65f760c8d44da130cf446b6f80a7a9bc6580e156ab" checksum = "3ff29fd136541e59d51946f0d2d353fefc886776f61a799ebfb5838b06cef13b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"deno_ast", "deno_ast",
@ -6169,9 +6170,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_v8" name = "serde_v8"
version = "0.225.0" version = "0.227.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce4b71200ef49a9e629edaea3d13fc98c25ede07e1496558df7f09354e37976f" checksum = "0a8294c2223c53bed343be8b80564ece4dc0d03b643b06fa86c4ccc0e064eda0"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"serde", "serde",

View file

@ -46,7 +46,7 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies] [workspace.dependencies]
deno_ast = { version = "=0.43.3", features = ["transpiling"] } deno_ast = { version = "=0.43.3", features = ["transpiling"] }
deno_core = { version = "0.316.0" } deno_core = { version = "0.318.0" }
deno_bench_util = { version = "0.169.0", path = "./bench_util" } deno_bench_util = { version = "0.169.0", path = "./bench_util" }
deno_lockfile = "=0.23.1" deno_lockfile = "=0.23.1"

View file

@ -70,7 +70,7 @@ winres.workspace = true
[dependencies] [dependencies]
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] } deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
deno_cache_dir = { workspace = true } deno_cache_dir = { workspace = true }
deno_config = { version = "=0.37.2", features = ["workspace", "sync"] } deno_config = { version = "=0.38.2", features = ["workspace", "sync"] }
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_doc = { version = "0.156.0", default-features = false, features = ["rust", "html", "syntect"] } deno_doc = { version = "0.156.0", default-features = false, features = ["rust", "html", "syntect"] }
deno_graph = { version = "=0.84.1" } deno_graph = { version = "=0.84.1" }
@ -107,7 +107,7 @@ dotenvy = "0.15.7"
dprint-plugin-json = "=0.19.4" dprint-plugin-json = "=0.19.4"
dprint-plugin-jupyter = "=0.1.5" dprint-plugin-jupyter = "=0.1.5"
dprint-plugin-markdown = "=0.17.8" dprint-plugin-markdown = "=0.17.8"
dprint-plugin-typescript = "=0.93.1" dprint-plugin-typescript = "=0.93.2"
env_logger = "=0.10.0" env_logger = "=0.10.0"
fancy-regex = "=0.10.0" fancy-regex = "=0.10.0"
faster-hex.workspace = true faster-hex.workspace = true

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

@ -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.
// deno-lint-ignore-file no-console no-process-globals
// deno-lint-ignore-file no-console
let [total, count] = typeof Deno !== "undefined" let [total, count] = typeof Deno !== "undefined"
? Deno.args ? Deno.args

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.
// deno-lint-ignore-file no-console no-process-globals
// deno-lint-ignore-file no-console
let [total, count] = typeof Deno !== "undefined" let [total, count] = typeof Deno !== "undefined"
? Deno.args ? Deno.args

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.
// deno-lint-ignore-file no-console no-process-globals
// deno-lint-ignore-file no-console
const queueMicrotask = globalThis.queueMicrotask || process.nextTick; const queueMicrotask = globalThis.queueMicrotask || process.nextTick;
let [total, count] = typeof Deno !== "undefined" let [total, count] = typeof Deno !== "undefined"

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.
// deno-lint-ignore-file no-console no-process-globals
// deno-lint-ignore-file no-console
let [total, count] = typeof Deno !== "undefined" let [total, count] = typeof Deno !== "undefined"
? Deno.args ? Deno.args

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.
// deno-lint-ignore-file no-console no-process-globals
// deno-lint-ignore-file no-console
const queueMicrotask = globalThis.queueMicrotask || process.nextTick; const queueMicrotask = globalThis.queueMicrotask || process.nextTick;
let [total, count] = typeof Deno !== "undefined" let [total, count] = typeof Deno !== "undefined"

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.
// deno-lint-ignore-file no-console no-process-globals
// deno-lint-ignore-file no-console
const queueMicrotask = globalThis.queueMicrotask || process.nextTick; const queueMicrotask = globalThis.queueMicrotask || process.nextTick;
let [total, count] = typeof Deno !== "undefined" let [total, count] = typeof Deno !== "undefined"

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.
// deno-lint-ignore-file no-console no-process-globals
// deno-lint-ignore-file no-console
const queueMicrotask = globalThis.queueMicrotask || process.nextTick; const queueMicrotask = globalThis.queueMicrotask || process.nextTick;
let [total, count] = typeof Deno !== "undefined" let [total, count] = typeof Deno !== "undefined"

View file

@ -863,7 +863,10 @@ impl Inner {
// We ignore these directories by default because there is a // We ignore these directories by default because there is a
// high likelihood they aren't relevant. Someone can opt-into // high likelihood they aren't relevant. Someone can opt-into
// them by specifying one of them as an enabled path. // them by specifying one of them as an enabled path.
if matches!(dir_name.as_str(), "vendor" | "node_modules" | ".git") { if matches!(
dir_name.as_str(),
"vendor" | "coverage" | "node_modules" | ".git"
) {
continue; continue;
} }
// ignore cargo target directories for anyone using Deno with Rust // ignore cargo target directories for anyone using Deno with Rust
@ -3944,7 +3947,9 @@ mod tests {
fn test_walk_workspace() { fn test_walk_workspace() {
let temp_dir = TempDir::new(); let temp_dir = TempDir::new();
temp_dir.create_dir_all("root1/vendor/"); temp_dir.create_dir_all("root1/vendor/");
temp_dir.create_dir_all("root1/coverage/");
temp_dir.write("root1/vendor/mod.ts", ""); // no, vendor temp_dir.write("root1/vendor/mod.ts", ""); // no, vendor
temp_dir.write("root1/coverage/mod.ts", ""); // no, coverage
temp_dir.create_dir_all("root1/node_modules/"); temp_dir.create_dir_all("root1/node_modules/");
temp_dir.write("root1/node_modules/mod.ts", ""); // no, node_modules temp_dir.write("root1/node_modules/mod.ts", ""); // no, node_modules

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

@ -1035,12 +1035,18 @@ fn junction_or_symlink_dir(
if symlink_err.kind() == std::io::ErrorKind::PermissionDenied => if symlink_err.kind() == std::io::ErrorKind::PermissionDenied =>
{ {
USE_JUNCTIONS.store(true, std::sync::atomic::Ordering::Relaxed); USE_JUNCTIONS.store(true, std::sync::atomic::Ordering::Relaxed);
junction::create(old_path, new_path).map_err(Into::into) junction::create(old_path, new_path)
.context("Failed creating junction in node_modules folder")
}
Err(symlink_err) => {
log::warn!(
"{} Unexpected error symlinking node_modules: {symlink_err}",
colors::yellow("Warning")
);
USE_JUNCTIONS.store(true, std::sync::atomic::Ordering::Relaxed);
junction::create(old_path, new_path)
.context("Failed creating junction in node_modules folder")
} }
Err(symlink_err) => Err(
AnyError::from(symlink_err)
.context("Failed creating symlink in node_modules folder"),
),
} }
} }

View file

@ -353,6 +353,21 @@ fn format_yaml(
file_text: &str, file_text: &str,
fmt_options: &FmtOptionsConfig, fmt_options: &FmtOptionsConfig,
) -> Result<Option<String>, AnyError> { ) -> Result<Option<String>, AnyError> {
let ignore_file = file_text
.lines()
.take_while(|line| line.starts_with('#'))
.any(|line| {
line
.strip_prefix('#')
.unwrap()
.trim()
.starts_with("deno-fmt-ignore-file")
});
if ignore_file {
return Ok(None);
}
let formatted_str = let formatted_str =
pretty_yaml::format_text(file_text, &get_resolved_yaml_config(fmt_options)) pretty_yaml::format_text(file_text, &get_resolved_yaml_config(fmt_options))
.map_err(AnyError::from)?; .map_err(AnyError::from)?;

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

@ -12,7 +12,9 @@ use deno_core::futures::StreamExt;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use deno_semver::jsr::JsrPackageReqReference; use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use deno_semver::Version;
use deno_semver::VersionReq; use deno_semver::VersionReq;
use jsonc_parser::cst::CstObject; use jsonc_parser::cst::CstObject;
use jsonc_parser::cst::CstObjectProp; use jsonc_parser::cst::CstObjectProp;
@ -455,15 +457,32 @@ pub async fn add(
match package_and_version { match package_and_version {
PackageAndVersion::NotFound { PackageAndVersion::NotFound {
package: package_name, package: package_name,
found_npm_package, help,
package_req, package_req,
} => { } => match help {
if found_npm_package { Some(NotFoundHelp::NpmPackage) => {
bail!("{} was not found, but a matching npm package exists. Did you mean `{}`?", crate::colors::red(package_name), crate::colors::yellow(format!("deno {cmd_name} npm:{package_req}"))); bail!(
} else { "{} was not found, but a matching npm package exists. Did you mean `{}`?",
bail!("{} was not found.", crate::colors::red(package_name)); crate::colors::red(package_name),
crate::colors::yellow(format!("deno {cmd_name} npm:{package_req}"))
);
} }
} Some(NotFoundHelp::JsrPackage) => {
bail!(
"{} was not found, but a matching jsr package exists. Did you mean `{}`?",
crate::colors::red(package_name),
crate::colors::yellow(format!("deno {cmd_name} jsr:{package_req}"))
)
}
Some(NotFoundHelp::PreReleaseVersion(version)) => {
bail!(
"{} has only pre-release versions available. Try specifying a version: `{}`",
crate::colors::red(&package_name),
crate::colors::yellow(format!("deno {cmd_name} {package_name}@^{version}"))
)
}
None => bail!("{} was not found.", crate::colors::red(package_name)),
},
PackageAndVersion::Selected(selected) => { PackageAndVersion::Selected(selected) => {
selected_packages.push(selected); selected_packages.push(selected);
} }
@ -511,76 +530,144 @@ struct SelectedPackage {
selected_version: String, selected_version: String,
} }
enum NotFoundHelp {
NpmPackage,
JsrPackage,
PreReleaseVersion(Version),
}
enum PackageAndVersion { enum PackageAndVersion {
NotFound { NotFound {
package: String, package: String,
found_npm_package: bool,
package_req: PackageReq, package_req: PackageReq,
help: Option<NotFoundHelp>,
}, },
Selected(SelectedPackage), Selected(SelectedPackage),
} }
fn best_version<'a>(
versions: impl Iterator<Item = &'a Version>,
) -> Option<&'a Version> {
let mut maybe_best_version: Option<&Version> = None;
for version in versions {
let is_best_version = maybe_best_version
.as_ref()
.map(|best_version| (*best_version).cmp(version).is_lt())
.unwrap_or(true);
if is_best_version {
maybe_best_version = Some(version);
}
}
maybe_best_version
}
trait PackageInfoProvider {
const SPECIFIER_PREFIX: &str;
/// The help to return if a package is found by this provider
const HELP: NotFoundHelp;
async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv>;
async fn latest_version<'a>(&self, req: &PackageReq) -> Option<Version>;
}
impl PackageInfoProvider for Arc<JsrFetchResolver> {
const HELP: NotFoundHelp = NotFoundHelp::JsrPackage;
const SPECIFIER_PREFIX: &str = "jsr";
async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv> {
(**self).req_to_nv(req).await
}
async fn latest_version<'a>(&self, req: &PackageReq) -> Option<Version> {
let info = self.package_info(&req.name).await?;
best_version(
info
.versions
.iter()
.filter(|(_, version_info)| !version_info.yanked)
.map(|(version, _)| version),
)
.cloned()
}
}
impl PackageInfoProvider for Arc<NpmFetchResolver> {
const HELP: NotFoundHelp = NotFoundHelp::NpmPackage;
const SPECIFIER_PREFIX: &str = "npm";
async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv> {
(**self).req_to_nv(req).await
}
async fn latest_version<'a>(&self, req: &PackageReq) -> Option<Version> {
let info = self.package_info(&req.name).await?;
best_version(info.versions.keys()).cloned()
}
}
async fn find_package_and_select_version_for_req( async fn find_package_and_select_version_for_req(
jsr_resolver: Arc<JsrFetchResolver>, jsr_resolver: Arc<JsrFetchResolver>,
npm_resolver: Arc<NpmFetchResolver>, npm_resolver: Arc<NpmFetchResolver>,
add_package_req: AddRmPackageReq, add_package_req: AddRmPackageReq,
) -> Result<PackageAndVersion, AnyError> { ) -> Result<PackageAndVersion, AnyError> {
match add_package_req.value { async fn select<T: PackageInfoProvider, S: PackageInfoProvider>(
AddRmPackageReqValue::Jsr(req) => { main_resolver: T,
let jsr_prefixed_name = format!("jsr:{}", &req.name); fallback_resolver: S,
let Some(nv) = jsr_resolver.req_to_nv(&req).await else { add_package_req: AddRmPackageReq,
if npm_resolver.req_to_nv(&req).await.is_some() { ) -> Result<PackageAndVersion, AnyError> {
let req = match &add_package_req.value {
AddRmPackageReqValue::Jsr(req) => req,
AddRmPackageReqValue::Npm(req) => req,
};
let prefixed_name = format!("{}:{}", T::SPECIFIER_PREFIX, req.name);
let help_if_found_in_fallback = S::HELP;
let Some(nv) = main_resolver.req_to_nv(req).await else {
if fallback_resolver.req_to_nv(req).await.is_some() {
// it's in the other registry
return Ok(PackageAndVersion::NotFound {
package: prefixed_name,
help: Some(help_if_found_in_fallback),
package_req: req.clone(),
});
}
if req.version_req.version_text() == "*" {
if let Some(pre_release_version) =
main_resolver.latest_version(req).await
{
return Ok(PackageAndVersion::NotFound { return Ok(PackageAndVersion::NotFound {
package: jsr_prefixed_name, package: prefixed_name,
found_npm_package: true, package_req: req.clone(),
package_req: req, help: Some(NotFoundHelp::PreReleaseVersion(
pre_release_version.clone(),
)),
}); });
} }
}
return Ok(PackageAndVersion::NotFound { return Ok(PackageAndVersion::NotFound {
package: jsr_prefixed_name, package: prefixed_name,
found_npm_package: false, help: None,
package_req: req, package_req: req.clone(),
}); });
}; };
let range_symbol = if req.version_req.version_text().starts_with('~') { let range_symbol = if req.version_req.version_text().starts_with('~') {
"~" "~"
} else if req.version_req.version_text() == nv.version.to_string() { } else if req.version_req.version_text() == nv.version.to_string() {
"" ""
} else { } else {
"^" "^"
}; };
Ok(PackageAndVersion::Selected(SelectedPackage { Ok(PackageAndVersion::Selected(SelectedPackage {
import_name: add_package_req.alias, import_name: add_package_req.alias,
package_name: jsr_prefixed_name, package_name: prefixed_name,
version_req: format!("{}{}", range_symbol, &nv.version), version_req: format!("{}{}", range_symbol, &nv.version),
selected_version: nv.version.to_string(), selected_version: nv.version.to_string(),
})) }))
}
match &add_package_req.value {
AddRmPackageReqValue::Jsr(_) => {
select(jsr_resolver, npm_resolver, add_package_req).await
} }
AddRmPackageReqValue::Npm(req) => { AddRmPackageReqValue::Npm(_) => {
let npm_prefixed_name = format!("npm:{}", &req.name); select(npm_resolver, jsr_resolver, add_package_req).await
let Some(nv) = npm_resolver.req_to_nv(&req).await else {
return Ok(PackageAndVersion::NotFound {
package: npm_prefixed_name,
found_npm_package: false,
package_req: req,
});
};
let range_symbol = if req.version_req.version_text().starts_with('~') {
"~"
} else if req.version_req.version_text() == nv.version.to_string() {
""
} else {
"^"
};
Ok(PackageAndVersion::Selected(SelectedPackage {
import_name: add_package_req.alias,
package_name: npm_prefixed_name,
version_req: format!("{}{}", range_symbol, &nv.version),
selected_version: nv.version.to_string(),
}))
} }
} }
} }

View file

@ -801,13 +801,18 @@ delete Object.prototype.__proto__;
if (logDebug) { if (logDebug) {
debug(`host.getScriptSnapshot("${specifier}")`); debug(`host.getScriptSnapshot("${specifier}")`);
} }
const sourceFile = sourceFileCache.get(specifier); if (specifier.startsWith(ASSETS_URL_PREFIX)) {
if (sourceFile) { const sourceFile = this.getSourceFile(
if (!assetScopes.has(specifier)) { specifier,
assetScopes.set(specifier, lastRequestScope); ts.ScriptTarget.ESNext,
);
if (sourceFile) {
if (!assetScopes.has(specifier)) {
assetScopes.set(specifier, lastRequestScope);
}
// This case only occurs for assets.
return ts.ScriptSnapshot.fromString(sourceFile.text);
} }
// This case only occurs for assets.
return ts.ScriptSnapshot.fromString(sourceFile.text);
} }
let sourceText = sourceTextCache.get(specifier); let sourceText = sourceTextCache.get(specifier);
if (sourceText == undefined) { if (sourceText == undefined) {

View file

@ -556,14 +556,23 @@ declare namespace Deno {
*/ */
env?: "inherit" | boolean | string[]; env?: "inherit" | boolean | string[];
/** Specifies if the `sys` permission should be requested or revoked. /** Specifies if the `ffi` permission should be requested or revoked.
* If set to `"inherit"`, the current `sys` permission will be inherited. * If set to `"inherit"`, the current `ffi` permission will be inherited.
* If set to `true`, the global `sys` permission will be requested. * If set to `true`, the global `ffi` permission will be requested.
* If set to `false`, the global `sys` permission will be revoked. * If set to `false`, the global `ffi` permission will be revoked.
* *
* @default {false} * @default {false}
*/ */
sys?: "inherit" | boolean | string[]; ffi?: "inherit" | boolean | Array<string | URL>;
/** Specifies if the `import` permission should be requested or revoked.
* If set to `"inherit"` the current `import` permission will be inherited.
* If set to `true`, the global `import` permission will be requested.
* If set to `false`, the global `import` permission will be revoked.
* If set to `Array<string>`, the `import` permissions will be requested with the
* specified domains.
*/
import?: "inherit" | boolean | Array<string>;
/** Specifies if the `net` permission should be requested or revoked. /** Specifies if the `net` permission should be requested or revoked.
* if set to `"inherit"`, the current `net` permission will be inherited. * if set to `"inherit"`, the current `net` permission will be inherited.
@ -638,15 +647,6 @@ declare namespace Deno {
*/ */
net?: "inherit" | boolean | string[]; net?: "inherit" | boolean | string[];
/** Specifies if the `ffi` permission should be requested or revoked.
* If set to `"inherit"`, the current `ffi` permission will be inherited.
* If set to `true`, the global `ffi` permission will be requested.
* If set to `false`, the global `ffi` permission will be revoked.
*
* @default {false}
*/
ffi?: "inherit" | boolean | Array<string | URL>;
/** Specifies if the `read` permission should be requested or revoked. /** Specifies if the `read` permission should be requested or revoked.
* If set to `"inherit"`, the current `read` permission will be inherited. * If set to `"inherit"`, the current `read` permission will be inherited.
* If set to `true`, the global `read` permission will be requested. * If set to `true`, the global `read` permission will be requested.
@ -667,6 +667,15 @@ declare namespace Deno {
*/ */
run?: "inherit" | boolean | Array<string | URL>; run?: "inherit" | boolean | Array<string | URL>;
/** Specifies if the `sys` permission should be requested or revoked.
* If set to `"inherit"`, the current `sys` permission will be inherited.
* If set to `true`, the global `sys` permission will be requested.
* If set to `false`, the global `sys` permission will be revoked.
*
* @default {false}
*/
sys?: "inherit" | boolean | string[];
/** Specifies if the `write` permission should be requested or revoked. /** Specifies if the `write` permission should be requested or revoked.
* If set to `"inherit"`, the current `write` permission will be inherited. * If set to `"inherit"`, the current `write` permission will be inherited.
* If set to `true`, the global `write` permission will be requested. * If set to `true`, the global `write` permission will be requested.

View file

@ -565,7 +565,9 @@ pub fn symlink_dir(oldpath: &Path, newpath: &Path) -> Result<(), Error> {
use std::os::windows::fs::symlink_dir; use std::os::windows::fs::symlink_dir;
symlink_dir(oldpath, newpath).map_err(|err| { symlink_dir(oldpath, newpath).map_err(|err| {
if let Some(code) = err.raw_os_error() { if let Some(code) = err.raw_os_error() {
if code as u32 == winapi::shared::winerror::ERROR_PRIVILEGE_NOT_HELD { if code as u32 == winapi::shared::winerror::ERROR_PRIVILEGE_NOT_HELD
|| code as u32 == winapi::shared::winerror::ERROR_INVALID_FUNCTION
{
return err_mapper(err, Some(ErrorKind::PermissionDenied)); return err_mapper(err, Some(ErrorKind::PermissionDenied));
} }
} }

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

@ -1312,6 +1312,8 @@ export function findSourceMap(_path) {
return undefined; return undefined;
} }
Module.findSourceMap = findSourceMap;
/** /**
* @param {string | URL} _specifier * @param {string | URL} _specifier
* @param {string | URL} _parentUrl * @param {string | URL} _parentUrl

View file

@ -20,6 +20,7 @@ import {
notImplemented, notImplemented,
TextEncodings, TextEncodings,
} from "ext:deno_node/_utils.ts"; } from "ext:deno_node/_utils.ts";
import { type Buffer } from "node:buffer";
export type CallbackWithError = (err: ErrnoException | null) => void; export type CallbackWithError = (err: ErrnoException | null) => void;

View file

@ -147,8 +147,8 @@ export function open(
export function openPromise( export function openPromise(
path: string | Buffer | URL, path: string | Buffer | URL,
flags?: openFlags = "r", flags: openFlags = "r",
mode? = 0o666, mode = 0o666,
): Promise<FileHandle> { ): Promise<FileHandle> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
open(path, flags, mode, (err, fd) => { open(path, flags, mode, (err, fd) => {

View file

@ -15,6 +15,7 @@ import { maybeCallback } from "ext:deno_node/_fs/_fs_common.ts";
import { validateInteger } from "ext:deno_node/internal/validators.mjs"; import { validateInteger } from "ext:deno_node/internal/validators.mjs";
import * as io from "ext:deno_io/12_io.js"; import * as io from "ext:deno_io/12_io.js";
import { op_fs_seek_async, op_fs_seek_sync } from "ext:core/ops"; import { op_fs_seek_async, op_fs_seek_sync } from "ext:core/ops";
import process from "node:process";
type Callback = ( type Callback = (
err: ErrnoException | null, err: ErrnoException | null,

View file

@ -29,6 +29,7 @@ import {
} from "ext:deno_node/internal/validators.mjs"; } from "ext:deno_node/internal/validators.mjs";
import { Buffer } from "node:buffer"; import { Buffer } from "node:buffer";
import { KeyFormat, KeyType } from "ext:deno_node/internal/crypto/types.ts"; import { KeyFormat, KeyType } from "ext:deno_node/internal/crypto/types.ts";
import process from "node:process";
import { import {
op_node_generate_dh_group_key, op_node_generate_dh_group_key,

View file

@ -38,6 +38,7 @@ import {
ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_TYPE,
ERR_OUT_OF_RANGE, ERR_OUT_OF_RANGE,
} from "ext:deno_node/internal/errors.ts"; } from "ext:deno_node/internal/errors.ts";
import { Buffer } from "node:buffer";
export { default as randomBytes } from "ext:deno_node/internal/crypto/_randomBytes.ts"; export { default as randomBytes } from "ext:deno_node/internal/crypto/_randomBytes.ts";
export { export {

View file

@ -126,6 +126,7 @@ ObjectSetPrototypeOf(HTTPParser.prototype, AsyncWrap.prototype);
function defineProps(obj: object, props: Record<string, unknown>) { function defineProps(obj: object, props: Record<string, unknown>) {
for (const entry of new SafeArrayIterator(ObjectEntries(props))) { for (const entry of new SafeArrayIterator(ObjectEntries(props))) {
ObjectDefineProperty(obj, entry[0], { ObjectDefineProperty(obj, entry[0], {
__proto__: null,
value: entry[1], value: entry[1],
enumerable: true, enumerable: true,
writable: true, writable: true,

View file

@ -182,6 +182,7 @@ function getContextOptions(options) {
let defaultContextNameIndex = 1; let defaultContextNameIndex = 1;
export function createContext( export function createContext(
// deno-lint-ignore prefer-primordials
contextObject = {}, contextObject = {},
options = { __proto__: null }, options = { __proto__: null },
) { ) {

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

@ -696,6 +696,7 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) {
// are lost. // are lost.
let jupyterNs = undefined; let jupyterNs = undefined;
ObjectDefineProperty(finalDenoNs, "jupyter", { ObjectDefineProperty(finalDenoNs, "jupyter", {
__proto__: null,
get() { get() {
if (jupyterNs) { if (jupyterNs) {
return jupyterNs; return jupyterNs;

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!")
} }
} }

View file

@ -6396,6 +6396,45 @@ fn lsp_cache_on_save() {
client.shutdown(); client.shutdown();
} }
// Regression test for https://github.com/denoland/deno/issues/25999.
#[test]
fn lsp_asset_document_dom_code_action() {
let context = TestContextBuilder::new().use_temp_cwd().build();
let temp_dir = context.temp_dir();
temp_dir.write(
"deno.json",
json!({
"compilerOptions": {
"lib": ["deno.window", "dom"],
},
})
.to_string(),
);
let mut client = context.new_lsp_command().build();
client.initialize_default();
client.did_open(json!({
"textDocument": {
"uri": temp_dir.url().join("file.ts").unwrap(),
"languageId": "typescript",
"version": 1,
"text": r#""#,
},
}));
let res = client.write_request(
"textDocument/codeAction",
json!({
"textDocument": { "uri": "asset:///lib.dom.d.ts" },
"range": {
"start": { "line": 0, "character": 0 },
"end": { "line": 0, "character": 0 },
},
"context": { "diagnostics": [], "only": ["quickfix"] },
}),
);
assert_eq!(res, json!(null));
client.shutdown();
}
// Regression test for https://github.com/denoland/deno/issues/22122. // Regression test for https://github.com/denoland/deno/issues/22122.
#[test] #[test]
fn lsp_cache_then_definition() { fn lsp_cache_then_definition() {

View file

@ -572,16 +572,19 @@ async fn serve_watch_all() {
let main_file_to_watch = t.path().join("main_file_to_watch.js"); let main_file_to_watch = t.path().join("main_file_to_watch.js");
main_file_to_watch.write( main_file_to_watch.write(
"export default { "export default {
fetch(_request: Request) { fetch(_request) {
return new Response(\"aaaaaaqqq!\"); return new Response(\"aaaaaaqqq!\");
}, },
};", };",
); );
let another_file = t.path().join("another_file.js");
another_file.write("");
let mut child = util::deno_cmd() let mut child = util::deno_cmd()
.current_dir(t.path()) .current_dir(t.path())
.arg("serve") .arg("serve")
.arg("--watch=another_file.js") .arg(format!("--watch={another_file}"))
.arg("-L") .arg("-L")
.arg("debug") .arg("debug")
.arg(&main_file_to_watch) .arg(&main_file_to_watch)
@ -596,7 +599,7 @@ async fn serve_watch_all() {
// Change content of the file // Change content of the file
main_file_to_watch.write( main_file_to_watch.write(
"export default { "export default {
fetch(_request: Request) { fetch(_request) {
return new Response(\"aaaaaaqqq123!\"); return new Response(\"aaaaaaqqq123!\");
}, },
};", };",
@ -604,18 +607,20 @@ async fn serve_watch_all() {
wait_contains("Restarting", &mut stderr_lines).await; wait_contains("Restarting", &mut stderr_lines).await;
wait_for_watcher("main_file_to_watch.js", &mut stderr_lines).await; wait_for_watcher("main_file_to_watch.js", &mut stderr_lines).await;
let another_file = t.path().join("another_file.js");
another_file.write("export const foo = 0;"); another_file.write("export const foo = 0;");
// Confirm that the added file is watched as well // Confirm that the added file is watched as well
wait_contains("Restarting", &mut stderr_lines).await; wait_contains("Restarting", &mut stderr_lines).await;
wait_for_watcher("main_file_to_watch.js", &mut stderr_lines).await;
main_file_to_watch main_file_to_watch
.write("import { foo } from './another_file.js'; console.log(foo);"); .write("import { foo } from './another_file.js'; console.log(foo);");
wait_contains("Restarting", &mut stderr_lines).await; wait_contains("Restarting", &mut stderr_lines).await;
wait_for_watcher("main_file_to_watch.js", &mut stderr_lines).await;
wait_contains("0", &mut stdout_lines).await; wait_contains("0", &mut stdout_lines).await;
another_file.write("export const foo = 42;"); another_file.write("export const foo = 42;");
wait_contains("Restarting", &mut stderr_lines).await; wait_contains("Restarting", &mut stderr_lines).await;
wait_for_watcher("main_file_to_watch.js", &mut stderr_lines).await;
wait_contains("42", &mut stdout_lines).await; wait_contains("42", &mut stdout_lines).await;
// Confirm that watch continues even with wrong syntax error // Confirm that watch continues even with wrong syntax error
@ -623,10 +628,11 @@ async fn serve_watch_all() {
wait_contains("Restarting", &mut stderr_lines).await; wait_contains("Restarting", &mut stderr_lines).await;
wait_contains("error:", &mut stderr_lines).await; wait_contains("error:", &mut stderr_lines).await;
wait_for_watcher("main_file_to_watch.js", &mut stderr_lines).await;
main_file_to_watch.write( main_file_to_watch.write(
"export default { "export default {
fetch(_request: Request) { fetch(_request) {
return new Response(\"aaaaaaqqq!\"); return new Response(\"aaaaaaqqq!\");
}, },
};", };",

View file

@ -1,5 +1,6 @@
const assert = require("assert"); const assert = require("assert");
const debug = require('util').debuglog('test'); const debug = require('util').debuglog('test');
const process = require("process");
function onmessage(m) { function onmessage(m) {
debug("CHILD got message:", m); debug("CHILD got message:", m);

View file

@ -0,0 +1,3 @@
export function doThing() {
return "thing";
}

View file

@ -0,0 +1,5 @@
{
"exports": {
".": "./mod.ts"
}
}

View file

@ -0,0 +1,3 @@
export function doThing() {
return "thing2";
}

View file

@ -0,0 +1,5 @@
{
"exports": {
".": "./mod.ts"
}
}

View file

@ -0,0 +1,6 @@
{
"versions": {
"1.0.0-beta.1": {},
"1.0.0-beta.2": {}
}
}

View file

@ -1,9 +1,22 @@
{ {
"tempDir": true, "tempDir": true,
"steps": [ "tests": {
{ "npm_package": {
"args": "add npm:@denotest/unstable", "steps": [
"output": "add.out" {
"args": "add npm:@denotest/unstable",
"output": "add.out"
}
]
},
"jsr_package": {
"steps": [
{
"args": "add jsr:@denotest/unstable",
"output": "add_jsr.out",
"exitCode": 1
}
]
} }
] }
} }

View file

@ -0,0 +1 @@
error: jsr:@denotest/unstable has only pre-release versions available. Try specifying a version: `deno add jsr:@denotest/unstable@^1.0.0-beta.2`

View file

@ -8,6 +8,30 @@
"well_formatted": { "well_formatted": {
"args": "fmt --check well_formatted.yml", "args": "fmt --check well_formatted.yml",
"output": "Checked 1 file\n" "output": "Checked 1 file\n"
},
"ignore_line": {
"args": "fmt --check ignore_line.yml",
"output": "Checked 1 file\n"
},
"ignore_file": {
"args": "fmt ignore_file.yaml",
"output": "Checked 1 file\n"
},
"ignore_file2": {
"args": "fmt ignore_file2.yaml",
"output": "Checked 1 file\n"
},
"ignore_file3": {
"args": "fmt ignore_file3.yaml",
"output": "Checked 1 file\n"
},
"ignore_file4": {
"args": "fmt ignore_file4.yaml",
"output": "Checked 1 file\n"
},
"wrong_file_ignore": {
"args": "fmt wrong_file_ignore.yaml",
"output": "wrong_file_ignore.out"
} }
} }
} }

View file

@ -0,0 +1,2 @@
# deno-fmt-ignore-file
{{something crazy

View file

@ -0,0 +1,2 @@
#deno-fmt-ignore-file
{{something crazy

View file

@ -0,0 +1,5 @@
# Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
# incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
# quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
# deno-fmt-ignore-file
{{something crazy

View file

@ -0,0 +1,2 @@
# deno-fmt-ignore-file Because this is templated yaml file
{{something crazy

View file

@ -0,0 +1,2 @@
# deno-fmt-ignore
- Test

View file

@ -0,0 +1,7 @@
Error formatting: [WILDCARD]wrong_file_ignore.yaml
parse error at line 5, column 1
|
5 | {{something crazy
| ^
Checked 1 file

View file

@ -0,0 +1,5 @@
# File ignore directive only works if it's in the first cluster
# of comment, ie. there are no empty lines after the first n-leading lines.
# deno-fmt-ignore-file
{{something crazy

View file

@ -0,0 +1,5 @@
{
"args": "run -L debug -A main.ts",
"output": "main.out",
"tempDir": true
}

View file

@ -0,0 +1,8 @@
{
"workspace": [
"./packages/*"
],
"imports": {
"chalk": "npm:chalk"
}
}

View file

@ -0,0 +1,22 @@
[WILDCARD]Workspace config generated this import map {
"imports": {
"chalk": "npm:chalk",
"chalk/": "npm:/chalk/"
},
"scopes": {
"./packages/bar/": {
"@/": "./packages/bar/",
"secret_mod/": "./packages/bar/some_mod/"
},
"./packages/foo/": {
"~/": "./packages/foo/",
"foo/": "./packages/foo/bar/"
}
}
}
[WILDCARD]
hello from foo
buzz from foo
hello from bar
buzz from bar
[Function: chalk][WILDCARD]

View file

@ -0,0 +1,5 @@
import chalk from "chalk";
import "./packages/foo/mod.ts";
import "./packages/bar/mod.ts";
console.log(chalk);

View file

@ -0,0 +1,8 @@
{
"name": "asdfasdfasdf",
"version": "0.0.0",
"imports": {
"@/": "./",
"secret_mod/": "./some_mod/"
}
}

View file

@ -0,0 +1 @@
export const buzz = "buzz from bar";

View file

@ -0,0 +1,5 @@
import { hello } from "secret_mod/hello.ts";
import { buzz } from "@/fizz/buzz.ts";
console.log(hello);
console.log(buzz);

View file

@ -0,0 +1 @@
export const hello = "hello from bar";

View file

@ -0,0 +1 @@
export const hello = "hello from foo";

View file

@ -0,0 +1,8 @@
{
"name": "qwerqwer",
"version": "0.0.0",
"imports": {
"~/": "./",
"foo/": "./bar/"
}
}

View file

@ -0,0 +1 @@
export const buzz = "buzz from foo";

View file

@ -0,0 +1,5 @@
import { hello } from "foo/hello.ts";
import { buzz } from "~/fizz/buzz.ts";
console.log(hello);
console.log(buzz);

View file

@ -1,4 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// deno-lint-ignore-file no-node-globals
import { import {
assert, assert,

View file

@ -56,12 +56,13 @@ async function dlint() {
":!:cli/tsc/compiler.d.ts", ":!:cli/tsc/compiler.d.ts",
":!:runtime/examples/", ":!:runtime/examples/",
":!:target/", ":!:target/",
":!:tests/ffi/tests/test.js",
":!:tests/registry/**", ":!:tests/registry/**",
":!:tests/specs/**", ":!:tests/specs/**",
":!:tests/testdata/**", ":!:tests/testdata/**",
":!:tests/unit_node/testdata/**", ":!:tests/unit_node/testdata/**",
":!:tests/wpt/suite/**",
":!:tests/wpt/runner/**", ":!:tests/wpt/runner/**",
":!:tests/wpt/suite/**",
]); ]);
if (!sourceFiles.length) { if (!sourceFiles.length) {

View file

@ -11,7 +11,7 @@ export { delay } from "@std/async/delay";
// [toolName] --version output // [toolName] --version output
const versions = { const versions = {
"dlint": "dlint 0.60.0", "dlint": "dlint 0.68.0",
}; };
const compressed = new Set(["ld64.lld", "rcodesign"]); const compressed = new Set(["ld64.lld", "rcodesign"]);
@ -178,7 +178,7 @@ export function getPrebuiltToolPath(toolName) {
return join(PREBUILT_TOOL_DIR, toolName + executableSuffix); return join(PREBUILT_TOOL_DIR, toolName + executableSuffix);
} }
const commitId = "b8aac22e0cd7c1c6557a56a813fe0c25486fafee"; const commitId = "7a3a6fee951b3381c59aa4c907274957f324ce8c";
const downloadUrl = const downloadUrl =
`https://raw.githubusercontent.com/denoland/deno_third_party/${commitId}/prebuilt/${platformDirName}`; `https://raw.githubusercontent.com/denoland/deno_third_party/${commitId}/prebuilt/${platformDirName}`;