summaryrefslogtreecommitdiff
path: root/runtime/permissions
diff options
context:
space:
mode:
authorAsher Gomez <ashersaupingomez@gmail.com>2023-02-23 09:02:10 +1100
committerGitHub <noreply@github.com>2023-02-22 23:02:10 +0100
commitc18e0d1d37878bb4441f7f8d339cc23ac8e68448 (patch)
tree8b4007aec8cef00fc605c56e6001b2d92f10987a /runtime/permissions
parent5fcbdd62285140353edbb28e67f7d72e3317e96e (diff)
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.
Diffstat (limited to 'runtime/permissions')
-rw-r--r--runtime/permissions/mod.rs399
-rw-r--r--runtime/permissions/prompter.rs31
2 files changed, 279 insertions, 151 deletions
diff --git a/runtime/permissions/mod.rs b/runtime/permissions/mod.rs
index 298146312..035c39304 100644
--- a/runtime/permissions/mod.rs
+++ b/runtime/permissions/mod.rs
@@ -90,7 +90,7 @@ impl PermissionState {
api_name: Option<&str>,
info: Option<&str>,
prompt: bool,
- ) -> (Result<(), AnyError>, bool) {
+ ) -> (Result<(), AnyError>, bool, bool) {
self.check2(name, api_name, || info.map(|s| s.to_string()), prompt)
}
@@ -101,11 +101,11 @@ impl PermissionState {
api_name: Option<&str>,
info: impl Fn() -> Option<String>,
prompt: bool,
- ) -> (Result<(), AnyError>, bool) {
+ ) -> (Result<(), AnyError>, bool, bool) {
match self {
PermissionState::Granted => {
Self::log_perm_access(name, info);
- (Ok(()), false)
+ (Ok(()), false, false)
}
PermissionState::Prompt if prompt => {
let msg = format!(
@@ -113,14 +113,19 @@ impl PermissionState {
name,
info().map_or(String::new(), |info| { format!(" to {info}") }),
);
- if PromptResponse::Allow == permission_prompt(&msg, name, api_name) {
- Self::log_perm_access(name, info);
- (Ok(()), true)
- } else {
- (Err(Self::error(name, info)), true)
+ match permission_prompt(&msg, name, api_name, true) {
+ PromptResponse::Allow => {
+ Self::log_perm_access(name, info);
+ (Ok(()), true, false)
+ }
+ 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),
self.name,
Some("Deno.permissions.query()"),
+ false,
)
{
self.state = PermissionState::Granted;
@@ -179,7 +185,7 @@ impl UnitPermission {
}
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);
if prompted {
if result.is_ok() {
@@ -357,19 +363,26 @@ impl UnaryPermission<ReadDescriptor> {
let (resolved_path, display_path) = resolved_and_display_path(path);
let state = self.query(Some(&resolved_path));
if state == PermissionState::Prompt {
- if PromptResponse::Allow
- == permission_prompt(
- &format!("read access to \"{}\"", display_path.display()),
- self.name,
- Some("Deno.permissions.query()"),
- )
- {
- self.granted_list.insert(ReadDescriptor(resolved_path));
- PermissionState::Granted
- } else {
- self.denied_list.insert(ReadDescriptor(resolved_path));
- self.global_state = PermissionState::Denied;
- PermissionState::Denied
+ match permission_prompt(
+ &format!("read access to \"{}\"", display_path.display()),
+ self.name,
+ Some("Deno.permissions.query()"),
+ true,
+ ) {
+ PromptResponse::Allow => {
+ self.granted_list.insert(ReadDescriptor(resolved_path));
+ PermissionState::Granted
+ }
+ PromptResponse::Deny => {
+ self.denied_list.insert(ReadDescriptor(resolved_path));
+ 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 {
self.granted_list.insert(ReadDescriptor(resolved_path));
@@ -385,6 +398,7 @@ impl UnaryPermission<ReadDescriptor> {
"read access",
self.name,
Some("Deno.permissions.query()"),
+ true,
)
{
self.granted_list.clear();
@@ -421,7 +435,7 @@ impl UnaryPermission<ReadDescriptor> {
path: &Path,
api_name: Option<&str>,
) -> Result<(), AnyError> {
- let (result, prompted) = self.query(Some(path)).check2(
+ let (result, prompted, is_allow_all) = self.query(Some(path)).check2(
self.name,
api_name,
|| Some(format!("\"{}\"", path.to_path_buf().display())),
@@ -430,7 +444,12 @@ impl UnaryPermission<ReadDescriptor> {
if prompted {
let resolved_path = resolve_from_cwd(path)?;
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 {
self.denied_list.insert(ReadDescriptor(resolved_path));
self.global_state = PermissionState::Denied;
@@ -448,25 +467,33 @@ impl UnaryPermission<ReadDescriptor> {
api_name: &str,
) -> Result<(), AnyError> {
let resolved_path = resolve_from_cwd(path)?;
- let (result, prompted) = self.query(Some(&resolved_path)).check(
- self.name,
- Some(api_name),
- Some(&format!("<{display}>")),
- self.prompt,
- );
+ let (result, prompted, is_allow_all) =
+ self.query(Some(&resolved_path)).check(
+ self.name,
+ Some(api_name),
+ Some(&format!("<{display}>")),
+ self.prompt,
+ );
if prompted {
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 {
- self.denied_list.insert(ReadDescriptor(resolved_path));
self.global_state = PermissionState::Denied;
+ if !is_allow_all {
+ self.denied_list.insert(ReadDescriptor(resolved_path));
+ }
}
}
result
}
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
- let (result, prompted) =
+ let (result, prompted, _) =
self
.query(None)
.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 state = self.query(Some(&resolved_path));
if state == PermissionState::Prompt {
- if PromptResponse::Allow
- == permission_prompt(
- &format!("write access to \"{}\"", display_path.display()),
- self.name,
- Some("Deno.permissions.query()"),
- )
- {
- self.granted_list.insert(WriteDescriptor(resolved_path));
- PermissionState::Granted
- } else {
- self.denied_list.insert(WriteDescriptor(resolved_path));
- self.global_state = PermissionState::Denied;
- PermissionState::Denied
+ match permission_prompt(
+ &format!("write access to \"{}\"", display_path.display()),
+ self.name,
+ Some("Deno.permissions.query()"),
+ true,
+ ) {
+ PromptResponse::Allow => {
+ self.granted_list.insert(WriteDescriptor(resolved_path));
+ PermissionState::Granted
+ }
+ PromptResponse::Deny => {
+ self.denied_list.insert(WriteDescriptor(resolved_path));
+ 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 {
self.granted_list.insert(WriteDescriptor(resolved_path));
@@ -558,6 +592,7 @@ impl UnaryPermission<WriteDescriptor> {
"write access",
self.name,
Some("Deno.permissions.query()"),
+ true,
)
{
self.granted_list.clear();
@@ -594,7 +629,7 @@ impl UnaryPermission<WriteDescriptor> {
path: &Path,
api_name: Option<&str>,
) -> Result<(), AnyError> {
- let (result, prompted) = self.query(Some(path)).check2(
+ let (result, prompted, is_allow_all) = self.query(Some(path)).check2(
self.name,
api_name,
|| Some(format!("\"{}\"", path.to_path_buf().display())),
@@ -603,7 +638,12 @@ impl UnaryPermission<WriteDescriptor> {
if prompted {
let resolved_path = resolve_from_cwd(path)?;
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 {
self.denied_list.insert(WriteDescriptor(resolved_path));
self.global_state = PermissionState::Denied;
@@ -613,7 +653,7 @@ impl UnaryPermission<WriteDescriptor> {
}
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
- let (result, prompted) =
+ let (result, prompted, _) =
self
.query(None)
.check(self.name, api_name, Some("all"), self.prompt);
@@ -685,19 +725,26 @@ impl UnaryPermission<NetDescriptor> {
let state = self.query(Some(host));
let host = NetDescriptor::new(&host);
if state == PermissionState::Prompt {
- if PromptResponse::Allow
- == permission_prompt(
- &format!("network access to \"{host}\""),
- self.name,
- Some("Deno.permissions.query()"),
- )
- {
- self.granted_list.insert(host);
- PermissionState::Granted
- } else {
- self.denied_list.insert(host);
- self.global_state = PermissionState::Denied;
- PermissionState::Denied
+ match permission_prompt(
+ &format!("network access to \"{host}\""),
+ self.name,
+ Some("Deno.permissions.query()"),
+ true,
+ ) {
+ PromptResponse::Allow => {
+ self.granted_list.insert(host);
+ PermissionState::Granted
+ }
+ PromptResponse::Deny => {
+ self.denied_list.insert(host);
+ 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 {
self.granted_list.insert(host);
@@ -713,6 +760,7 @@ impl UnaryPermission<NetDescriptor> {
"network access",
self.name,
Some("Deno.permissions.query()"),
+ true,
)
{
self.granted_list.clear();
@@ -756,7 +804,7 @@ impl UnaryPermission<NetDescriptor> {
api_name: Option<&str>,
) -> Result<(), AnyError> {
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,
api_name,
Some(&format!("\"{new_host}\"")),
@@ -764,7 +812,12 @@ impl UnaryPermission<NetDescriptor> {
);
if prompted {
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 {
self.denied_list.insert(new_host);
self.global_state = PermissionState::Denied;
@@ -787,7 +840,7 @@ impl UnaryPermission<NetDescriptor> {
Some(port) => format!("{hostname}:{port}"),
};
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,
api_name,
Some(&format!("\"{display_host}\"")),
@@ -795,7 +848,12 @@ impl UnaryPermission<NetDescriptor> {
);
if prompted {
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 {
self.denied_list.insert(NetDescriptor::new(&host));
self.global_state = PermissionState::Denied;
@@ -805,7 +863,7 @@ impl UnaryPermission<NetDescriptor> {
}
pub fn check_all(&mut self) -> Result<(), AnyError> {
- let (result, prompted) =
+ let (result, prompted, _) =
self
.query::<&str>(None)
.check(self.name, None, Some("all"), self.prompt);
@@ -859,19 +917,26 @@ impl UnaryPermission<EnvDescriptor> {
if let Some(env) = env {
let state = self.query(Some(env));
if state == PermissionState::Prompt {
- if PromptResponse::Allow
- == permission_prompt(
- &format!("env access to \"{env}\""),
- self.name,
- Some("Deno.permissions.query()"),
- )
- {
- self.granted_list.insert(EnvDescriptor::new(env));
- PermissionState::Granted
- } else {
- self.denied_list.insert(EnvDescriptor::new(env));
- self.global_state = PermissionState::Denied;
- PermissionState::Denied
+ match permission_prompt(
+ &format!("env access to \"{env}\""),
+ self.name,
+ Some("Deno.permissions.query()"),
+ true,
+ ) {
+ PromptResponse::Allow => {
+ self.granted_list.insert(EnvDescriptor::new(env));
+ PermissionState::Granted
+ }
+ PromptResponse::Deny => {
+ self.denied_list.insert(EnvDescriptor::new(env));
+ 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 {
self.granted_list.insert(EnvDescriptor::new(env));
@@ -887,6 +952,7 @@ impl UnaryPermission<EnvDescriptor> {
"env access",
self.name,
Some("Deno.permissions.query()"),
+ true,
)
{
self.granted_list.clear();
@@ -915,7 +981,7 @@ impl UnaryPermission<EnvDescriptor> {
}
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,
None,
Some(&format!("\"{env}\"")),
@@ -923,7 +989,12 @@ impl UnaryPermission<EnvDescriptor> {
);
if prompted {
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 {
self.denied_list.insert(EnvDescriptor::new(env));
self.global_state = PermissionState::Denied;
@@ -933,7 +1004,7 @@ impl UnaryPermission<EnvDescriptor> {
}
pub fn check_all(&mut self) -> Result<(), AnyError> {
- let (result, prompted) =
+ let (result, prompted, _) =
self
.query(None)
.check(self.name, None, Some("all"), self.prompt);
@@ -993,19 +1064,26 @@ impl UnaryPermission<SysDescriptor> {
}
if let Some(kind) = kind {
let desc = SysDescriptor(kind.to_string());
- if PromptResponse::Allow
- == permission_prompt(
- &format!("sys access to \"{kind}\""),
- self.name,
- Some("Deno.permissions.query()"),
- )
- {
- self.granted_list.insert(desc);
- PermissionState::Granted
- } else {
- self.denied_list.insert(desc);
- self.global_state = PermissionState::Denied;
- PermissionState::Denied
+ match permission_prompt(
+ &format!("sys access to \"{kind}\""),
+ self.name,
+ Some("Deno.permissions.query()"),
+ true,
+ ) {
+ PromptResponse::Allow => {
+ self.granted_list.insert(desc);
+ PermissionState::Granted
+ }
+ PromptResponse::Deny => {
+ self.denied_list.insert(desc);
+ self.global_state = PermissionState::Denied;
+ PermissionState::Denied
+ }
+ PromptResponse::AllowAll => {
+ self.granted_list.clear();
+ self.global_state = PermissionState::Granted;
+ PermissionState::Granted
+ }
}
} else {
if PromptResponse::Allow
@@ -1013,6 +1091,7 @@ impl UnaryPermission<SysDescriptor> {
"sys access",
self.name,
Some("Deno.permissions.query()"),
+ true,
)
{
self.global_state = PermissionState::Granted;
@@ -1041,7 +1120,7 @@ impl UnaryPermission<SysDescriptor> {
kind: &str,
api_name: Option<&str>,
) -> Result<(), AnyError> {
- let (result, prompted) = self.query(Some(kind)).check(
+ let (result, prompted, is_allow_all) = self.query(Some(kind)).check(
self.name,
api_name,
Some(&format!("\"{kind}\"")),
@@ -1049,7 +1128,12 @@ impl UnaryPermission<SysDescriptor> {
);
if prompted {
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 {
self.denied_list.insert(SysDescriptor(kind.to_string()));
self.global_state = PermissionState::Denied;
@@ -1059,7 +1143,7 @@ impl UnaryPermission<SysDescriptor> {
}
pub fn check_all(&mut self) -> Result<(), AnyError> {
- let (result, prompted) =
+ let (result, prompted, _is_allow_all) =
self
.query(None)
.check(self.name, None, Some("all"), self.prompt);
@@ -1116,23 +1200,30 @@ impl UnaryPermission<RunDescriptor> {
if let Some(cmd) = cmd {
let state = self.query(Some(cmd));
if state == PermissionState::Prompt {
- if PromptResponse::Allow
- == permission_prompt(
- &format!("run access to \"{cmd}\""),
- self.name,
- Some("Deno.permissions.query()"),
- )
- {
- self
- .granted_list
- .insert(RunDescriptor::from_str(cmd).unwrap());
- PermissionState::Granted
- } else {
- self
- .denied_list
- .insert(RunDescriptor::from_str(cmd).unwrap());
- self.global_state = PermissionState::Denied;
- PermissionState::Denied
+ match permission_prompt(
+ &format!("run access to \"{cmd}\""),
+ self.name,
+ Some("Deno.permissions.query()"),
+ true,
+ ) {
+ PromptResponse::Allow => {
+ self
+ .granted_list
+ .insert(RunDescriptor::from_str(cmd).unwrap());
+ PermissionState::Granted
+ }
+ PromptResponse::Deny => {
+ self
+ .denied_list
+ .insert(RunDescriptor::from_str(cmd).unwrap());
+ 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 {
self
@@ -1150,6 +1241,7 @@ impl UnaryPermission<RunDescriptor> {
"run access",
self.name,
Some("Deno.permissions.query()"),
+ true,
)
{
self.granted_list.clear();
@@ -1184,7 +1276,7 @@ impl UnaryPermission<RunDescriptor> {
cmd: &str,
api_name: Option<&str>,
) -> Result<(), AnyError> {
- let (result, prompted) = self.query(Some(cmd)).check(
+ let (result, prompted, is_allow_all) = self.query(Some(cmd)).check(
self.name,
api_name,
Some(&format!("\"{cmd}\"")),
@@ -1192,9 +1284,14 @@ impl UnaryPermission<RunDescriptor> {
);
if prompted {
if result.is_ok() {
- self
- .granted_list
- .insert(RunDescriptor::from_str(cmd).unwrap());
+ if is_allow_all {
+ self.granted_list.clear();
+ self.global_state = PermissionState::Granted;
+ } else {
+ self
+ .granted_list
+ .insert(RunDescriptor::from_str(cmd).unwrap());
+ }
} else {
self
.denied_list
@@ -1206,7 +1303,7 @@ impl UnaryPermission<RunDescriptor> {
}
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
- let (result, prompted) =
+ let (result, prompted, _) =
self
.query(None)
.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 state = self.query(Some(&resolved_path));
if state == PermissionState::Prompt {
- if PromptResponse::Allow
- == permission_prompt(
- &format!("ffi access to \"{}\"", display_path.display()),
- self.name,
- Some("Deno.permissions.query()"),
- )
- {
- self.granted_list.insert(FfiDescriptor(resolved_path));
- PermissionState::Granted
- } else {
- self.denied_list.insert(FfiDescriptor(resolved_path));
- self.global_state = PermissionState::Denied;
- PermissionState::Denied
+ match permission_prompt(
+ &format!("ffi access to \"{}\"", display_path.display()),
+ self.name,
+ Some("Deno.permissions.query()"),
+ true,
+ ) {
+ PromptResponse::Allow => {
+ self.granted_list.insert(FfiDescriptor(resolved_path));
+ PermissionState::Granted
+ }
+ PromptResponse::Deny => {
+ self.denied_list.insert(FfiDescriptor(resolved_path));
+ 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 {
self.granted_list.insert(FfiDescriptor(resolved_path));
@@ -1295,6 +1399,7 @@ impl UnaryPermission<FfiDescriptor> {
"ffi access",
self.name,
Some("Deno.permissions.query()"),
+ true,
)
{
self.granted_list.clear();
@@ -1328,16 +1433,22 @@ impl UnaryPermission<FfiDescriptor> {
pub fn check(&mut self, path: Option<&Path>) -> Result<(), AnyError> {
if let Some(path) = path {
let (resolved_path, display_path) = resolved_and_display_path(path);
- let (result, prompted) = self.query(Some(&resolved_path)).check(
- self.name,
- None,
- Some(&format!("\"{}\"", display_path.display())),
- self.prompt,
- );
+ let (result, prompted, is_allow_all) =
+ self.query(Some(&resolved_path)).check(
+ self.name,
+ None,
+ Some(&format!("\"{}\"", display_path.display())),
+ self.prompt,
+ );
if prompted {
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 {
self.denied_list.insert(FfiDescriptor(resolved_path));
self.global_state = PermissionState::Denied;
@@ -1346,7 +1457,7 @@ impl UnaryPermission<FfiDescriptor> {
result
} else {
- let (result, prompted) =
+ let (result, prompted, _) =
self.query(None).check(self.name, None, None, self.prompt);
if prompted {
@@ -1362,7 +1473,7 @@ impl UnaryPermission<FfiDescriptor> {
}
pub fn check_all(&mut self) -> Result<(), AnyError> {
- let (result, prompted) =
+ let (result, prompted, _) =
self
.query(None)
.check(self.name, None, Some("all"), self.prompt);
diff --git a/runtime/permissions/prompter.rs b/runtime/permissions/prompter.rs
index c33483645..d148b485e 100644
--- a/runtime/permissions/prompter.rs
+++ b/runtime/permissions/prompter.rs
@@ -11,6 +11,7 @@ pub const PERMISSION_EMOJI: &str = "⚠️";
pub enum PromptResponse {
Allow,
Deny,
+ AllowAll,
}
static PERMISSION_PROMPTER: Lazy<Mutex<Box<dyn PermissionPrompter>>> =
@@ -26,11 +27,14 @@ pub fn permission_prompt(
message: &str,
flag: &str,
api_name: Option<&str>,
+ is_unary: bool,
) -> PromptResponse {
if let Some(before_callback) = MAYBE_BEFORE_PROMPT_CALLBACK.lock().as_mut() {
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() {
after_callback();
}
@@ -53,6 +57,7 @@ pub trait PermissionPrompter: Send + Sync {
message: &str,
name: &str,
api_name: Option<&str>,
+ is_unary: bool,
) -> PromptResponse;
}
@@ -64,6 +69,7 @@ impl PermissionPrompter for TtyPrompter {
message: &str,
name: &str,
api_name: Option<&str>,
+ is_unary: bool,
) -> PromptResponse {
if !atty::is(atty::Stream::Stdin) || !atty::is(atty::Stream::Stderr) {
return PromptResponse::Deny;
@@ -198,7 +204,11 @@ impl PermissionPrompter for TtyPrompter {
let _stderr_guard = std::io::stderr().lock();
// 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!("{}", colors::bold("Deno requests "));
eprint!("{}", colors::bold(message));
@@ -209,7 +219,7 @@ impl PermissionPrompter for TtyPrompter {
let msg = format!("Run again with --allow-{name} to bypass this prompt.");
eprintln!("├ {}", colors::italic(&msg));
eprint!("└ {}", colors::bold("Allow?"));
- eprint!(" {OPTS} > ");
+ eprint!(" {opts} > ");
let value = loop {
let mut input = String::new();
let stdin = std::io::stdin();
@@ -221,24 +231,30 @@ impl PermissionPrompter for TtyPrompter {
None => break PromptResponse::Deny,
Some(v) => v,
};
- match ch.to_ascii_lowercase() {
- 'y' => {
+ match ch {
+ 'y' | 'Y' => {
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
let msg = format!("Granted {message}.");
eprintln!("✅ {}", colors::bold(&msg));
break PromptResponse::Allow;
}
- 'n' => {
+ 'n' | 'N' => {
clear_n_lines(if api_name.is_some() { 4 } else { 3 });
let msg = format!("Denied {message}.");
eprintln!("❌ {}", colors::bold(&msg));
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.
clear_n_lines(1);
eprint!("└ {}", colors::bold("Unrecognized option. Allow?"));
- eprint!(" {OPTS} > ");
+ eprint!(" {opts} > ");
}
};
};
@@ -264,6 +280,7 @@ pub mod tests {
_message: &str,
_name: &str,
_api_name: Option<&str>,
+ _is_unary: bool,
) -> PromptResponse {
if STUB_PROMPT_VALUE.load(Ordering::SeqCst) {
PromptResponse::Allow