summaryrefslogtreecommitdiff
path: root/cli/permissions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/permissions.rs')
-rw-r--r--cli/permissions.rs110
1 files changed, 82 insertions, 28 deletions
diff --git a/cli/permissions.rs b/cli/permissions.rs
index 833dc28df..298259f6b 100644
--- a/cli/permissions.rs
+++ b/cli/permissions.rs
@@ -1,10 +1,12 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::colors;
use crate::flags::Flags;
+use crate::fs::resolve_from_cwd;
use crate::op_error::OpError;
use serde::de;
use serde::Deserialize;
use std::collections::HashSet;
+use std::env::current_dir;
use std::fmt;
#[cfg(not(test))]
use std::io;
@@ -149,20 +151,20 @@ pub struct Permissions {
pub allow_hrtime: PermissionState,
}
+fn resolve_fs_whitelist(whitelist: &[PathBuf]) -> HashSet<PathBuf> {
+ whitelist
+ .iter()
+ .map(|raw_path| resolve_from_cwd(Path::new(&raw_path)).unwrap())
+ .collect()
+}
+
impl Permissions {
pub fn from_flags(flags: &Flags) -> Self {
- // assert each whitelist path is absolute, since the cwd may change.
- for path in &flags.read_whitelist {
- assert!(path.has_root());
- }
- for path in &flags.write_whitelist {
- assert!(path.has_root());
- }
Self {
allow_read: PermissionState::from(flags.allow_read),
- read_whitelist: flags.read_whitelist.iter().cloned().collect(),
+ read_whitelist: resolve_fs_whitelist(&flags.read_whitelist),
allow_write: PermissionState::from(flags.allow_write),
- write_whitelist: flags.write_whitelist.iter().cloned().collect(),
+ write_whitelist: resolve_fs_whitelist(&flags.write_whitelist),
allow_net: PermissionState::from(flags.allow_net),
net_whitelist: flags.net_whitelist.iter().cloned().collect(),
allow_env: PermissionState::from(flags.allow_env),
@@ -172,6 +174,24 @@ impl Permissions {
}
}
+ /// Arbitrary helper. Resolves the path from CWD, and also gets a path that
+ /// can be displayed without leaking the CWD when not allowed.
+ fn resolved_and_display_path(&self, path: &Path) -> (PathBuf, PathBuf) {
+ let resolved_path = resolve_from_cwd(path).unwrap();
+ let display_path = if path.is_absolute() {
+ path.to_path_buf()
+ } else {
+ match self
+ .get_state_read(&Some(&current_dir().unwrap()))
+ .check("", "")
+ {
+ Ok(_) => resolved_path.clone(),
+ Err(_) => path.to_path_buf(),
+ }
+ };
+ (resolved_path, display_path)
+ }
+
pub fn allow_all() -> Self {
Self {
allow_read: PermissionState::from(true),
@@ -199,12 +219,26 @@ impl Permissions {
}
pub fn check_read(&self, path: &Path) -> Result<(), OpError> {
- self.get_state_read(&Some(path)).check(
- &format!("read access to \"{}\"", path.display()),
+ let (resolved_path, display_path) = self.resolved_and_display_path(path);
+ self.get_state_read(&Some(&resolved_path)).check(
+ &format!("read access to \"{}\"", display_path.display()),
"--allow-read",
)
}
+ /// As `check_read()`, but permission error messages will anonymize the path
+ /// by replacing it with the given `display`.
+ pub fn check_read_blind(
+ &self,
+ path: &Path,
+ display: &str,
+ ) -> Result<(), OpError> {
+ let resolved_path = resolve_from_cwd(path).unwrap();
+ self
+ .get_state_read(&Some(&resolved_path))
+ .check(&format!("read access to <{}>", display), "--allow-read")
+ }
+
fn get_state_write(&self, path: &Option<&Path>) -> PermissionState {
if path.map_or(false, |f| check_path_white_list(f, &self.write_whitelist)) {
return PermissionState::Allow;
@@ -213,8 +247,9 @@ impl Permissions {
}
pub fn check_write(&self, path: &Path) -> Result<(), OpError> {
- self.get_state_write(&Some(path)).check(
- &format!("write access to \"{}\"", path.display()),
+ let (resolved_path, display_path) = self.resolved_and_display_path(path);
+ self.get_state_write(&Some(&resolved_path)).check(
+ &format!("write access to \"{}\"", display_path.display()),
"--allow-write",
)
}
@@ -264,8 +299,9 @@ impl Permissions {
}
pub fn check_plugin(&self, path: &Path) -> Result<(), OpError> {
+ let (_, display_path) = self.resolved_and_display_path(path);
self.allow_plugin.check(
- &format!("access to open a plugin: {}", path.display()),
+ &format!("access to open a plugin: {}", display_path.display()),
"--allow-plugin",
)
}
@@ -277,26 +313,34 @@ impl Permissions {
}
pub fn request_read(&mut self, path: &Option<&Path>) -> PermissionState {
- if path.map_or(false, |f| check_path_white_list(f, &self.read_whitelist)) {
- return PermissionState::Allow;
+ let paths = path.map(|p| self.resolved_and_display_path(p));
+ if let Some((p, _)) = paths.as_ref() {
+ if check_path_white_list(&p, &self.read_whitelist) {
+ return PermissionState::Allow;
+ }
};
- self.allow_read.request(&match path {
+ self.allow_read.request(&match paths {
None => "Deno requests read access".to_string(),
- Some(path) => {
- format!("Deno requests read access to \"{}\"", path.display())
- }
+ Some((_, display_path)) => format!(
+ "Deno requests read access to \"{}\"",
+ display_path.display()
+ ),
})
}
pub fn request_write(&mut self, path: &Option<&Path>) -> PermissionState {
- if path.map_or(false, |f| check_path_white_list(f, &self.write_whitelist)) {
- return PermissionState::Allow;
+ let paths = path.map(|p| self.resolved_and_display_path(p));
+ if let Some((p, _)) = paths.as_ref() {
+ if check_path_white_list(&p, &self.write_whitelist) {
+ return PermissionState::Allow;
+ }
};
- self.allow_write.request(&match path {
+ self.allow_write.request(&match paths {
None => "Deno requests write access".to_string(),
- Some(path) => {
- format!("Deno requests write access to \"{}\"", path.display())
- }
+ Some((_, display_path)) => format!(
+ "Deno requests write access to \"{}\"",
+ display_path.display()
+ ),
})
}
@@ -335,10 +379,12 @@ impl Permissions {
url: &Option<&str>,
path: &Option<&Path>,
) -> Result<PermissionState, OpError> {
+ let path = path.map(|p| resolve_from_cwd(p).unwrap());
+ let path = path.as_deref();
match name {
"run" => Ok(self.allow_run),
- "read" => Ok(self.get_state_read(path)),
- "write" => Ok(self.get_state_write(path)),
+ "read" => Ok(self.get_state_read(&path)),
+ "write" => Ok(self.get_state_write(&path)),
"net" => self.get_state_net_url(url),
"env" => Ok(self.allow_env),
"plugin" => Ok(self.allow_plugin),
@@ -486,6 +532,14 @@ mod tests {
assert!(perms.check_read(Path::new("/b/c/sub/path")).is_ok());
assert!(perms.check_write(Path::new("/b/c/sub/path")).is_ok());
+ // Sub path within /b/c, needs normalizing
+ assert!(perms
+ .check_read(Path::new("/b/c/sub/path/../path/."))
+ .is_ok());
+ assert!(perms
+ .check_write(Path::new("/b/c/sub/path/../path/."))
+ .is_ok());
+
// Inside of /b but outside of /b/c
assert!(perms.check_read(Path::new("/b/e")).is_err());
assert!(perms.check_write(Path::new("/b/e")).is_err());