Skip to content

Commit

Permalink
Add fs read permission
Browse files Browse the repository at this point in the history
  • Loading branch information
dsseng committed Feb 5, 2019
1 parent cb95797 commit c7cf8b6
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 22 deletions.
17 changes: 10 additions & 7 deletions js/test_util.ts
Expand Up @@ -18,31 +18,34 @@ export {
testing.setFilter(deno.args[1]);

interface DenoPermissions {
read?: boolean;
write?: boolean;
net?: boolean;
env?: boolean;
run?: boolean;
}

function permToString(perms: DenoPermissions): string {
const r = perms.read ? 1 : 0;
const w = perms.write ? 1 : 0;
const n = perms.net ? 1 : 0;
const e = perms.env ? 1 : 0;
const r = perms.run ? 1 : 0;
return `permW${w}N${n}E${e}R${r}`;
const u = perms.run ? 1 : 0;
return `permR${r}W${w}N${n}E${e}U${u}`;
}

function permFromString(s: string): DenoPermissions {
const re = /^permW([01])N([01])E([01])R([01])$/;
const re = /^permR([01])W([01])N([01])E([01])U([01])$/;
const found = s.match(re);
if (!found) {
throw Error("Not a permission string");
}
return {
write: Boolean(Number(found[1])),
net: Boolean(Number(found[2])),
env: Boolean(Number(found[3])),
run: Boolean(Number(found[4]))
read: Boolean(Number(found[1])),
write: Boolean(Number(found[2])),
net: Boolean(Number(found[3])),
env: Boolean(Number(found[4])),
run: Boolean(Number(found[5]))
};
}

Expand Down
7 changes: 7 additions & 0 deletions src/flags.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
Expand All @@ -105,6 +109,7 @@ fn set_recognized_flags(
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") {
Expand Down Expand Up @@ -142,6 +147,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.");
Expand Down Expand Up @@ -262,6 +268,7 @@ fn test_set_flags_7() {
allow_net: true,
allow_env: true,
allow_run: true,
allow_read: true,
allow_write: true,
..DenoFlags::default()
}
Expand Down
5 changes: 5 additions & 0 deletions src/isolate.rs
Expand Up @@ -112,6 +112,11 @@ impl IsolateState {
Arc::new(IsolateState::new(flags, rest_argv, None))
}

#[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)
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Expand Up @@ -82,6 +82,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;
}

Expand Down
42 changes: 34 additions & 8 deletions src/ops.rs
Expand Up @@ -680,6 +680,10 @@ fn op_open(
}
}

if let Err(e) = state.check_read(&filename_str) {
return odd_future(e);
}

if mode != "r" {
// Write permission is needed except "r" mode
if let Err(e) = state.check_write(&filename_str) {
Expand Down Expand Up @@ -857,15 +861,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.
Expand Down Expand Up @@ -897,10 +905,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);
}
Expand Down Expand Up @@ -969,16 +981,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);
Expand Down Expand Up @@ -1016,7 +1033,7 @@ fn op_stat(
}

fn op_read_dir(
_state: &Arc<IsolateState>,
state: &Arc<IsolateState>,
base: &msg::Base<'_>,
data: libdeno::deno_buf,
) -> Box<Op> {
Expand All @@ -1025,6 +1042,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();
Expand Down Expand Up @@ -1152,14 +1173,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());
Expand Down
17 changes: 17 additions & 0 deletions src/permissions.rs
Expand Up @@ -11,6 +11,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,
Expand All @@ -20,6 +21,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),
Expand All @@ -39,6 +41,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(());
Expand Down
2 changes: 1 addition & 1 deletion tests/016_double_await.test
@@ -1,2 +1,2 @@
args: tests/016_double_await.ts --reload
args: tests/016_double_await.ts --allow-read --reload
output: tests/016_double_await.ts.out
12 changes: 6 additions & 6 deletions tools/unit_tests.py
Expand Up @@ -43,12 +43,12 @@ def run_unit_test(deno_exe, permStr, flags=None):
# tests by the special string. permW0N0 means allow-write but not allow-net.
# See js/test_util.ts for more details.
def unit_tests(deno_exe):
run_unit_test(deno_exe, "permW0N0E0R0")
run_unit_test(deno_exe, "permW1N0E0R0", ["--allow-write"])
run_unit_test(deno_exe, "permW0N1E0R0", ["--allow-net"])
run_unit_test(deno_exe, "permW0N0E1R0", ["--allow-env"])
run_unit_test(deno_exe, "permW0N0E0R1", ["--allow-run"])
run_unit_test(deno_exe, "permW1N0E0R1", ["--allow-run", "--allow-write"])
run_unit_test(deno_exe, "permR1W0N0E0U0", ["--allow-read"])
run_unit_test(deno_exe, "permR1W1N0E0U0", ["--allow-read", "--allow-write"])
run_unit_test(deno_exe, "permR1W0N1E0U0", ["--allow-read", "--allow-net"])
run_unit_test(deno_exe, "permR0W0N0E1U0", ["--allow-env"])
run_unit_test(deno_exe, "permR0W0N0E0U1", ["--allow-run"])
run_unit_test(deno_exe, "permR0W1N0E0U1", ["--allow-run", "--allow-write"])
# TODO We might accidentally miss some. We should be smarter about which we
# run. Maybe we can use the "filtered out" number to check this.

Expand Down

0 comments on commit c7cf8b6

Please sign in to comment.