diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/flags.rs | 22 | ||||
-rw-r--r-- | src/isolate.rs | 5 | ||||
-rw-r--r-- | src/main.rs | 1 | ||||
-rw-r--r-- | src/ops.rs | 60 | ||||
-rw-r--r-- | src/permissions.rs | 17 |
5 files changed, 93 insertions, 12 deletions
diff --git a/src/flags.rs b/src/flags.rs index d68bb5e09..a680c8aa1 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -23,6 +23,7 @@ pub struct DenoFlags { pub version: bool, pub reload: bool, pub recompile: bool, + pub allow_read: bool, pub allow_write: bool, pub allow_net: bool, pub allow_env: bool, @@ -89,6 +90,9 @@ fn set_recognized_flags( if matches.opt_present("recompile") { flags.recompile = true; } + if matches.opt_present("allow-read") { + flags.allow_read = true; + } if matches.opt_present("allow-write") { flags.allow_write = true; } @@ -102,9 +106,11 @@ fn set_recognized_flags( flags.allow_run = true; } if matches.opt_present("allow-all") { + flags.allow_read = true; flags.allow_env = true; flags.allow_net = true; flags.allow_run = true; + flags.allow_read = true; flags.allow_write = true; } if matches.opt_present("types") { @@ -142,6 +148,7 @@ pub fn set_flags( // TODO(kevinkassimo): v8_set_flags intercepts '-help' with single '-' // Resolve that and then uncomment line below (enabling Go style -long-flag) // opts.long_only(true); + opts.optflag("", "allow-read", "Allow file system read access."); opts.optflag("", "allow-write", "Allow file system write access."); opts.optflag("", "allow-net", "Allow network access."); opts.optflag("", "allow-env", "Allow environment access."); @@ -262,12 +269,27 @@ fn test_set_flags_7() { allow_net: true, allow_env: true, allow_run: true, + allow_read: true, allow_write: true, ..DenoFlags::default() } ) } +#[test] +fn test_set_flags_8() { + let (flags, rest, _) = + set_flags(svec!["deno", "gist.ts", "--allow-read"]).unwrap(); + assert_eq!(rest, svec!["deno", "gist.ts"]); + assert_eq!( + flags, + DenoFlags { + allow_read: true, + ..DenoFlags::default() + } + ) +} + // Returns args passed to V8, followed by args passed to JS fn v8_set_flags_preprocess(args: Vec<String>) -> (Vec<String>, Vec<String>) { let (rest, mut v8_args) = diff --git a/src/isolate.rs b/src/isolate.rs index 3c9cec797..fbe65a54e 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -114,6 +114,11 @@ impl IsolateState { } #[inline] + pub fn check_read(&self, filename: &str) -> DenoResult<()> { + self.permissions.check_read(filename) + } + + #[inline] pub fn check_write(&self, filename: &str) -> DenoResult<()> { self.permissions.check_write(filename) } diff --git a/src/main.rs b/src/main.rs index 3daea0d31..25e68e344 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,6 +86,7 @@ fn main() { if flags.fmt { rest_argv.insert(1, "https://deno.land/x/std/prettier/main.ts".to_string()); + flags.allow_read = true; flags.allow_write = true; } diff --git a/src/ops.rs b/src/ops.rs index 82d79fc2f..86bc6efad 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -685,10 +685,24 @@ fn op_open( } } - if mode != "r" { - // Write permission is needed except "r" mode - if let Err(e) = state.check_write(&filename_str) { - return odd_future(e); + match mode { + "r" => { + if let Err(e) = state.check_read(&filename_str) { + return odd_future(e); + } + } + "w" | "a" | "x" => { + if let Err(e) = state.check_write(&filename_str) { + return odd_future(e); + } + } + &_ => { + if let Err(e) = state.check_read(&filename_str) { + return odd_future(e); + } + if let Err(e) = state.check_write(&filename_str) { + return odd_future(e); + } } } @@ -862,15 +876,19 @@ fn op_remove( // Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184 fn op_read_file( - _state: &Arc<IsolateState>, + state: &Arc<IsolateState>, base: &msg::Base<'_>, data: libdeno::deno_buf, ) -> Box<Op> { assert_eq!(data.len(), 0); let inner = base.inner_as_read_file().unwrap(); let cmd_id = base.cmd_id(); - let filename = PathBuf::from(inner.filename().unwrap()); + let filename_ = inner.filename().unwrap(); + let filename = PathBuf::from(filename_); debug!("op_read_file {}", filename.display()); + if let Err(e) = state.check_read(&filename_) { + return odd_future(e); + } blocking(base.sync(), move || { let vec = fs::read(&filename)?; // Build the response message. memcpy data into inner. @@ -902,10 +920,14 @@ fn op_copy_file( ) -> Box<Op> { assert_eq!(data.len(), 0); let inner = base.inner_as_copy_file().unwrap(); - let from = PathBuf::from(inner.from().unwrap()); + let from_ = inner.from().unwrap(); + let from = PathBuf::from(from_); let to_ = inner.to().unwrap(); let to = PathBuf::from(to_); + if let Err(e) = state.check_read(&from_) { + return odd_future(e); + } if let Err(e) = state.check_write(&to_) { return odd_future(e); } @@ -974,16 +996,21 @@ fn op_cwd( } fn op_stat( - _state: &Arc<IsolateState>, + state: &Arc<IsolateState>, base: &msg::Base<'_>, data: libdeno::deno_buf, ) -> Box<Op> { assert_eq!(data.len(), 0); let inner = base.inner_as_stat().unwrap(); let cmd_id = base.cmd_id(); - let filename = PathBuf::from(inner.filename().unwrap()); + let filename_ = inner.filename().unwrap(); + let filename = PathBuf::from(filename_); let lstat = inner.lstat(); + if let Err(e) = state.check_read(&filename_) { + return odd_future(e); + } + blocking(base.sync(), move || { let builder = &mut FlatBufferBuilder::new(); debug!("op_stat {} {}", filename.display(), lstat); @@ -1021,7 +1048,7 @@ fn op_stat( } fn op_read_dir( - _state: &Arc<IsolateState>, + state: &Arc<IsolateState>, base: &msg::Base<'_>, data: libdeno::deno_buf, ) -> Box<Op> { @@ -1030,6 +1057,10 @@ fn op_read_dir( let cmd_id = base.cmd_id(); let path = String::from(inner.path().unwrap()); + if let Err(e) = state.check_read(&path) { + return odd_future(e); + } + blocking(base.sync(), move || -> OpResult { debug!("op_read_dir {}", path); let builder = &mut FlatBufferBuilder::new(); @@ -1157,14 +1188,19 @@ fn op_symlink( } fn op_read_link( - _state: &Arc<IsolateState>, + state: &Arc<IsolateState>, base: &msg::Base<'_>, data: libdeno::deno_buf, ) -> Box<Op> { assert_eq!(data.len(), 0); let inner = base.inner_as_readlink().unwrap(); let cmd_id = base.cmd_id(); - let name = PathBuf::from(inner.name().unwrap()); + let name_ = inner.name().unwrap(); + let name = PathBuf::from(name_); + + if let Err(e) = state.check_read(&name_) { + return odd_future(e); + } blocking(base.sync(), move || -> OpResult { debug!("op_read_link {}", name.display()); diff --git a/src/permissions.rs b/src/permissions.rs index c05ea4ee5..8546e4ee9 100644 --- a/src/permissions.rs +++ b/src/permissions.rs @@ -12,6 +12,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; #[cfg_attr(feature = "cargo-clippy", allow(stutter))] #[derive(Debug, Default)] pub struct DenoPermissions { + pub allow_read: AtomicBool, pub allow_write: AtomicBool, pub allow_net: AtomicBool, pub allow_env: AtomicBool, @@ -21,6 +22,7 @@ pub struct DenoPermissions { impl DenoPermissions { pub fn new(flags: &DenoFlags) -> Self { Self { + allow_read: AtomicBool::new(flags.allow_read), allow_write: AtomicBool::new(flags.allow_write), allow_env: AtomicBool::new(flags.allow_env), allow_net: AtomicBool::new(flags.allow_net), @@ -40,6 +42,21 @@ impl DenoPermissions { r } + pub fn check_read(&self, filename: &str) -> DenoResult<()> { + if self.allow_read.load(Ordering::SeqCst) { + return Ok(()); + }; + // TODO get location (where access occurred) + let r = permission_prompt(&format!( + "Deno requests read access to \"{}\".", + filename + ));; + if r.is_ok() { + self.allow_read.store(true, Ordering::SeqCst); + } + r + } + pub fn check_write(&self, filename: &str) -> DenoResult<()> { if self.allow_write.load(Ordering::SeqCst) { return Ok(()); |