mirror of
https://github.com/denoland/deno.git
synced 2025-01-14 10:01:51 -05:00
fix: worker environment permissions should accept an array (#12250)
This commit is contained in:
parent
83169dc314
commit
b20a779f7b
6 changed files with 123 additions and 54 deletions
14
cli/tests/testdata/workers/env_read_check_worker.js
vendored
Normal file
14
cli/tests/testdata/workers/env_read_check_worker.js
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
onmessage = async ({ data }) => {
|
||||||
|
const permissions = [];
|
||||||
|
for (const name of data.names) {
|
||||||
|
const { state } = await Deno.permissions.query({
|
||||||
|
name: "env",
|
||||||
|
variable: name,
|
||||||
|
});
|
||||||
|
permissions.push(state === "granted");
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage({
|
||||||
|
permissions,
|
||||||
|
});
|
||||||
|
};
|
43
cli/tests/unit/worker_permissions_test.ts
Normal file
43
cli/tests/unit/worker_permissions_test.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
import { assertEquals, deferred, unitTest } from "./test_util.ts";
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ permissions: { env: true, read: true } },
|
||||||
|
async function workerEnvArrayPermissions() {
|
||||||
|
const promise = deferred<boolean[]>();
|
||||||
|
|
||||||
|
const worker = new Worker(
|
||||||
|
new URL(
|
||||||
|
"../testdata/workers/env_read_check_worker.js",
|
||||||
|
import.meta.url,
|
||||||
|
).href,
|
||||||
|
{
|
||||||
|
type: "module",
|
||||||
|
deno: {
|
||||||
|
namespace: true,
|
||||||
|
permissions: {
|
||||||
|
env: ["test", "OTHER"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
worker.onmessage = ({ data }) => {
|
||||||
|
promise.resolve(data.permissions);
|
||||||
|
};
|
||||||
|
|
||||||
|
worker.postMessage({
|
||||||
|
names: ["test", "TEST", "asdf", "OTHER"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const permissions = await promise;
|
||||||
|
worker.terminate();
|
||||||
|
|
||||||
|
if (Deno.build.os === "windows") {
|
||||||
|
// windows ignores case
|
||||||
|
assertEquals(permissions, [true, true, false, true]);
|
||||||
|
} else {
|
||||||
|
assertEquals(permissions, [true, false, false, true]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
|
@ -5,7 +5,7 @@ unitTest(
|
||||||
{ permissions: { read: true } },
|
{ permissions: { read: true } },
|
||||||
function utimeSyncFileSuccess() {
|
function utimeSyncFileSuccess() {
|
||||||
const w = new Worker(
|
const w = new Worker(
|
||||||
new URL("../workers/worker_types.ts", import.meta.url).href,
|
new URL("../testdata/workers/worker_types.ts", import.meta.url).href,
|
||||||
{ type: "module" },
|
{ type: "module" },
|
||||||
);
|
);
|
||||||
assert(w);
|
assert(w);
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {"inherit" | boolean} value
|
||||||
* @param {string} permission
|
* @param {string} permission
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
|
@ -127,7 +128,7 @@
|
||||||
write = "inherit",
|
write = "inherit",
|
||||||
}) {
|
}) {
|
||||||
return {
|
return {
|
||||||
env: parseUnitPermission(env, "env"),
|
env: parseArrayPermission(env, "env"),
|
||||||
hrtime: parseUnitPermission(hrtime, "hrtime"),
|
hrtime: parseUnitPermission(hrtime, "hrtime"),
|
||||||
net: parseArrayPermission(net, "net"),
|
net: parseArrayPermission(net, "net"),
|
||||||
ffi: parseUnitPermission(ffi, "ffi"),
|
ffi: parseUnitPermission(ffi, "ffi"),
|
||||||
|
|
|
@ -223,7 +223,10 @@ fn merge_env_permission(
|
||||||
) -> Result<UnaryPermission<EnvDescriptor>, AnyError> {
|
) -> Result<UnaryPermission<EnvDescriptor>, AnyError> {
|
||||||
if let Some(worker) = worker {
|
if let Some(worker) = worker {
|
||||||
if (worker.global_state < main.global_state)
|
if (worker.global_state < main.global_state)
|
||||||
|| !worker.granted_list.iter().all(|x| main.check(&x.0).is_ok())
|
|| !worker
|
||||||
|
.granted_list
|
||||||
|
.iter()
|
||||||
|
.all(|x| main.check(x.as_ref()).is_ok())
|
||||||
{
|
{
|
||||||
return Err(custom_error(
|
return Err(custom_error(
|
||||||
"PermissionDenied",
|
"PermissionDenied",
|
||||||
|
@ -448,11 +451,7 @@ where
|
||||||
|
|
||||||
Ok(Some(UnaryPermission::<EnvDescriptor> {
|
Ok(Some(UnaryPermission::<EnvDescriptor> {
|
||||||
global_state: value.global_state,
|
global_state: value.global_state,
|
||||||
granted_list: value
|
granted_list: value.paths.into_iter().map(EnvDescriptor::new).collect(),
|
||||||
.paths
|
|
||||||
.into_iter()
|
|
||||||
.map(|env| EnvDescriptor(env.to_uppercase()))
|
|
||||||
.collect(),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,26 +159,48 @@ impl UnitPermission {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
/// A normalized environment variable name. On Windows this will
|
||||||
|
/// be uppercase and on other platforms it will stay as-is.
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
|
||||||
|
struct EnvVarName {
|
||||||
|
inner: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnvVarName {
|
||||||
|
pub fn new(env: impl AsRef<str>) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: if cfg!(windows) {
|
||||||
|
env.as_ref().to_uppercase()
|
||||||
|
} else {
|
||||||
|
env.as_ref().to_string()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for EnvVarName {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
self.inner.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
pub struct UnaryPermission<T: Eq + Hash> {
|
pub struct UnaryPermission<T: Eq + Hash> {
|
||||||
#[serde(skip)]
|
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
#[serde(skip)]
|
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
pub global_state: PermissionState,
|
pub global_state: PermissionState,
|
||||||
pub granted_list: HashSet<T>,
|
pub granted_list: HashSet<T>,
|
||||||
pub denied_list: HashSet<T>,
|
pub denied_list: HashSet<T>,
|
||||||
#[serde(skip)]
|
|
||||||
pub prompt: bool,
|
pub prompt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
|
||||||
pub struct ReadDescriptor(pub PathBuf);
|
pub struct ReadDescriptor(pub PathBuf);
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
|
||||||
pub struct WriteDescriptor(pub PathBuf);
|
pub struct WriteDescriptor(pub PathBuf);
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
|
||||||
pub struct NetDescriptor(pub String, pub Option<u16>);
|
pub struct NetDescriptor(pub String, pub Option<u16>);
|
||||||
|
|
||||||
impl NetDescriptor {
|
impl NetDescriptor {
|
||||||
|
@ -203,13 +225,25 @@ impl fmt::Display for NetDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
|
||||||
pub struct EnvDescriptor(pub String);
|
pub struct EnvDescriptor(EnvVarName);
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
|
impl EnvDescriptor {
|
||||||
|
pub fn new(env: impl AsRef<str>) -> Self {
|
||||||
|
Self(EnvVarName::new(env))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for EnvDescriptor {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
|
||||||
pub struct RunDescriptor(pub String);
|
pub struct RunDescriptor(pub String);
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default, Deserialize)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
|
||||||
pub struct FfiDescriptor(pub String);
|
pub struct FfiDescriptor(pub String);
|
||||||
|
|
||||||
impl UnaryPermission<ReadDescriptor> {
|
impl UnaryPermission<ReadDescriptor> {
|
||||||
|
@ -585,21 +619,18 @@ impl UnaryPermission<NetDescriptor> {
|
||||||
|
|
||||||
impl UnaryPermission<EnvDescriptor> {
|
impl UnaryPermission<EnvDescriptor> {
|
||||||
pub fn query(&self, env: Option<&str>) -> PermissionState {
|
pub fn query(&self, env: Option<&str>) -> PermissionState {
|
||||||
#[cfg(windows)]
|
let env = env.map(EnvVarName::new);
|
||||||
let env = env.map(|env| env.to_uppercase());
|
|
||||||
#[cfg(windows)]
|
|
||||||
let env = env.as_deref();
|
|
||||||
if self.global_state == PermissionState::Denied
|
if self.global_state == PermissionState::Denied
|
||||||
&& match env {
|
&& match env.as_ref() {
|
||||||
None => true,
|
None => true,
|
||||||
Some(env) => self.denied_list.iter().any(|env_| env_.0 == env),
|
Some(env) => self.denied_list.iter().any(|env_| &env_.0 == env),
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PermissionState::Denied
|
PermissionState::Denied
|
||||||
} else if self.global_state == PermissionState::Granted
|
} else if self.global_state == PermissionState::Granted
|
||||||
|| match env {
|
|| match env.as_ref() {
|
||||||
None => false,
|
None => false,
|
||||||
Some(env) => self.granted_list.iter().any(|env_| env_.0 == env),
|
Some(env) => self.granted_list.iter().any(|env_| &env_.0 == env),
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
|
@ -610,23 +641,18 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
|
|
||||||
pub fn request(&mut self, env: Option<&str>) -> PermissionState {
|
pub fn request(&mut self, env: Option<&str>) -> PermissionState {
|
||||||
if let Some(env) = env {
|
if let Some(env) = env {
|
||||||
let env = if cfg!(windows) {
|
let state = self.query(Some(env));
|
||||||
env.to_uppercase()
|
|
||||||
} else {
|
|
||||||
env.to_string()
|
|
||||||
};
|
|
||||||
let state = self.query(Some(&env));
|
|
||||||
if state == PermissionState::Prompt {
|
if state == PermissionState::Prompt {
|
||||||
if permission_prompt(&format!("env access to \"{}\"", env)) {
|
if permission_prompt(&format!("env access to \"{}\"", env)) {
|
||||||
self.granted_list.insert(EnvDescriptor(env));
|
self.granted_list.insert(EnvDescriptor::new(env));
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(EnvDescriptor(env));
|
self.denied_list.insert(EnvDescriptor::new(env));
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
PermissionState::Denied
|
PermissionState::Denied
|
||||||
}
|
}
|
||||||
} else if state == PermissionState::Granted {
|
} else if state == PermissionState::Granted {
|
||||||
self.granted_list.insert(EnvDescriptor(env));
|
self.granted_list.insert(EnvDescriptor::new(env));
|
||||||
PermissionState::Granted
|
PermissionState::Granted
|
||||||
} else {
|
} else {
|
||||||
state
|
state
|
||||||
|
@ -650,9 +676,7 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
|
|
||||||
pub fn revoke(&mut self, env: Option<&str>) -> PermissionState {
|
pub fn revoke(&mut self, env: Option<&str>) -> PermissionState {
|
||||||
if let Some(env) = env {
|
if let Some(env) = env {
|
||||||
#[cfg(windows)]
|
self.granted_list.remove(&EnvDescriptor::new(env));
|
||||||
let env = env.to_uppercase();
|
|
||||||
self.granted_list.remove(&EnvDescriptor(env.to_string()));
|
|
||||||
} else {
|
} else {
|
||||||
self.granted_list.clear();
|
self.granted_list.clear();
|
||||||
}
|
}
|
||||||
|
@ -663,8 +687,6 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&mut self, env: &str) -> Result<(), AnyError> {
|
pub fn check(&mut self, env: &str) -> Result<(), AnyError> {
|
||||||
#[cfg(windows)]
|
|
||||||
let env = &env.to_uppercase();
|
|
||||||
let (result, prompted) = self.query(Some(env)).check(
|
let (result, prompted) = self.query(Some(env)).check(
|
||||||
self.name,
|
self.name,
|
||||||
Some(&format!("\"{}\"", env)),
|
Some(&format!("\"{}\"", env)),
|
||||||
|
@ -672,9 +694,9 @@ impl UnaryPermission<EnvDescriptor> {
|
||||||
);
|
);
|
||||||
if prompted {
|
if prompted {
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
self.granted_list.insert(EnvDescriptor(env.to_string()));
|
self.granted_list.insert(EnvDescriptor::new(env));
|
||||||
} else {
|
} else {
|
||||||
self.denied_list.insert(EnvDescriptor(env.to_string()));
|
self.denied_list.insert(EnvDescriptor::new(env));
|
||||||
self.global_state = PermissionState::Denied;
|
self.global_state = PermissionState::Denied;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -976,17 +998,7 @@ impl Permissions {
|
||||||
global_state: global_state_from_option(state),
|
global_state: global_state_from_option(state),
|
||||||
granted_list: state
|
granted_list: state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|v| {
|
.map(|v| v.iter().map(EnvDescriptor::new).collect())
|
||||||
v.iter()
|
|
||||||
.map(|x| {
|
|
||||||
EnvDescriptor(if cfg!(windows) {
|
|
||||||
x.to_uppercase()
|
|
||||||
} else {
|
|
||||||
x.clone()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.unwrap_or_else(HashSet::new),
|
.unwrap_or_else(HashSet::new),
|
||||||
denied_list: Default::default(),
|
denied_list: Default::default(),
|
||||||
prompt,
|
prompt,
|
||||||
|
|
Loading…
Reference in a new issue