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

Add --deny flag support #1591

Closed
wants to merge 11 commits into from
5 changes: 5 additions & 0 deletions src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub struct DenoFlags {
pub allow_net: bool,
pub allow_env: bool,
pub allow_run: bool,
pub deny: bool,
pub types: bool,
pub prefetch: bool,
}
Expand Down Expand Up @@ -105,6 +106,9 @@ fn set_recognized_flags(
flags.allow_run = true;
flags.allow_write = true;
}
if matches.opt_present("deny") {
flags.deny = true;
}
if matches.opt_present("types") {
flags.types = true;
}
Expand Down Expand Up @@ -138,6 +142,7 @@ pub fn set_flags(
opts.optflag("", "allow-net", "Allow network access.");
opts.optflag("", "allow-env", "Allow environment access.");
opts.optflag("", "allow-run", "Allow running subprocesses.");
opts.optflag("", "deny", "Deny all permission requests");
opts.optflag("A", "allow-all", "Allow all permissions.");
opts.optflag("", "recompile", "Force recompilation of TypeScript code.");
opts.optflag("h", "help", "Print this message.");
Expand Down
49 changes: 27 additions & 22 deletions src/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct DenoPermissions {
pub allow_net: AtomicBool,
pub allow_env: AtomicBool,
pub allow_run: AtomicBool,
pub deny: bool,
}

impl DenoPermissions {
Expand All @@ -24,6 +25,28 @@ impl DenoPermissions {
allow_env: AtomicBool::new(flags.allow_env),
allow_net: AtomicBool::new(flags.allow_net),
allow_run: AtomicBool::new(flags.allow_run),
deny: flags.deny,
}
}

fn permission_prompt(&self, message: &str) -> DenoResult<()> {
if !atty::is(atty::Stream::Stdin)
|| !atty::is(atty::Stream::Stderr)
|| self.deny
{
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 input = String::new();
let stdin = io::stdin();
let _nread = stdin.read_line(&mut input)?;
let ch = input.chars().next().unwrap();
let is_yes = ch == 'y' || ch == 'Y';
if is_yes {
Ok(())
} else {
Err(permission_denied())
}
}

Expand All @@ -32,7 +55,7 @@ impl DenoPermissions {
return Ok(());
};
// TODO get location (where access occurred)
let r = permission_prompt("Deno requests access to run a subprocess.");
let r = self.permission_prompt("Deno requests access to run a subprocess.");
if r.is_ok() {
self.allow_run.store(true, Ordering::SeqCst);
}
Expand All @@ -44,7 +67,7 @@ impl DenoPermissions {
return Ok(());
};
// TODO get location (where access occurred)
let r = permission_prompt(&format!(
let r = self.permission_prompt(&format!(
"Deno requests write access to \"{}\".",
filename
));;
Expand All @@ -59,7 +82,7 @@ impl DenoPermissions {
return Ok(());
};
// TODO get location (where access occurred)
let r = permission_prompt(&format!(
let r = self.permission_prompt(&format!(
"Deno requests network access to \"{}\".",
domain_name
));
Expand All @@ -75,28 +98,10 @@ impl DenoPermissions {
};
// TODO get location (where access occurred)
let r =
permission_prompt(&"Deno requests access to environment variables.");
self.permission_prompt(&"Deno requests access to environment variables.");
if r.is_ok() {
self.allow_env.store(true, Ordering::SeqCst);
}
r
}
}

fn permission_prompt(message: &str) -> 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 input = String::new();
let stdin = io::stdin();
let _nread = stdin.read_line(&mut input)?;
let ch = input.chars().next().unwrap();
let is_yes = ch == 'y' || ch == 'Y';
if is_yes {
Ok(())
} else {
Err(permission_denied())
}
}
37 changes: 36 additions & 1 deletion tools/permission_prompt_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ def run(self,
allow_write=False,
allow_net=False,
allow_env=False,
allow_run=False):
allow_run=False,
deny=False):
"Returns (return_code, stdout, stderr)."
cmd = [self.deno_exe, PERMISSIONS_PROMPT_TEST_TS, arg]
if deny:
cmd.append("--deny")
if allow_write:
cmd.append("--allow-write")
if allow_net:
Expand Down Expand Up @@ -142,6 +145,34 @@ def test_run_no(self):
assert b'PermissionDenied: permission denied' in stderr
assert b'Deno requests access to run' in stderr

def test_deny_run(self):
code, _stdout, stderr = self.run('needsRun', b'', deny=True)
assert code == 1
assert b'PermissionDenied: permission denied' in stderr

def test_deny_net(self):
code, _stdout, stderr = self.run('needsNet', b'', deny=True)
assert code == 1
assert b'PermissionDenied: permission denied' in stderr

def test_deny_but_allow_run(self):
code, stdout, stderr = self.run('needsRun',
b'',
allow_run=True,
deny=True)
assert code == 0
assert stdout == b'hello'
assert stderr == b''

def test_deny_but_allow_net(self):
code, stdout, stderr = self.run('needsNet',
b'',
allow_net=True,
deny=True)
assert code == 0
assert stdout == b''
assert stderr == b''


def permission_prompt_test(deno_exe):
p = Prompt(deno_exe)
Expand All @@ -158,6 +189,10 @@ def permission_prompt_test(deno_exe):
p.test_run_yes()
p.test_run_arg()
p.test_run_no()
p.test_deny_run()
p.test_deny_net()
p.test_deny_but_allow_run()
p.test_deny_but_allow_net()


def main():
Expand Down