mirror of
https://github.com/denoland/deno.git
synced 2025-01-18 03:44:05 -05:00
feat(permissions): grant all permission for a group in permission prompt (#17140)
This commit adds new "A" option to the interactive permission prompt, that will allow all subsequent permissions for given group (domain). Ie. when querying for permissions to access eg. env variables responding with "A" will allow access to all environmental variables. This works for all permission domains and should make permission prompts more ergonomic for users.
This commit is contained in:
parent
5fcbdd6228
commit
c18e0d1d37
5 changed files with 363 additions and 151 deletions
|
@ -591,6 +591,62 @@ fn _090_run_permissions_request_sync() {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn permissions_prompt_allow_all() {
|
||||||
|
let args = "run --quiet run/permissions_prompt_allow_all.ts";
|
||||||
|
use util::PtyData::*;
|
||||||
|
util::test_pty2(args, vec![
|
||||||
|
// "run" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests run access to \"FOO\".\r\n├ Requested by `Deno.permissions.query()` API\r\n ├ Run again with --allow-run to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all run permissions) >"),
|
||||||
|
Input("a\n"),
|
||||||
|
Output("✅ Granted all run access.\r\n"),
|
||||||
|
// "read" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests read access to \"FOO\".\r\n├ Requested by `Deno.permissions.query()` API\r\n ├ Run again with --allow-read to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions) >"),
|
||||||
|
Input("a\n"),
|
||||||
|
Output("✅ Granted all read access.\r\n"),
|
||||||
|
// "write" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests write access to \"FOO\".\r\n├ Requested by `Deno.permissions.query()` API\r\n ├ Run again with --allow-write to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all write permissions) >"),
|
||||||
|
Input("a\n"),
|
||||||
|
Output("✅ Granted all write access.\r\n"),
|
||||||
|
// "net" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests net access to \"FOO\".\r\n├ Requested by `Deno.permissions.query()` API\r\n ├ Run again with --allow-net to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all net permissions) >"),
|
||||||
|
Input("a\n"),
|
||||||
|
Output("✅ Granted all net access.\r\n"),
|
||||||
|
// "env" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests env access to \"FOO\".\r\n├ Requested by `Deno.permissions.query()` API\r\n ├ Run again with --allow-env to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions) >"),
|
||||||
|
Input("a\n"),
|
||||||
|
Output("✅ Granted all env access.\r\n"),
|
||||||
|
// "sys" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests sys access to \"loadavg\".\r\n├ Requested by `Deno.permissions.query()` API\r\n ├ Run again with --allow-sys to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all sys permissions) >"),
|
||||||
|
Input("a\n"),
|
||||||
|
Output("✅ Granted all sys access.\r\n"),
|
||||||
|
// "ffi" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests ffi access to \"FOO\".\r\n├ Requested by `Deno.permissions.query()` API\r\n ├ Run again with --allow-ffi to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all ffi permissions) >"),
|
||||||
|
Input("a\n"),
|
||||||
|
Output("✅ Granted all ffi access.\r\n")
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn permissions_prompt_allow_all_2() {
|
||||||
|
let args = "run --quiet run/permissions_prompt_allow_all_2.ts";
|
||||||
|
use util::PtyData::*;
|
||||||
|
util::test_pty2(args, vec![
|
||||||
|
// "env" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests env access to \"FOO\".\r\n├ Run again with --allow-env to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all env permissions) >"),
|
||||||
|
Input("d\n"),
|
||||||
|
Output("✅ Granted all env access.\r\n"),
|
||||||
|
// "sys" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests sys access to \"FOO\".\r\n├ Run again with --allow-sys to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all sys permissions) >"),
|
||||||
|
Input("d\n"),
|
||||||
|
Output("✅ Granted all sys access.\r\n"),
|
||||||
|
// "read" permissions
|
||||||
|
Output("┌ ⚠️ Deno requests read access to \"FOO\".\r\n├ Run again with --allow-read to bypass this prompt.\r\n└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions) >"),
|
||||||
|
Input("d\n"),
|
||||||
|
Output("✅ Granted all read access.\r\n"),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
itest!(_091_use_define_for_class_fields {
|
itest!(_091_use_define_for_class_fields {
|
||||||
args: "run --check run/091_use_define_for_class_fields.ts",
|
args: "run --check run/091_use_define_for_class_fields.ts",
|
||||||
output: "run/091_use_define_for_class_fields.ts.out",
|
output: "run/091_use_define_for_class_fields.ts.out",
|
||||||
|
|
20
cli/tests/testdata/run/permissions_prompt_allow_all.ts
vendored
Normal file
20
cli/tests/testdata/run/permissions_prompt_allow_all.ts
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Deno.permissions.requestSync({ name: "run", command: "FOO" });
|
||||||
|
Deno.permissions.requestSync({ name: "run", command: "BAR" });
|
||||||
|
|
||||||
|
Deno.permissions.requestSync({ name: "read", path: "FOO" });
|
||||||
|
Deno.permissions.requestSync({ name: "read", path: "BAR" });
|
||||||
|
|
||||||
|
Deno.permissions.requestSync({ name: "write", path: "FOO" });
|
||||||
|
Deno.permissions.requestSync({ name: "write", path: "BAR" });
|
||||||
|
|
||||||
|
Deno.permissions.requestSync({ name: "net", host: "FOO" });
|
||||||
|
Deno.permissions.requestSync({ name: "net", host: "BAR" });
|
||||||
|
|
||||||
|
Deno.permissions.requestSync({ name: "env", variable: "FOO" });
|
||||||
|
Deno.permissions.requestSync({ name: "env", variable: "BAR" });
|
||||||
|
|
||||||
|
Deno.permissions.requestSync({ name: "sys", kind: "loadavg" });
|
||||||
|
Deno.permissions.requestSync({ name: "sys", kind: "hostname" });
|
||||||
|
|
||||||
|
Deno.permissions.requestSync({ name: "ffi", path: "FOO" });
|
||||||
|
Deno.permissions.requestSync({ name: "ffi", path: "BAR" });
|
8
cli/tests/testdata/run/permissions_prompt_allow_all_2.ts
vendored
Normal file
8
cli/tests/testdata/run/permissions_prompt_allow_all_2.ts
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Deno.env.get("FOO");
|
||||||
|
Deno.env.get("BAR");
|
||||||
|
|
||||||
|
Deno.loadavg();
|
||||||
|
Deno.hostname();
|
||||||
|
|
||||||
|
Deno.cwd();
|
||||||
|
Deno.lstatSync(new URL("../", import.meta.url));
|
|
@ -90,7 +90,7 @@ impl PermissionState {
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
info: Option<&str>,
|
info: Option<&str>,
|
||||||
prompt: bool,
|
prompt: bool,
|
||||||
) -> (Result<(), AnyError>, bool) {
|
) -> (Result<(), AnyError>, bool, bool) {
|
||||||
self.check2(name, api_name, || info.map(|s| s.to_string()), prompt)
|
self.check2(name, api_name, || info.map(|s| s.to_string()), prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,11 +101,11 @@ impl PermissionState {
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
info: impl Fn() -> Option<String>,
|
info: impl Fn() -> Option<String>,
|
||||||
prompt: bool,
|
prompt: bool,
|
||||||
) -> (Result<(), AnyError>, bool) {
|
) -> (Result<(), AnyError>, bool, bool) {
|
||||||
match self {
|
match self {
|
||||||
PermissionState::Granted => {
|
PermissionState::Granted => {
|
||||||
Self::log_perm_access(name, info);
|
Self::log_perm_access(name, info);
|
||||||
(Ok(()), false)
|
(Ok(()), false, false)
|
||||||
}
|
}
|
||||||
PermissionState::Prompt if prompt => {
|
PermissionState::Prompt if prompt => {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
|
@ -113,14 +113,19 @@ impl PermissionState {
|
||||||
name,
|
name,
|
||||||
info().map_or(String::new(), |info| { format!(" to {info}") }),
|
info().map_or(String::new(), |info| { format!(" to {info}") }),
|
||||||
);
|
);
|
||||||
if PromptResponse::Allow == permission_prompt(&msg, name, api_name) {
|
match permission_prompt(&msg, name, api_name, true) {
|
||||||
Self::log_perm_access(name, info);
|
PromptResponse::Allow => {
|
||||||
(Ok(()), true)
|
Self::log_perm_access(name, info);
|
||||||
} else {
|
(Ok(()), true, false)
|
||||||
(Err(Self::error(name, info)), true)
|
}
|
||||||
|
PromptResponse::AllowAll => {
|
||||||
|
Self::log_perm_access(name, info);
|
||||||
|
(Ok(()), true, true)
|
||||||
|
}
|
||||||
|
PromptResponse::Deny => (Err(Self::error(name, info)), true, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (Err(Self::error(name, info)), false),
|
_ => (Err(Self::error(name, info)), false, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,6 +166,7 @@ impl UnitPermission {
|
||||||
&format!("access to {}", self.description),
|
&format!("access to {}", self.description),
|
||||||
self.name,
|
self.name,
|
||||||
Some("Deno.permissions.query()"),
|
Some("Deno.permissions.query()"),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.state = PermissionState::Granted;
|
self.state = PermissionState::Granted;
|
||||||
|
@ -179,7 +185,7 @@ impl UnitPermission {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&mut self) -> Result<(), AnyError> {
|
pub fn check(&mut self) -> Result<(), AnyError> {
|
||||||
let (result, prompted) =
|
let (result, prompted, _is_allow_all) =
|
||||||
self.state.check(self.name, None, None, self.prompt);
|
self.state.check(self.name, None, None, self.prompt);
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
|
@ -357,19 +363,26 @@ impl UnaryPermission<ReadDescriptor> {
|
||||||
let (resolved_path, display_path) = resolved_and_display_path(path);
|
let (resolved_path, display_path) = resolved_and_display_path(path);
|
||||||
let state = self.query(Some(&resolved_path));
|
let state = self.query(Some(&resolved_path));
|
||||||
if state == PermissionState::Prompt {
|
if state == PermissionState::Prompt {
|
||||||
if PromptResponse::Allow
|
match permission_prompt(
|
||||||
== permission_prompt(
|
&format!("read access to \"{}\"", display_path.display()),
|
||||||
&format!("read access to \"{}\"", display_path.display()),
|
self.name,
|
||||||
self.name,
|
Some("Deno.permissions.query()"),
|
||||||
Some("Deno.permissions.query()"),
|
true,
|
||||||
)
|
) {
|
||||||
{
|
PromptResponse::Allow => {
|
||||||
self.granted_list.insert(ReadDescriptor(resolved_path));
|
self.granted_list.insert(ReadDescriptor(resolved_path));
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
}
|
||||||
self.denied_list.insert(ReadDescriptor(resolved_path));
|
PromptResponse::Deny => {
|
||||||
self.global_state = PermissionState::Denied;
|
self.denied_list.insert(ReadDescriptor(resolved_path));
|
||||||
PermissionState::Denied
|
self.global_state = PermissionState::Denied;
|
||||||
|
PermissionState::Denied
|
||||||
|
}
|
||||||
|
PromptResponse::AllowAll => {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
PermissionState::Granted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if state == PermissionState::Granted {
|
} else if state == PermissionState::Granted {
|
||||||
self.granted_list.insert(ReadDescriptor(resolved_path));
|
self.granted_list.insert(ReadDescriptor(resolved_path));
|
||||||
|
@ -385,6 +398,7 @@ impl UnaryPermission<ReadDescriptor> {
|
||||||
"read access",
|
"read access",
|
||||||
self.name,
|
self.name,
|
||||||
Some("Deno.permissions.query()"),
|
Some("Deno.permissions.query()"),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.granted_list.clear();
|
self.granted_list.clear();
|
||||||
|
@ -421,7 +435,7 @@ impl UnaryPermission<ReadDescriptor> {
|
||||||
path: &Path,
|
path: &Path,
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let (result, prompted) = self.query(Some(path)).check2(
|
let (result, prompted, is_allow_all) = self.query(Some(path)).check2(
|
||||||
self.name,
|
self.name,
|
||||||
api_name,
|
api_name,
|
||||||
|| Some(format!("\"{}\"", path.to_path_buf().display())),
|
|| Some(format!("\"{}\"", path.to_path_buf().display())),
|
||||||
|
@ -430,7 +444,12 @@ impl UnaryPermission<ReadDescriptor> {
|
||||||
if prompted {
|
if prompted {
|
||||||
let resolved_path = resolve_from_cwd(path)?;
|
let resolved_path = resolve_from_cwd(path)?;
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(ReadDescriptor(resolved_path));
|
if is_allow_all {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.granted_list.insert(ReadDescriptor(resolved_path));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(ReadDescriptor(resolved_path));
|
self.denied_list.insert(ReadDescriptor(resolved_path));
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
|
@ -448,25 +467,33 @@ impl UnaryPermission<ReadDescriptor> {
|
||||||
api_name: &str,
|
api_name: &str,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let resolved_path = resolve_from_cwd(path)?;
|
let resolved_path = resolve_from_cwd(path)?;
|
||||||
let (result, prompted) = self.query(Some(&resolved_path)).check(
|
let (result, prompted, is_allow_all) =
|
||||||
self.name,
|
self.query(Some(&resolved_path)).check(
|
||||||
Some(api_name),
|
self.name,
|
||||||
Some(&format!("<{display}>")),
|
Some(api_name),
|
||||||
self.prompt,
|
Some(&format!("<{display}>")),
|
||||||
);
|
self.prompt,
|
||||||
|
);
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(ReadDescriptor(resolved_path));
|
if is_allow_all {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.granted_list.insert(ReadDescriptor(resolved_path));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(ReadDescriptor(resolved_path));
|
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
|
if !is_allow_all {
|
||||||
|
self.denied_list.insert(ReadDescriptor(resolved_path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||||
let (result, prompted) =
|
let (result, prompted, _) =
|
||||||
self
|
self
|
||||||
.query(None)
|
.query(None)
|
||||||
.check(self.name, api_name, Some("all"), self.prompt);
|
.check(self.name, api_name, Some("all"), self.prompt);
|
||||||
|
@ -530,19 +557,26 @@ impl UnaryPermission<WriteDescriptor> {
|
||||||
let (resolved_path, display_path) = resolved_and_display_path(path);
|
let (resolved_path, display_path) = resolved_and_display_path(path);
|
||||||
let state = self.query(Some(&resolved_path));
|
let state = self.query(Some(&resolved_path));
|
||||||
if state == PermissionState::Prompt {
|
if state == PermissionState::Prompt {
|
||||||
if PromptResponse::Allow
|
match permission_prompt(
|
||||||
== permission_prompt(
|
&format!("write access to \"{}\"", display_path.display()),
|
||||||
&format!("write access to \"{}\"", display_path.display()),
|
self.name,
|
||||||
self.name,
|
Some("Deno.permissions.query()"),
|
||||||
Some("Deno.permissions.query()"),
|
true,
|
||||||
)
|
) {
|
||||||
{
|
PromptResponse::Allow => {
|
||||||
self.granted_list.insert(WriteDescriptor(resolved_path));
|
self.granted_list.insert(WriteDescriptor(resolved_path));
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
}
|
||||||
self.denied_list.insert(WriteDescriptor(resolved_path));
|
PromptResponse::Deny => {
|
||||||
self.global_state = PermissionState::Denied;
|
self.denied_list.insert(WriteDescriptor(resolved_path));
|
||||||
PermissionState::Denied
|
self.global_state = PermissionState::Denied;
|
||||||
|
PermissionState::Denied
|
||||||
|
}
|
||||||
|
PromptResponse::AllowAll => {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
PermissionState::Granted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if state == PermissionState::Granted {
|
} else if state == PermissionState::Granted {
|
||||||
self.granted_list.insert(WriteDescriptor(resolved_path));
|
self.granted_list.insert(WriteDescriptor(resolved_path));
|
||||||
|
@ -558,6 +592,7 @@ impl UnaryPermission<WriteDescriptor> {
|
||||||
"write access",
|
"write access",
|
||||||
self.name,
|
self.name,
|
||||||
Some("Deno.permissions.query()"),
|
Some("Deno.permissions.query()"),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.granted_list.clear();
|
self.granted_list.clear();
|
||||||
|
@ -594,7 +629,7 @@ impl UnaryPermission<WriteDescriptor> {
|
||||||
path: &Path,
|
path: &Path,
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let (result, prompted) = self.query(Some(path)).check2(
|
let (result, prompted, is_allow_all) = self.query(Some(path)).check2(
|
||||||
self.name,
|
self.name,
|
||||||
api_name,
|
api_name,
|
||||||
|| Some(format!("\"{}\"", path.to_path_buf().display())),
|
|| Some(format!("\"{}\"", path.to_path_buf().display())),
|
||||||
|
@ -603,7 +638,12 @@ impl UnaryPermission<WriteDescriptor> {
|
||||||
if prompted {
|
if prompted {
|
||||||
let resolved_path = resolve_from_cwd(path)?;
|
let resolved_path = resolve_from_cwd(path)?;
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(WriteDescriptor(resolved_path));
|
if is_allow_all {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.granted_list.insert(WriteDescriptor(resolved_path));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(WriteDescriptor(resolved_path));
|
self.denied_list.insert(WriteDescriptor(resolved_path));
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
|
@ -613,7 +653,7 @@ impl UnaryPermission<WriteDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||||
let (result, prompted) =
|
let (result, prompted, _) =
|
||||||
self
|
self
|
||||||
.query(None)
|
.query(None)
|
||||||
.check(self.name, api_name, Some("all"), self.prompt);
|
.check(self.name, api_name, Some("all"), self.prompt);
|
||||||
|
@ -685,19 +725,26 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
let state = self.query(Some(host));
|
let state = self.query(Some(host));
|
||||||
let host = NetDescriptor::new(&host);
|
let host = NetDescriptor::new(&host);
|
||||||
if state == PermissionState::Prompt {
|
if state == PermissionState::Prompt {
|
||||||
if PromptResponse::Allow
|
match permission_prompt(
|
||||||
== permission_prompt(
|
&format!("network access to \"{host}\""),
|
||||||
&format!("network access to \"{host}\""),
|
self.name,
|
||||||
self.name,
|
Some("Deno.permissions.query()"),
|
||||||
Some("Deno.permissions.query()"),
|
true,
|
||||||
)
|
) {
|
||||||
{
|
PromptResponse::Allow => {
|
||||||
self.granted_list.insert(host);
|
self.granted_list.insert(host);
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
}
|
||||||
self.denied_list.insert(host);
|
PromptResponse::Deny => {
|
||||||
self.global_state = PermissionState::Denied;
|
self.denied_list.insert(host);
|
||||||
PermissionState::Denied
|
self.global_state = PermissionState::Denied;
|
||||||
|
PermissionState::Denied
|
||||||
|
}
|
||||||
|
PromptResponse::AllowAll => {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
PermissionState::Granted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if state == PermissionState::Granted {
|
} else if state == PermissionState::Granted {
|
||||||
self.granted_list.insert(host);
|
self.granted_list.insert(host);
|
||||||
|
@ -713,6 +760,7 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
"network access",
|
"network access",
|
||||||
self.name,
|
self.name,
|
||||||
Some("Deno.permissions.query()"),
|
Some("Deno.permissions.query()"),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.granted_list.clear();
|
self.granted_list.clear();
|
||||||
|
@ -756,7 +804,7 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let new_host = NetDescriptor::new(&host);
|
let new_host = NetDescriptor::new(&host);
|
||||||
let (result, prompted) = self.query(Some(host)).check(
|
let (result, prompted, is_allow_all) = self.query(Some(host)).check(
|
||||||
self.name,
|
self.name,
|
||||||
api_name,
|
api_name,
|
||||||
Some(&format!("\"{new_host}\"")),
|
Some(&format!("\"{new_host}\"")),
|
||||||
|
@ -764,7 +812,12 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
);
|
);
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(new_host);
|
if is_allow_all {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.granted_list.insert(new_host);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(new_host);
|
self.denied_list.insert(new_host);
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
|
@ -787,7 +840,7 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
Some(port) => format!("{hostname}:{port}"),
|
Some(port) => format!("{hostname}:{port}"),
|
||||||
};
|
};
|
||||||
let host = &(&hostname, url.port_or_known_default());
|
let host = &(&hostname, url.port_or_known_default());
|
||||||
let (result, prompted) = self.query(Some(host)).check(
|
let (result, prompted, is_allow_all) = self.query(Some(host)).check(
|
||||||
self.name,
|
self.name,
|
||||||
api_name,
|
api_name,
|
||||||
Some(&format!("\"{display_host}\"")),
|
Some(&format!("\"{display_host}\"")),
|
||||||
|
@ -795,7 +848,12 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
);
|
);
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(NetDescriptor::new(&host));
|
if is_allow_all {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.granted_list.insert(NetDescriptor::new(&host));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(NetDescriptor::new(&host));
|
self.denied_list.insert(NetDescriptor::new(&host));
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
|
@ -805,7 +863,7 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||||
let (result, prompted) =
|
let (result, prompted, _) =
|
||||||
self
|
self
|
||||||
.query::<&str>(None)
|
.query::<&str>(None)
|
||||||
.check(self.name, None, Some("all"), self.prompt);
|
.check(self.name, None, Some("all"), self.prompt);
|
||||||
|
@ -859,19 +917,26 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
if let Some(env) = env {
|
if let Some(env) = env {
|
||||||
let state = self.query(Some(env));
|
let state = self.query(Some(env));
|
||||||
if state == PermissionState::Prompt {
|
if state == PermissionState::Prompt {
|
||||||
if PromptResponse::Allow
|
match permission_prompt(
|
||||||
== permission_prompt(
|
&format!("env access to \"{env}\""),
|
||||||
&format!("env access to \"{env}\""),
|
self.name,
|
||||||
self.name,
|
Some("Deno.permissions.query()"),
|
||||||
Some("Deno.permissions.query()"),
|
true,
|
||||||
)
|
) {
|
||||||
{
|
PromptResponse::Allow => {
|
||||||
self.granted_list.insert(EnvDescriptor::new(env));
|
self.granted_list.insert(EnvDescriptor::new(env));
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
}
|
||||||
self.denied_list.insert(EnvDescriptor::new(env));
|
PromptResponse::Deny => {
|
||||||
self.global_state = PermissionState::Denied;
|
self.denied_list.insert(EnvDescriptor::new(env));
|
||||||
PermissionState::Denied
|
self.global_state = PermissionState::Denied;
|
||||||
|
PermissionState::Denied
|
||||||
|
}
|
||||||
|
PromptResponse::AllowAll => {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
PermissionState::Granted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if state == PermissionState::Granted {
|
} else if state == PermissionState::Granted {
|
||||||
self.granted_list.insert(EnvDescriptor::new(env));
|
self.granted_list.insert(EnvDescriptor::new(env));
|
||||||
|
@ -887,6 +952,7 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
"env access",
|
"env access",
|
||||||
self.name,
|
self.name,
|
||||||
Some("Deno.permissions.query()"),
|
Some("Deno.permissions.query()"),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.granted_list.clear();
|
self.granted_list.clear();
|
||||||
|
@ -915,7 +981,7 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&mut self, env: &str) -> Result<(), AnyError> {
|
pub fn check(&mut self, env: &str) -> Result<(), AnyError> {
|
||||||
let (result, prompted) = self.query(Some(env)).check(
|
let (result, prompted, is_allow_all) = self.query(Some(env)).check(
|
||||||
self.name,
|
self.name,
|
||||||
None,
|
None,
|
||||||
Some(&format!("\"{env}\"")),
|
Some(&format!("\"{env}\"")),
|
||||||
|
@ -923,7 +989,12 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
);
|
);
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(EnvDescriptor::new(env));
|
if is_allow_all {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.granted_list.insert(EnvDescriptor::new(env));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(EnvDescriptor::new(env));
|
self.denied_list.insert(EnvDescriptor::new(env));
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
|
@ -933,7 +1004,7 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||||
let (result, prompted) =
|
let (result, prompted, _) =
|
||||||
self
|
self
|
||||||
.query(None)
|
.query(None)
|
||||||
.check(self.name, None, Some("all"), self.prompt);
|
.check(self.name, None, Some("all"), self.prompt);
|
||||||
|
@ -993,19 +1064,26 @@ impl UnaryPermission<SysDescriptor> {
|
||||||
}
|
}
|
||||||
if let Some(kind) = kind {
|
if let Some(kind) = kind {
|
||||||
let desc = SysDescriptor(kind.to_string());
|
let desc = SysDescriptor(kind.to_string());
|
||||||
if PromptResponse::Allow
|
match permission_prompt(
|
||||||
== permission_prompt(
|
&format!("sys access to \"{kind}\""),
|
||||||
&format!("sys access to \"{kind}\""),
|
self.name,
|
||||||
self.name,
|
Some("Deno.permissions.query()"),
|
||||||
Some("Deno.permissions.query()"),
|
true,
|
||||||
)
|
) {
|
||||||
{
|
PromptResponse::Allow => {
|
||||||
self.granted_list.insert(desc);
|
self.granted_list.insert(desc);
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
}
|
||||||
self.denied_list.insert(desc);
|
PromptResponse::Deny => {
|
||||||
self.global_state = PermissionState::Denied;
|
self.denied_list.insert(desc);
|
||||||
PermissionState::Denied
|
self.global_state = PermissionState::Denied;
|
||||||
|
PermissionState::Denied
|
||||||
|
}
|
||||||
|
PromptResponse::AllowAll => {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
PermissionState::Granted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if PromptResponse::Allow
|
if PromptResponse::Allow
|
||||||
|
@ -1013,6 +1091,7 @@ impl UnaryPermission<SysDescriptor> {
|
||||||
"sys access",
|
"sys access",
|
||||||
self.name,
|
self.name,
|
||||||
Some("Deno.permissions.query()"),
|
Some("Deno.permissions.query()"),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.global_state = PermissionState::Granted;
|
self.global_state = PermissionState::Granted;
|
||||||
|
@ -1041,7 +1120,7 @@ impl UnaryPermission<SysDescriptor> {
|
||||||
kind: &str,
|
kind: &str,
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let (result, prompted) = self.query(Some(kind)).check(
|
let (result, prompted, is_allow_all) = self.query(Some(kind)).check(
|
||||||
self.name,
|
self.name,
|
||||||
api_name,
|
api_name,
|
||||||
Some(&format!("\"{kind}\"")),
|
Some(&format!("\"{kind}\"")),
|
||||||
|
@ -1049,7 +1128,12 @@ impl UnaryPermission<SysDescriptor> {
|
||||||
);
|
);
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(SysDescriptor(kind.to_string()));
|
if is_allow_all {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.granted_list.insert(SysDescriptor(kind.to_string()));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(SysDescriptor(kind.to_string()));
|
self.denied_list.insert(SysDescriptor(kind.to_string()));
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
|
@ -1059,7 +1143,7 @@ impl UnaryPermission<SysDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||||
let (result, prompted) =
|
let (result, prompted, _is_allow_all) =
|
||||||
self
|
self
|
||||||
.query(None)
|
.query(None)
|
||||||
.check(self.name, None, Some("all"), self.prompt);
|
.check(self.name, None, Some("all"), self.prompt);
|
||||||
|
@ -1116,23 +1200,30 @@ impl UnaryPermission<RunDescriptor> {
|
||||||
if let Some(cmd) = cmd {
|
if let Some(cmd) = cmd {
|
||||||
let state = self.query(Some(cmd));
|
let state = self.query(Some(cmd));
|
||||||
if state == PermissionState::Prompt {
|
if state == PermissionState::Prompt {
|
||||||
if PromptResponse::Allow
|
match permission_prompt(
|
||||||
== permission_prompt(
|
&format!("run access to \"{cmd}\""),
|
||||||
&format!("run access to \"{cmd}\""),
|
self.name,
|
||||||
self.name,
|
Some("Deno.permissions.query()"),
|
||||||
Some("Deno.permissions.query()"),
|
true,
|
||||||
)
|
) {
|
||||||
{
|
PromptResponse::Allow => {
|
||||||
self
|
self
|
||||||
.granted_list
|
.granted_list
|
||||||
.insert(RunDescriptor::from_str(cmd).unwrap());
|
.insert(RunDescriptor::from_str(cmd).unwrap());
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
}
|
||||||
self
|
PromptResponse::Deny => {
|
||||||
.denied_list
|
self
|
||||||
.insert(RunDescriptor::from_str(cmd).unwrap());
|
.denied_list
|
||||||
self.global_state = PermissionState::Denied;
|
.insert(RunDescriptor::from_str(cmd).unwrap());
|
||||||
PermissionState::Denied
|
self.global_state = PermissionState::Denied;
|
||||||
|
PermissionState::Denied
|
||||||
|
}
|
||||||
|
PromptResponse::AllowAll => {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
PermissionState::Granted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if state == PermissionState::Granted {
|
} else if state == PermissionState::Granted {
|
||||||
self
|
self
|
||||||
|
@ -1150,6 +1241,7 @@ impl UnaryPermission<RunDescriptor> {
|
||||||
"run access",
|
"run access",
|
||||||
self.name,
|
self.name,
|
||||||
Some("Deno.permissions.query()"),
|
Some("Deno.permissions.query()"),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.granted_list.clear();
|
self.granted_list.clear();
|
||||||
|
@ -1184,7 +1276,7 @@ impl UnaryPermission<RunDescriptor> {
|
||||||
cmd: &str,
|
cmd: &str,
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let (result, prompted) = self.query(Some(cmd)).check(
|
let (result, prompted, is_allow_all) = self.query(Some(cmd)).check(
|
||||||
self.name,
|
self.name,
|
||||||
api_name,
|
api_name,
|
||||||
Some(&format!("\"{cmd}\"")),
|
Some(&format!("\"{cmd}\"")),
|
||||||
|
@ -1192,9 +1284,14 @@ impl UnaryPermission<RunDescriptor> {
|
||||||
);
|
);
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self
|
if is_allow_all {
|
||||||
.granted_list
|
self.granted_list.clear();
|
||||||
.insert(RunDescriptor::from_str(cmd).unwrap());
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
.granted_list
|
||||||
|
.insert(RunDescriptor::from_str(cmd).unwrap());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self
|
self
|
||||||
.denied_list
|
.denied_list
|
||||||
|
@ -1206,7 +1303,7 @@ impl UnaryPermission<RunDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||||
let (result, prompted) =
|
let (result, prompted, _) =
|
||||||
self
|
self
|
||||||
.query(None)
|
.query(None)
|
||||||
.check(self.name, api_name, Some("all"), self.prompt);
|
.check(self.name, api_name, Some("all"), self.prompt);
|
||||||
|
@ -1267,19 +1364,26 @@ impl UnaryPermission<FfiDescriptor> {
|
||||||
let (resolved_path, display_path) = resolved_and_display_path(path);
|
let (resolved_path, display_path) = resolved_and_display_path(path);
|
||||||
let state = self.query(Some(&resolved_path));
|
let state = self.query(Some(&resolved_path));
|
||||||
if state == PermissionState::Prompt {
|
if state == PermissionState::Prompt {
|
||||||
if PromptResponse::Allow
|
match permission_prompt(
|
||||||
== permission_prompt(
|
&format!("ffi access to \"{}\"", display_path.display()),
|
||||||
&format!("ffi access to \"{}\"", display_path.display()),
|
self.name,
|
||||||
self.name,
|
Some("Deno.permissions.query()"),
|
||||||
Some("Deno.permissions.query()"),
|
true,
|
||||||
)
|
) {
|
||||||
{
|
PromptResponse::Allow => {
|
||||||
self.granted_list.insert(FfiDescriptor(resolved_path));
|
self.granted_list.insert(FfiDescriptor(resolved_path));
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
}
|
||||||
self.denied_list.insert(FfiDescriptor(resolved_path));
|
PromptResponse::Deny => {
|
||||||
self.global_state = PermissionState::Denied;
|
self.denied_list.insert(FfiDescriptor(resolved_path));
|
||||||
PermissionState::Denied
|
self.global_state = PermissionState::Denied;
|
||||||
|
PermissionState::Denied
|
||||||
|
}
|
||||||
|
PromptResponse::AllowAll => {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
PermissionState::Granted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if state == PermissionState::Granted {
|
} else if state == PermissionState::Granted {
|
||||||
self.granted_list.insert(FfiDescriptor(resolved_path));
|
self.granted_list.insert(FfiDescriptor(resolved_path));
|
||||||
|
@ -1295,6 +1399,7 @@ impl UnaryPermission<FfiDescriptor> {
|
||||||
"ffi access",
|
"ffi access",
|
||||||
self.name,
|
self.name,
|
||||||
Some("Deno.permissions.query()"),
|
Some("Deno.permissions.query()"),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
self.granted_list.clear();
|
self.granted_list.clear();
|
||||||
|
@ -1328,16 +1433,22 @@ impl UnaryPermission<FfiDescriptor> {
|
||||||
pub fn check(&mut self, path: Option<&Path>) -> Result<(), AnyError> {
|
pub fn check(&mut self, path: Option<&Path>) -> Result<(), AnyError> {
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
let (resolved_path, display_path) = resolved_and_display_path(path);
|
let (resolved_path, display_path) = resolved_and_display_path(path);
|
||||||
let (result, prompted) = self.query(Some(&resolved_path)).check(
|
let (result, prompted, is_allow_all) =
|
||||||
self.name,
|
self.query(Some(&resolved_path)).check(
|
||||||
None,
|
self.name,
|
||||||
Some(&format!("\"{}\"", display_path.display())),
|
None,
|
||||||
self.prompt,
|
Some(&format!("\"{}\"", display_path.display())),
|
||||||
);
|
self.prompt,
|
||||||
|
);
|
||||||
|
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(FfiDescriptor(resolved_path));
|
if is_allow_all {
|
||||||
|
self.granted_list.clear();
|
||||||
|
self.global_state = PermissionState::Granted;
|
||||||
|
} else {
|
||||||
|
self.granted_list.insert(FfiDescriptor(resolved_path));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(FfiDescriptor(resolved_path));
|
self.denied_list.insert(FfiDescriptor(resolved_path));
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
|
@ -1346,7 +1457,7 @@ impl UnaryPermission<FfiDescriptor> {
|
||||||
|
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
let (result, prompted) =
|
let (result, prompted, _) =
|
||||||
self.query(None).check(self.name, None, None, self.prompt);
|
self.query(None).check(self.name, None, None, self.prompt);
|
||||||
|
|
||||||
if prompted {
|
if prompted {
|
||||||
|
@ -1362,7 +1473,7 @@ impl UnaryPermission<FfiDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||||
let (result, prompted) =
|
let (result, prompted, _) =
|
||||||
self
|
self
|
||||||
.query(None)
|
.query(None)
|
||||||
.check(self.name, None, Some("all"), self.prompt);
|
.check(self.name, None, Some("all"), self.prompt);
|
||||||
|
|
|
@ -11,6 +11,7 @@ pub const PERMISSION_EMOJI: &str = "⚠️";
|
||||||
pub enum PromptResponse {
|
pub enum PromptResponse {
|
||||||
Allow,
|
Allow,
|
||||||
Deny,
|
Deny,
|
||||||
|
AllowAll,
|
||||||
}
|
}
|
||||||
|
|
||||||
static PERMISSION_PROMPTER: Lazy<Mutex<Box<dyn PermissionPrompter>>> =
|
static PERMISSION_PROMPTER: Lazy<Mutex<Box<dyn PermissionPrompter>>> =
|
||||||
|
@ -26,11 +27,14 @@ pub fn permission_prompt(
|
||||||
message: &str,
|
message: &str,
|
||||||
flag: &str,
|
flag: &str,
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
|
is_unary: bool,
|
||||||
) -> PromptResponse {
|
) -> PromptResponse {
|
||||||
if let Some(before_callback) = MAYBE_BEFORE_PROMPT_CALLBACK.lock().as_mut() {
|
if let Some(before_callback) = MAYBE_BEFORE_PROMPT_CALLBACK.lock().as_mut() {
|
||||||
before_callback();
|
before_callback();
|
||||||
}
|
}
|
||||||
let r = PERMISSION_PROMPTER.lock().prompt(message, flag, api_name);
|
let r = PERMISSION_PROMPTER
|
||||||
|
.lock()
|
||||||
|
.prompt(message, flag, api_name, is_unary);
|
||||||
if let Some(after_callback) = MAYBE_AFTER_PROMPT_CALLBACK.lock().as_mut() {
|
if let Some(after_callback) = MAYBE_AFTER_PROMPT_CALLBACK.lock().as_mut() {
|
||||||
after_callback();
|
after_callback();
|
||||||
}
|
}
|
||||||
|
@ -53,6 +57,7 @@ pub trait PermissionPrompter: Send + Sync {
|
||||||
message: &str,
|
message: &str,
|
||||||
name: &str,
|
name: &str,
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
|
is_unary: bool,
|
||||||
) -> PromptResponse;
|
) -> PromptResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +69,7 @@ impl PermissionPrompter for TtyPrompter {
|
||||||
message: &str,
|
message: &str,
|
||||||
name: &str,
|
name: &str,
|
||||||
api_name: Option<&str>,
|
api_name: Option<&str>,
|
||||||
|
is_unary: bool,
|
||||||
) -> PromptResponse {
|
) -> PromptResponse {
|
||||||
if !atty::is(atty::Stream::Stdin) || !atty::is(atty::Stream::Stderr) {
|
if !atty::is(atty::Stream::Stdin) || !atty::is(atty::Stream::Stderr) {
|
||||||
return PromptResponse::Deny;
|
return PromptResponse::Deny;
|
||||||
|
@ -198,7 +204,11 @@ impl PermissionPrompter for TtyPrompter {
|
||||||
let _stderr_guard = std::io::stderr().lock();
|
let _stderr_guard = std::io::stderr().lock();
|
||||||
|
|
||||||
// print to stderr so that if stdout is piped this is still displayed.
|
// print to stderr so that if stdout is piped this is still displayed.
|
||||||
const OPTS: &str = "[y/n] (y = yes, allow; n = no, deny)";
|
let opts: String = if is_unary {
|
||||||
|
format!("[y/n/A] (y = yes, allow; n = no, deny; A = allow all {name} permissions)")
|
||||||
|
} else {
|
||||||
|
"[y/n] (y = yes, allow; n = no, deny)".to_string()
|
||||||
|
};
|
||||||
eprint!("┌ {PERMISSION_EMOJI} ");
|
eprint!("┌ {PERMISSION_EMOJI} ");
|
||||||
eprint!("{}", colors::bold("Deno requests "));
|
eprint!("{}", colors::bold("Deno requests "));
|
||||||
eprint!("{}", colors::bold(message));
|
eprint!("{}", colors::bold(message));
|
||||||
|
@ -209,7 +219,7 @@ impl PermissionPrompter for TtyPrompter {
|
||||||
let msg = format!("Run again with --allow-{name} to bypass this prompt.");
|
let msg = format!("Run again with --allow-{name} to bypass this prompt.");
|
||||||
eprintln!("├ {}", colors::italic(&msg));
|
eprintln!("├ {}", colors::italic(&msg));
|
||||||
eprint!("└ {}", colors::bold("Allow?"));
|
eprint!("└ {}", colors::bold("Allow?"));
|
||||||
eprint!(" {OPTS} > ");
|
eprint!(" {opts} > ");
|
||||||
let value = loop {
|
let value = loop {
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
|
@ -221,24 +231,30 @@ impl PermissionPrompter for TtyPrompter {
|
||||||
None => break PromptResponse::Deny,
|
None => break PromptResponse::Deny,
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
};
|
};
|
||||||
match ch.to_ascii_lowercase() {
|
match ch {
|
||||||
'y' => {
|
'y' | 'Y' => {
|
||||||
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
|
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
|
||||||
let msg = format!("Granted {message}.");
|
let msg = format!("Granted {message}.");
|
||||||
eprintln!("✅ {}", colors::bold(&msg));
|
eprintln!("✅ {}", colors::bold(&msg));
|
||||||
break PromptResponse::Allow;
|
break PromptResponse::Allow;
|
||||||
}
|
}
|
||||||
'n' => {
|
'n' | 'N' => {
|
||||||
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
|
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
|
||||||
let msg = format!("Denied {message}.");
|
let msg = format!("Denied {message}.");
|
||||||
eprintln!("❌ {}", colors::bold(&msg));
|
eprintln!("❌ {}", colors::bold(&msg));
|
||||||
break PromptResponse::Deny;
|
break PromptResponse::Deny;
|
||||||
}
|
}
|
||||||
|
'A' if is_unary => {
|
||||||
|
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
|
||||||
|
let msg = format!("Granted all {name} access.");
|
||||||
|
eprintln!("✅ {}", colors::bold(&msg));
|
||||||
|
break PromptResponse::AllowAll;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// If we don't get a recognized option try again.
|
// If we don't get a recognized option try again.
|
||||||
clear_n_lines(1);
|
clear_n_lines(1);
|
||||||
eprint!("└ {}", colors::bold("Unrecognized option. Allow?"));
|
eprint!("└ {}", colors::bold("Unrecognized option. Allow?"));
|
||||||
eprint!(" {OPTS} > ");
|
eprint!(" {opts} > ");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -264,6 +280,7 @@ pub mod tests {
|
||||||
_message: &str,
|
_message: &str,
|
||||||
_name: &str,
|
_name: &str,
|
||||||
_api_name: Option<&str>,
|
_api_name: Option<&str>,
|
||||||
|
_is_unary: bool,
|
||||||
) -> PromptResponse {
|
) -> PromptResponse {
|
||||||
if STUB_PROMPT_VALUE.load(Ordering::SeqCst) {
|
if STUB_PROMPT_VALUE.load(Ordering::SeqCst) {
|
||||||
PromptResponse::Allow
|
PromptResponse::Allow
|
||||||
|
|
Loading…
Add table
Reference in a new issue