Skip to content

Commit

Permalink
Prompt user for overriding permissions
Browse files Browse the repository at this point in the history
This is only available if stdin is tty.
Move permissions to its own module.
Update third_party - add atty.
  • Loading branch information
hayd committed Oct 22, 2018
1 parent 5114512 commit e16e317
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 54 deletions.
13 changes: 7 additions & 6 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,24 @@ config("deno_config") {
}

main_extern = [
"$rust_build:atty",
"$rust_build:dirs",
"$rust_build:futures",
"$rust_build:hyper",
"$rust_build:hyper_rustls",
"$rust_build:futures",
"$rust_build:lazy_static",
"$rust_build:libc",
"$rust_build:log",
"$rust_build:rand",
"$rust_build:remove_dir_all",
"$rust_build:ring",
"$rust_build:tempfile",
"$rust_build:rand",
"$rust_build:tokio",
"$rust_build:tokio_io",
"$rust_build:tokio_fs",
"$rust_build:tokio_executor",
"$rust_build:tokio_fs",
"$rust_build:tokio_io",
"$rust_build:tokio_threadpool",
"$rust_build:url",
"$rust_build:remove_dir_all",
"$rust_build:dirs",
"//build_extra/flatbuffers/rust:flatbuffers",
":msg_rs",
]
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ name = "deno"
version = "0.0.0"

[dependencies]
atty = "0.2.11"
dirs = "1.0.4"
flatbuffers = { path = "third_party/flatbuffers/rust/flatbuffers/" }
futures = "0.1.25"
Expand Down
14 changes: 13 additions & 1 deletion build_extra/rust/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,15 @@ rust_crate("winapi") {
"basetsd",
"cfg",
"cfgmgr32",
"consoleapi",
"combaseapi",
"errhandlingapi",
"excpt",
"fileapi",
"guiddef",
"handleapi",
"inaddr",
"in6addr",
"inaddr",
"knownfolders",
"ktmtypes",
"libloaderapi",
Expand All @@ -134,6 +135,7 @@ rust_crate("winapi") {
"objbase",
"objidl",
"objidlbase",
"processenv",
"processthreadsapi",
"profileapi",
"propidl",
Expand All @@ -152,8 +154,10 @@ rust_crate("winapi") {
"vadefs",
"vcruntime",
"winbase",
"wincon",
"wincred",
"windef",
"wingdi",
"winerror",
"winnt",
"winreg",
Expand Down Expand Up @@ -862,6 +866,14 @@ rust_crate("sct") {
]
}

rust_crate("atty") {
source_root = "$registry_github/atty-0.2.11/src/lib.rs"
extern = [
":libc",
":winapi",
]
}

rust_crate("base64") {
source_root = "$registry_github/base64-0.9.2/src/lib.rs"
extern = [
Expand Down
42 changes: 12 additions & 30 deletions src/flags.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
use errors::DenoResult;
use errors::permission_denied;
use libc::c_int;
use libdeno;
use log;
Expand All @@ -9,6 +7,8 @@ use std::ffi::CString;
use std::mem;
use std::vec::Vec;

use permissions::DenoPermissions;

// Creates vector of strings, Vec<String>
#[cfg(test)]
macro_rules! svec {
Expand All @@ -22,30 +22,13 @@ pub struct DenoFlags {
pub version: bool,
pub reload: bool,
pub recompile: bool,
allow_write: bool,
allow_net: bool,
allow_env: bool,
pub permissions: DenoPermissions,
pub deps_flag: bool,
pub types_flag: bool,
}

impl DenoFlags {

pub fn permissions_check_write(&self, filename: &str) -> DenoResult<()> {
if self.allow_write { return Ok(()) };
permission_prompt(format!("XX requests write access to \"{}\".", filename))
}

pub fn permissions_check_net(&self, domain_name: &str) -> DenoResult<()> {
if self.allow_net { return Ok(()) };
permission_prompt(format!("XX requests network access to \"{}\".", domain_name))
}

pub fn permissions_check_env(&self) -> DenoResult<()> {
if self.allow_env { return Ok(()) };
permission_prompt("XX requests access to environment variables.".to_string())
}

pub fn set_log_level(&self) {
let mut log_level = log::LevelFilter::Info;
if self.log_debug {
Expand Down Expand Up @@ -75,11 +58,6 @@ DENO_DIR Set deno's base directory."
}
}

fn permission_prompt(message: String) -> DenoResult<()> {
println!("{}", message);
Err(permission_denied())
}

// Parses flags for deno. This does not do v8_set_flags() - call that separately.
pub fn set_flags(
args: Vec<String>,
Expand All @@ -98,9 +76,9 @@ pub fn set_flags(
"--version" => flags.version = true,
"--reload" => flags.reload = true,
"--recompile" => flags.recompile = true,
"--allow-write" => flags.allow_write = true,
"--allow-net" => flags.allow_net = true,
"--allow-env" => flags.allow_env = true,
"--allow-write" => flags.permissions.allow_write(true),
"--allow-net" => flags.permissions.allow_net(true),
"--allow-env" => flags.permissions.allow_env(true),
"--deps" => flags.deps_flag = true,
"--types" => flags.types_flag = true,
"--" => break,
Expand Down Expand Up @@ -161,11 +139,13 @@ fn test_set_flags_3() {
set_flags(svec!["deno", "-r", "--deps", "script.ts", "--allow-write"])
.unwrap();
assert_eq!(rest, svec!["deno", "script.ts"]);
let mut expected_permissions = DenoPermissions::default();
expected_permissions.allow_write(true);
assert_eq!(
flags,
DenoFlags {
reload: true,
allow_write: true,
permissions: expected_permissions,
deps_flag: true,
..DenoFlags::default()
}
Expand All @@ -177,12 +157,14 @@ fn test_set_flags_4() {
let (flags, rest) =
set_flags(svec!["deno", "-Dr", "script.ts", "--allow-write"]).unwrap();
assert_eq!(rest, svec!["deno", "script.ts"]);
let mut expected_permissions = DenoPermissions::default();
expected_permissions.allow_write(true);
assert_eq!(
flags,
DenoFlags {
log_debug: true,
reload: true,
allow_write: true,
permissions: expected_permissions,
..DenoFlags::default()
}
);
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mod http_util;
mod isolate;
mod libdeno;
pub mod ops;
mod permissions;
mod resources;
mod tokio_util;
mod tokio_write;
Expand Down
32 changes: 16 additions & 16 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,9 @@ fn op_set_env(
let key = inner.key().unwrap();
let value = inner.value().unwrap();

if state.flags.permissions_check_env().is_err() {
if state.flags.permissions.check_env().is_err() {
return odd_future(permission_denied());
};
}
std::env::set_var(key, value);
ok_future(empty_buf())
}
Expand All @@ -347,9 +347,9 @@ fn op_env(
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();

if state.flags.permissions_check_env().is_err() {
if state.flags.permissions.check_env().is_err() {
return odd_future(permission_denied());
};
}

let builder = &mut FlatBufferBuilder::new();
let vars: Vec<_> = std::env::vars()
Expand Down Expand Up @@ -397,7 +397,7 @@ fn op_fetch_req(
let url = inner.url().unwrap();

// FIXME use domain (or use this inside check_net)
if state.flags.permissions_check_net(url).is_err() {
if state.flags.permissions.check_net(url).is_err() {
return odd_future(permission_denied());
}

Expand Down Expand Up @@ -512,7 +512,7 @@ fn op_make_temp_dir(
let cmd_id = base.cmd_id();

// FIXME
if state.flags.permissions_check_write("make_temp").is_err() {
if state.flags.permissions.check_write("make_temp").is_err() {
return odd_future(permission_denied());
}

Expand Down Expand Up @@ -561,7 +561,7 @@ fn op_mkdir(
let mode = inner.mode();
let path = String::from(inner.path().unwrap());

if state.flags.permissions_check_write(&path).is_err() {
if state.flags.permissions.check_write(&path).is_err() {
return odd_future(permission_denied());
}
blocking!(base.sync(), || {
Expand Down Expand Up @@ -738,7 +738,7 @@ fn op_remove(
let path = PathBuf::from(path_);
let recursive = inner.recursive();

if state.flags.permissions_check_write(&path_).is_err() {
if state.flags.permissions.check_write(&path_).is_err() {
return odd_future(permission_denied());
}

Expand Down Expand Up @@ -805,7 +805,7 @@ fn op_copy_file(
let to_ = inner.to().unwrap();
let to = PathBuf::from(to_);

if state.flags.permissions_check_write(&to_).is_err() {
if state.flags.permissions.check_write(&to_).is_err() {
return odd_future(permission_denied());
}

Expand Down Expand Up @@ -990,7 +990,7 @@ fn op_write_file(
let filename = String::from(inner.filename().unwrap());
let perm = inner.perm();

if state.flags.permissions_check_write(&filename).is_err() {
if state.flags.permissions.check_write(&filename).is_err() {
return odd_future(permission_denied());
}

Expand All @@ -1011,7 +1011,7 @@ fn op_rename(
let oldpath = PathBuf::from(inner.oldpath().unwrap());
let newpath_ = inner.newpath().unwrap();
let newpath = PathBuf::from(newpath_);
if state.flags.permissions_check_write(&newpath_).is_err() {
if state.flags.permissions.check_write(&newpath_).is_err() {
return odd_future(permission_denied());
}
blocking!(base.sync(), || -> OpResult {
Expand All @@ -1032,7 +1032,7 @@ fn op_symlink(
let newname_ = inner.newname().unwrap();
let newname = PathBuf::from(newname_);

if state.flags.permissions_check_write(&newname_).is_err() {
if state.flags.permissions.check_write(&newname_).is_err() {
return odd_future(permission_denied());
}
// TODO Use type for Windows.
Expand Down Expand Up @@ -1095,7 +1095,7 @@ fn op_truncate(
let filename = String::from(inner.name().unwrap());
let len = inner.len();

if state.flags.permissions_check_write(&filename).is_err() {
if state.flags.permissions.check_write(&filename).is_err() {
return odd_future(permission_denied());
}

Expand All @@ -1114,7 +1114,7 @@ fn op_listen(
) -> Box<Op> {
assert_eq!(data.len(), 0);
// FIXME
if state.flags.permissions_check_net("listen").is_err() {
if state.flags.permissions.check_net("listen").is_err() {
return odd_future(permission_denied());
}

Expand Down Expand Up @@ -1180,7 +1180,7 @@ fn op_accept(
data: &'static mut [u8],
) -> Box<Op> {
assert_eq!(data.len(), 0);
if state.flags.permissions_check_net("accept").is_err() {
if state.flags.permissions.check_net("accept").is_err() {
return odd_future(permission_denied());
}
let cmd_id = base.cmd_id();
Expand All @@ -1206,7 +1206,7 @@ fn op_dial(
data: &'static mut [u8],
) -> Box<Op> {
assert_eq!(data.len(), 0);
if state.flags.permissions_check_net("dial").is_err() {
if state.flags.permissions.check_net("dial").is_err() {
return odd_future(permission_denied());
}
let cmd_id = base.cmd_id();
Expand Down
56 changes: 56 additions & 0 deletions src/permissions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
extern crate atty;

use std::io;
use std::io::Read;
use errors::DenoResult;
use errors::permission_denied;

#[derive(Debug, Default, PartialEq)]
pub struct DenoPermissions {
allow_write: bool,
allow_net: bool,
allow_env: bool,
}

impl DenoPermissions {
pub fn check_write(&self, filename: &str) -> DenoResult<()> {
if self.allow_write { return Ok(()) };
// TODO get location (where access occurred)
permission_prompt(format!("Deno requests write access to \"{}\".", filename))
}

pub fn check_net(&self, domain_name: &str) -> DenoResult<()> {
if self.allow_net { return Ok(()) };
// TODO get location (where access occurred)
permission_prompt(format!("Deno requests network access to \"{}\".", domain_name))
}

pub fn check_env(&self) -> DenoResult<()> {
if self.allow_env { return Ok(()) };
// TODO get location (where access occurred)
permission_prompt("Deno requests access to environment variables.".to_string())
}

pub fn allow_write(&mut self, b: bool) -> () {
self.allow_write = b;
}

pub fn allow_net(&mut self, b: bool) -> () {
self.allow_net = b;
}

pub fn allow_env(&mut self, b: bool) -> () {
self.allow_env = b;
}
}

fn permission_prompt(message: String) -> DenoResult<()> {
if !atty::is(atty::Stream::Stdin) || !atty::is(atty::Stream::Stderr) { return Err(permission_denied()) };
// print to stderr so that if deno is > to a file this is still displayed.
eprint!("{} Grant? yN", message);
let mut buf = vec![0u8; 1];
io::stdin().read_exact(&mut buf)?;
let input = buf[0];
let is_yes = input == 'y' as u8 || input == 'Y' as u8;
if is_yes { Ok(()) } else { Err(permission_denied()) }
}

0 comments on commit e16e317

Please sign in to comment.