Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(runtime): Improve Error Handling and-Dot Handling in-fqdn! Macro #23590

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
91b438e
Implement improvements for error handling and dot handling in fqdn! m…
yazan-nidal Apr 28, 2024
01b8f01
add tests for modified fqdn
yazan-nidal Apr 29, 2024
cc8a798
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal Apr 29, 2024
3aa5ca0
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal Apr 29, 2024
ea3cc59
Implement improvements(v2) for error handling and dot handling in fqd…
yazan-nidal May 6, 2024
2fbaf97
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 6, 2024
f8bfa41
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 7, 2024
589d407
add failed parse domain tests
yazan-nidal May 7, 2024
9e373ce
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 7, 2024
1bbf516
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 8, 2024
114cc7a
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
bartlomieju May 9, 2024
694aa25
fmt
bartlomieju May 9, 2024
92a9509
Fix lint issues
yazan-nidal May 9, 2024
d7a541d
fmt
yazan-nidal May 9, 2024
c74d45f
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 12, 2024
1bbc4f6
Merge branch 'denoland:main' into fix-(runtime)-Improve-Error-Handlin…
yazan-nidal May 13, 2024
166d117
fix: improve parsing of IPv6, IPv4, hostnames, and URLs; make port op…
yazan-nidal May 23, 2024
6f8664b
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 23, 2024
40fe3bb
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
dsherret May 23, 2024
816b410
Merge branch 'fix-(runtime)-Improve-Error-Handling-and-Dot-Handling-i…
yazan-nidal May 27, 2024
dd15f60
enhancing
yazan-nidal May 27, 2024
2179fe8
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 27, 2024
49c4053
update Cargo.lock
bartlomieju May 27, 2024
e7a41b0
fmt
bartlomieju May 27, 2024
b4b84ab
fmt#
yazan-nidal May 28, 2024
5c63b47
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 28, 2024
d704574
fmt#
yazan-nidal May 28, 2024
3008de6
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 28, 2024
233111f
Merge branch 'fix-(runtime)-Improve-Error-Handling-and-Dot-Handling-i…
yazan-nidal May 28, 2024
8b8e240
fmt
yazan-nidal May 29, 2024
58efbb5
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
yazan-nidal May 29, 2024
932efa7
fmt#
yazan-nidal May 29, 2024
68c6104
Merge branch 'fix-(runtime)-Improve-Error-Handling-and-Dot-Handling-i…
yazan-nidal May 29, 2024
280035e
Merge branch 'main' into fix-(runtime)-Improve-Error-Handling-and-Dot…
dsherret May 30, 2024
05c6689
lint
yazan-nidal May 30, 2024
390b79c
Merge remote-tracking branch 'origin/fix-(runtime)-Improve-Error-Hand…
yazan-nidal May 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 39 additions & 0 deletions cli/args/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9738,4 +9738,43 @@ mod tests {
}
);
}

#[test]
fn wildcard_flags() {
#[rustfmt::skip]
let r = flags_from_vec(svec![
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let r = flags_from_vec(svec![
let r = flags_from_vec(svec![

"deno",
"run",
"--allow-read",
"--allow-write=notion-next",
"--allow-net=api.notion.com,*.amazonaws.com",
"--allow-env",
"script.ts"
]);

let flags = r.unwrap();
assert_eq!(
flags,
Flags {
subcommand: DenoSubcommand::Run(RunFlags::new_default(
"script.ts".to_string()
)),
permissions: PermissionFlags {
allow_env: Some(vec![],),
allow_net: Some(vec![
"api.notion.com".to_string(),
"*.amazonaws.com".to_string(),
],),
allow_read: Some(vec![],),
allow_write: Some(vec!["notion-next".to_string(),],),
..Default::default()
},
unstable_config: UnstableConfig {
..Default::default()
},
code_cache_enabled: true,
..Flags::default()
}
);
}
}
164 changes: 142 additions & 22 deletions runtime/permissions/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::error::custom_error;
use deno_core::error::type_error;
Expand All @@ -16,7 +17,6 @@ use deno_core::url;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_terminal::colors;
use fqdn::fqdn;
use fqdn::FQDN;
use once_cell::sync::Lazy;
use std::borrow::Cow;
Expand Down Expand Up @@ -692,8 +692,10 @@ impl Descriptor for WriteDescriptor {
pub struct NetDescriptor(pub FQDN, pub Option<u16>);

impl NetDescriptor {
fn new<T: AsRef<str>>(host: &&(T, Option<u16>)) -> Self {
NetDescriptor(fqdn!(host.0.as_ref()), host.1)
fn new<T: AsRef<str>>(host: &&(T, Option<u16>)) -> Result<Self, AnyError> {
let fqdn = FQDN::from_str(host.0.as_ref())
.with_context(|| format!("Failed to parse {}", host.0.as_ref()))?;
Ok(NetDescriptor(fqdn, host.1))
}
}

Expand Down Expand Up @@ -733,13 +735,18 @@ impl FromStr for NetDescriptor {
// Set the scheme to `unknown` to parse the URL, as we really don't know
// what the scheme is. We only using Url::parse to parse the host and port
// and don't care about the scheme.
let url = url::Url::parse(&format!("unknown://{s}"))?;
let url = url::Url::parse(&format!("unknown://{s}"))
.with_context(|| format!("Failed to parse {}", s))?;

let hostname = url
.host_str()
.ok_or(url::ParseError::EmptyHost)?
.to_string();

Ok(NetDescriptor(fqdn!(&hostname), url.port()))
let fqdn = FQDN::from_str(&hostname)
.with_context(|| format!("Failed to parse {}", hostname))?;

Ok(NetDescriptor(fqdn, url.port()))
}
}

Expand Down Expand Up @@ -1101,30 +1108,65 @@ impl UnaryPermission<WriteDescriptor> {
self.check_desc(None, false, api_name, || None)
}
}

impl UnaryPermission<NetDescriptor> {
pub fn query<T: AsRef<str>>(
&self,
host: Option<&(T, Option<u16>)>,
) -> PermissionState {
self.query_desc(
host.map(|h| NetDescriptor::new(&h)).as_ref(),
AllowPartial::TreatAsPartialGranted,
)
let net_desc_result = match host {
Some(&(ref host_str, port_option)) => {
NetDescriptor::new(&&(host_str.as_ref(), port_option))
}
None => Err(anyhow!("Host information is missing")),
};
match net_desc_result {
Ok(net_desc) => {
self.query_desc(Some(&net_desc), AllowPartial::TreatAsPartialGranted)
}

Err(err) => {
log::error!("Error creating NetDescriptor: {}", err);
yazan-nidal marked this conversation as resolved.
Show resolved Hide resolved
PermissionState::Prompt
}
}
}

pub fn request<T: AsRef<str>>(
&mut self,
host: Option<&(T, Option<u16>)>,
) -> PermissionState {
self.request_desc(host.map(|h| NetDescriptor::new(&h)).as_ref(), || None)
let net_desc_result = match host {
Some(&(ref host_str, port_option)) => {
NetDescriptor::new(&&(host_str.as_ref(), port_option))
}
None => Err(anyhow!("Host information is missing")),
};
match net_desc_result {
Ok(net_desc) => self.request_desc(Some(&net_desc), || None),
Err(err) => {
log::error!("Error creating NetDescriptor: {}", err);
PermissionState::Prompt
}
}
}

pub fn revoke<T: AsRef<str>>(
&mut self,
host: Option<&(T, Option<u16>)>,
) -> PermissionState {
self.revoke_desc(host.map(|h| NetDescriptor::new(&h)).as_ref())
let net_desc_result = match host {
Some(&(ref host_str, port_option)) => {
NetDescriptor::new(&&(host_str.as_ref(), port_option))
}
None => Err(anyhow!("Host information is missing")),
};
match net_desc_result {
Ok(net_desc) => self.revoke_desc(Some(&net_desc)),
Err(err) => {
log::error!("Error creating NetDescriptor: {}", err);
PermissionState::Prompt
}
}
}

pub fn check<T: AsRef<str>>(
Expand All @@ -1133,7 +1175,16 @@ impl UnaryPermission<NetDescriptor> {
api_name: Option<&str>,
) -> Result<(), AnyError> {
skip_check_if_is_permission_fully_granted!(self);
self.check_desc(Some(&NetDescriptor::new(&host)), false, api_name, || None)
let net_desc_result = NetDescriptor::new(&&(host.0.as_ref(), host.1));
match net_desc_result {
Ok(net_desc) => {
self.check_desc(Some(&net_desc), false, api_name, || None)
}
Err(err) => {
log::error!("Error creating NetDescriptor: {}", err);
Err(err)
}
}
}

pub fn check_url(
Expand All @@ -1142,18 +1193,31 @@ impl UnaryPermission<NetDescriptor> {
api_name: Option<&str>,
) -> Result<(), AnyError> {
skip_check_if_is_permission_fully_granted!(self);

let hostname = url
.host_str()
.ok_or_else(|| uri_error("Missing host"))?
.ok_or_else(|| anyhow!("Missing host"))?
.to_string();
let host = &(&hostname, url.port_or_known_default());
let display_host = match url.port() {
None => hostname.clone(),
Some(port) => format!("{hostname}:{port}"),
};
self.check_desc(Some(&NetDescriptor::new(&host)), false, api_name, || {
Some(format!("\"{}\"", display_host))
})
let port = url.port_or_known_default();
let host = &&(hostname.clone(), port);

let net_desc_result = NetDescriptor::new(host);

match net_desc_result {
Ok(net_desc) => {
let display_host = match url.port() {
None => hostname.clone(),
Some(port) => format!("{}:{}", hostname, port),
};
self.check_desc(Some(&net_desc), false, api_name, || {
Some(format!("\"{}\"", display_host))
})
}
Err(err) => {
log::error!("Error creating NetDescriptor: {}", err);
Err(err)
}
}
}

pub fn check_all(&mut self) -> Result<(), AnyError> {
Expand Down Expand Up @@ -3290,4 +3354,60 @@ mod tests {
)
.is_err());
}

#[test]
fn test_net_descriptor_valid() {
let host: (String, Option<u16>) = ("foo.bar.com.".to_string(), Some(1));
let result = NetDescriptor::new(&&host);
assert!(result.is_ok());
let net_descriptor = result.unwrap();
assert_eq!(net_descriptor.0.to_string(), "foo.bar.com");
assert_eq!(net_descriptor.1, Some(1));
}

#[test]
fn test_net_descriptor_invalid_with_special_characters() {
let host: (String, Option<u16>) = ("foo@bar.com.".to_string(), Some(1));
let result = NetDescriptor::new(&&host);
assert!(result.is_err());
let expected_error_message = "Failed to parse foo@bar.com.";
assert_eq!(result.unwrap_err().to_string(), expected_error_message);
}

#[test]
fn test_net_descriptor_from_str_valid() {
let url_string = "example.com:8080";
let result = NetDescriptor::from_str(url_string);
assert!(result.is_ok());
let net_descriptor = result.unwrap();
assert_eq!(net_descriptor.0.to_string(), "example.com");
assert_eq!(net_descriptor.1, Some(8080));
}

#[test]
fn test_permission_query_invalid_hostname() {
let permission = UnaryPermission::<NetDescriptor>::default();
let invalid_host: (String, Option<u16>) =
("foo@bar.com.".to_string(), Some(443));
let state = permission.query(Some(&invalid_host));
assert_eq!(state, PermissionState::Prompt);
}

#[test]
fn test_request_invalid_domain() {
let mut permission = UnaryPermission::<NetDescriptor>::default();
let invalid_host: (String, Option<u16>) =
("foo@bar.com.".to_string(), Some(443));
let result = permission.request(Some(&invalid_host));
assert_eq!(result, PermissionState::Prompt);
}

#[test]
fn test_revoke_invalid_domain() {
let mut permission = UnaryPermission::<NetDescriptor>::default();
let invalid_host: (String, Option<u16>) =
("foo@bar.com.".to_string(), Some(443));
let result = permission.revoke(Some(&invalid_host));
assert_eq!(result, PermissionState::Prompt);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"tempDir": true,
"steps": [
{
"args": " run --allow-read --allow-env --allow-write=notion-next --allow-net=api.notion.com,www.google.com,*.amazon.com main.js",
"output": "err_i.out",
"exitCode": 1
},
{
"args": " run --allow-net main.js",
"output": "err_ii.out",
"exitCode": 1
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
error: Failed to parse *.amazon.com

Caused by:
invalid char found in FQDN
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: Uncaught (in promise) Error: No such host is known. (os error 11001)
at async Object.connect (ext:deno_net/01_net.js:587:55)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Deno.connect({ hostname: "api.notion.com.", port: 443 });
Deno.connect({ hostname: "*.amazon.com.", port: 443 });