mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(runtime/ops/worker_host): move permission arg parsing to Rust (#12297)
This commit is contained in:
parent
43a63530ac
commit
7a22df9b76
19 changed files with 1201 additions and 823 deletions
1
cli/dts/lib.deno.ns.d.ts
vendored
1
cli/dts/lib.deno.ns.d.ts
vendored
|
@ -2178,6 +2178,7 @@ declare namespace Deno {
|
|||
|
||||
export interface FfiPermissionDescriptor {
|
||||
name: "ffi";
|
||||
path?: string | URL;
|
||||
}
|
||||
|
||||
export interface HrtimePermissionDescriptor {
|
||||
|
|
6
cli/dts/lib.deno.unstable.d.ts
vendored
6
cli/dts/lib.deno.unstable.d.ts
vendored
|
@ -910,10 +910,12 @@ declare namespace Deno {
|
|||
* If set to `"inherit"`, the current `ffi` permission will be inherited.
|
||||
* If set to `true`, the global `ffi` permission will be requested.
|
||||
* If set to `false`, the global `ffi` permission will be revoked.
|
||||
* If set to `Array<string | URL>`, the `ffi` permission will be requested with the
|
||||
* specified file paths.
|
||||
*
|
||||
* Defaults to "inherit".
|
||||
*/
|
||||
ffi?: "inherit" | boolean;
|
||||
ffi?: "inherit" | boolean | Array<string | URL>;
|
||||
|
||||
/** Specifies if the `read` permission should be requested or revoked.
|
||||
* If set to `"inherit"`, the current `read` permission will be inherited.
|
||||
|
@ -1237,7 +1239,7 @@ declare interface WorkerOptions {
|
|||
* For example: `["https://deno.land", "localhost:8080"]`.
|
||||
*/
|
||||
net?: "inherit" | boolean | string[];
|
||||
ffi?: "inherit" | boolean;
|
||||
ffi?: "inherit" | boolean | Array<string | URL>;
|
||||
read?: "inherit" | boolean | Array<string | URL>;
|
||||
run?: "inherit" | boolean | Array<string | URL>;
|
||||
write?: "inherit" | boolean | Array<string | URL>;
|
||||
|
|
|
@ -198,7 +198,7 @@ pub struct Flags {
|
|||
pub allow_env: Option<Vec<String>>,
|
||||
pub allow_hrtime: bool,
|
||||
pub allow_net: Option<Vec<String>>,
|
||||
pub allow_ffi: Option<Vec<String>>,
|
||||
pub allow_ffi: Option<Vec<PathBuf>>,
|
||||
pub allow_read: Option<Vec<PathBuf>>,
|
||||
pub allow_run: Option<Vec<String>>,
|
||||
pub allow_write: Option<Vec<PathBuf>>,
|
||||
|
@ -324,7 +324,7 @@ impl Flags {
|
|||
args.push("--allow-ffi".to_string());
|
||||
}
|
||||
Some(ffi_allowlist) => {
|
||||
let s = format!("--allow-ffi={}", ffi_allowlist.join(","));
|
||||
let s = format!("--allow-ffi={}", join_paths(ffi_allowlist, ","));
|
||||
args.push(s);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -2202,7 +2202,7 @@ fn permission_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
|||
}
|
||||
|
||||
if let Some(ffi_wl) = matches.values_of("allow-ffi") {
|
||||
let ffi_allowlist: Vec<String> = ffi_wl.map(ToString::to_string).collect();
|
||||
let ffi_allowlist: Vec<PathBuf> = ffi_wl.map(PathBuf::from).collect();
|
||||
flags.allow_ffi = Some(ffi_allowlist);
|
||||
debug!("ffi allowlist: {:#?}", &flags.allow_ffi);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ use deno_core::error::AnyError;
|
|||
use deno_core::JsRuntime;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_runtime::ops::worker_host::create_worker_permissions;
|
||||
use deno_runtime::ops::worker_host::PermissionsArg;
|
||||
use deno_runtime::permissions::create_child_permissions;
|
||||
use deno_runtime::permissions::ChildPermissionsArg;
|
||||
use deno_runtime::permissions::Permissions;
|
||||
use std::sync::mpsc::Sender;
|
||||
use uuid::Uuid;
|
||||
|
@ -26,15 +26,15 @@ struct PermissionsHolder(Uuid, Permissions);
|
|||
|
||||
pub fn op_pledge_test_permissions(
|
||||
state: &mut OpState,
|
||||
args: PermissionsArg,
|
||||
args: ChildPermissionsArg,
|
||||
_: (),
|
||||
) -> Result<Uuid, AnyError> {
|
||||
deno_runtime::ops::check_unstable(state, "Deno.test.permissions");
|
||||
|
||||
let token = Uuid::new_v4();
|
||||
let parent_permissions = state.borrow::<Permissions>().clone();
|
||||
let worker_permissions =
|
||||
create_worker_permissions(parent_permissions.clone(), args)?;
|
||||
let parent_permissions = state.borrow_mut::<Permissions>();
|
||||
let worker_permissions = create_child_permissions(parent_permissions, args)?;
|
||||
let parent_permissions = parent_permissions.clone();
|
||||
|
||||
state.put::<PermissionsHolder>(PermissionsHolder(token, parent_permissions));
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use crate::itest;
|
||||
|
||||
itest!(workers {
|
||||
args: "test --reload --location http://127.0.0.1:4545/ --allow-net --allow-read --unstable workers/test.ts",
|
||||
args: "test --reload --location http://127.0.0.1:4545/ -A --unstable workers/test.ts",
|
||||
output: "workers/test.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
|
2
cli/tests/testdata/test/allow_all.ts
vendored
2
cli/tests/testdata/test/allow_all.ts
vendored
|
@ -18,7 +18,7 @@ for (const name of permissions) {
|
|||
},
|
||||
async fn() {
|
||||
const status = await Deno.permissions.query({ name });
|
||||
assertEquals(status.state, "denied");
|
||||
assertEquals(status.state, "prompt");
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ self.onmessage = async () => {
|
|||
const run = await Deno.permissions.query({ name: "run" });
|
||||
const write = await Deno.permissions.query({ name: "write" });
|
||||
self.postMessage(
|
||||
hrtime.state === "denied" &&
|
||||
net.state === "denied" &&
|
||||
ffi.state === "denied" &&
|
||||
read.state === "denied" &&
|
||||
run.state === "denied" &&
|
||||
write.state === "denied",
|
||||
hrtime.state === "prompt" &&
|
||||
net.state === "prompt" &&
|
||||
ffi.state === "prompt" &&
|
||||
read.state === "prompt" &&
|
||||
run.state === "prompt" &&
|
||||
write.state === "prompt",
|
||||
);
|
||||
self.close();
|
||||
};
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
const worker = new Worker(
|
||||
new URL("./read_check_granular_worker.js", import.meta.url).href,
|
||||
{
|
||||
type: "module",
|
||||
deno: {
|
||||
namespace: true,
|
||||
permissions: {
|
||||
read: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
let received = 0;
|
||||
const messages = [];
|
||||
|
||||
worker.onmessage = ({ data: childResponse }) => {
|
||||
received++;
|
||||
postMessage({
|
||||
childHasPermission: childResponse.hasPermission,
|
||||
index: childResponse.index,
|
||||
parentHasPermission: messages[childResponse.index],
|
||||
});
|
||||
if (received === messages.length) {
|
||||
worker.terminate();
|
||||
}
|
||||
};
|
||||
|
||||
onmessage = async ({ data }) => {
|
||||
const { state } = await Deno.permissions.query({
|
||||
name: "read",
|
||||
path: data.path,
|
||||
});
|
||||
|
||||
messages[data.index] = state === "granted";
|
||||
|
||||
worker.postMessage({
|
||||
index: data.index,
|
||||
route: data.route,
|
||||
});
|
||||
};
|
|
@ -1,27 +1,18 @@
|
|||
onmessage = async () => {
|
||||
const { state } = await Deno.permissions.query({
|
||||
name: "read",
|
||||
});
|
||||
|
||||
const worker = new Worker(
|
||||
new URL("./read_check_worker.js", import.meta.url).href,
|
||||
{
|
||||
type: "module",
|
||||
deno: {
|
||||
namespace: true,
|
||||
permissions: {
|
||||
read: false,
|
||||
},
|
||||
},
|
||||
const worker = new Worker(
|
||||
new URL("./read_check_granular_worker.js", import.meta.url).href,
|
||||
{
|
||||
type: "module",
|
||||
deno: {
|
||||
namespace: true,
|
||||
permissions: "none",
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
worker.onmessage = ({ data: childHasPermission }) => {
|
||||
postMessage({
|
||||
parentHasPermission: state === "granted",
|
||||
childHasPermission,
|
||||
});
|
||||
close();
|
||||
};
|
||||
worker.postMessage(null);
|
||||
onmessage = ({ data }) => {
|
||||
worker.postMessage(data);
|
||||
};
|
||||
|
||||
worker.onmessage = ({ data }) => {
|
||||
postMessage(data);
|
||||
};
|
||||
|
|
|
@ -1,11 +1,29 @@
|
|||
onmessage = async ({ data }) => {
|
||||
const { state } = await Deno.permissions.query({
|
||||
name: "read",
|
||||
path: data.path,
|
||||
});
|
||||
|
||||
postMessage({
|
||||
hasPermission: state === "granted",
|
||||
index: data.index,
|
||||
});
|
||||
};
|
||||
// deno-fmt-ignore-file
|
||||
postMessage({
|
||||
envGlobal: (await Deno.permissions.query({ name: "env" })).state,
|
||||
envFoo: (await Deno.permissions.query({ name: "env", variable: "foo" })).state,
|
||||
envAbsent: (await Deno.permissions.query({ name: "env", variable: "absent" })).state,
|
||||
hrtime: (await Deno.permissions.query({ name: "hrtime" })).state,
|
||||
netGlobal: (await Deno.permissions.query({ name: "net" })).state,
|
||||
netFoo: (await Deno.permissions.query({ name: "net", host: "foo" })).state,
|
||||
netFoo8000: (await Deno.permissions.query({ name: "net", host: "foo:8000" })).state,
|
||||
netBar: (await Deno.permissions.query({ name: "net", host: "bar" })).state,
|
||||
netBar8000: (await Deno.permissions.query({ name: "net", host: "bar:8000" })).state,
|
||||
ffiGlobal: (await Deno.permissions.query({ name: "ffi" })).state,
|
||||
ffiFoo: (await Deno.permissions.query({ name: "ffi", path: new URL("foo", import.meta.url) })).state,
|
||||
ffiBar: (await Deno.permissions.query({ name: "ffi", path: "bar" })).state,
|
||||
ffiAbsent: (await Deno.permissions.query({ name: "ffi", path: "absent" })).state,
|
||||
readGlobal: (await Deno.permissions.query({ name: "read" })).state,
|
||||
readFoo: (await Deno.permissions.query({ name: "read", path: new URL("foo", import.meta.url) })).state,
|
||||
readBar: (await Deno.permissions.query({ name: "read", path: "bar" })).state,
|
||||
readAbsent: (await Deno.permissions.query({ name: "read", path: "absent" })).state,
|
||||
runGlobal: (await Deno.permissions.query({ name: "run" })).state,
|
||||
runFoo: (await Deno.permissions.query({ name: "run", command: new URL("foo", import.meta.url) })).state,
|
||||
runBar: (await Deno.permissions.query({ name: "run", command: "bar" })).state,
|
||||
runBaz: (await Deno.permissions.query({ name: "run", command: "./baz" })).state,
|
||||
runAbsent: (await Deno.permissions.query({ name: "run", command: "absent" })).state,
|
||||
writeGlobal: (await Deno.permissions.query({ name: "write" })).state,
|
||||
writeFoo: (await Deno.permissions.query({ name: "write", path: new URL("foo", import.meta.url) })).state,
|
||||
writeBar: (await Deno.permissions.query({ name: "write", path: "bar" })).state,
|
||||
writeAbsent: (await Deno.permissions.query({ name: "write", path: "absent" })).state,
|
||||
});
|
||||
|
|
235
cli/tests/testdata/workers/test.ts
vendored
235
cli/tests/testdata/workers/test.ts
vendored
|
@ -8,7 +8,6 @@ import {
|
|||
assertThrows,
|
||||
} from "../../../../test_util/std/testing/asserts.ts";
|
||||
import { deferred } from "../../../../test_util/std/async/deferred.ts";
|
||||
import { fromFileUrl } from "../../../../test_util/std/path/mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "worker terminate",
|
||||
|
@ -454,7 +453,6 @@ Deno.test("Worker limit children permissions", async function () {
|
|||
});
|
||||
|
||||
Deno.test("Worker limit children permissions granularly", async function () {
|
||||
const promise = deferred();
|
||||
const worker = new Worker(
|
||||
new URL("./read_check_granular_worker.js", import.meta.url).href,
|
||||
{
|
||||
|
@ -462,53 +460,52 @@ Deno.test("Worker limit children permissions granularly", async function () {
|
|||
deno: {
|
||||
namespace: true,
|
||||
permissions: {
|
||||
read: [
|
||||
new URL("./read_check_worker.js", import.meta.url),
|
||||
],
|
||||
env: ["foo"],
|
||||
hrtime: true,
|
||||
net: ["foo", "bar:8000"],
|
||||
ffi: [new URL("foo", import.meta.url), "bar"],
|
||||
read: [new URL("foo", import.meta.url), "bar"],
|
||||
run: [new URL("foo", import.meta.url), "bar", "./baz"],
|
||||
write: [new URL("foo", import.meta.url), "bar"],
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
//Routes are relative to the spawned worker location
|
||||
const routes = [
|
||||
{
|
||||
permission: false,
|
||||
path: fromFileUrl(
|
||||
new URL("read_check_granular_worker.js", import.meta.url),
|
||||
),
|
||||
},
|
||||
{
|
||||
permission: true,
|
||||
path: fromFileUrl(new URL("read_check_worker.js", import.meta.url)),
|
||||
},
|
||||
];
|
||||
|
||||
let checked = 0;
|
||||
worker.onmessage = ({ data }) => {
|
||||
checked++;
|
||||
assertEquals(data.hasPermission, routes[data.index].permission);
|
||||
routes.shift();
|
||||
if (checked === routes.length) {
|
||||
promise.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
routes.forEach(({ path }, index) =>
|
||||
worker.postMessage({
|
||||
index,
|
||||
path,
|
||||
})
|
||||
);
|
||||
|
||||
await promise;
|
||||
const promise = deferred();
|
||||
worker.onmessage = ({ data }) => promise.resolve(data);
|
||||
assertEquals(await promise, {
|
||||
envGlobal: "prompt",
|
||||
envFoo: "granted",
|
||||
envAbsent: "prompt",
|
||||
hrtime: "granted",
|
||||
netGlobal: "prompt",
|
||||
netFoo: "granted",
|
||||
netFoo8000: "granted",
|
||||
netBar: "prompt",
|
||||
netBar8000: "granted",
|
||||
ffiGlobal: "prompt",
|
||||
ffiFoo: "granted",
|
||||
ffiBar: "granted",
|
||||
ffiAbsent: "prompt",
|
||||
readGlobal: "prompt",
|
||||
readFoo: "granted",
|
||||
readBar: "granted",
|
||||
readAbsent: "prompt",
|
||||
runGlobal: "prompt",
|
||||
runFoo: "granted",
|
||||
runBar: "granted",
|
||||
runBaz: "granted",
|
||||
runAbsent: "prompt",
|
||||
writeGlobal: "prompt",
|
||||
writeFoo: "granted",
|
||||
writeBar: "granted",
|
||||
writeAbsent: "prompt",
|
||||
});
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
Deno.test("Nested worker limit children permissions", async function () {
|
||||
const promise = deferred();
|
||||
|
||||
/** This worker has read permissions but doesn't grant them to its children */
|
||||
/** This worker has permissions but doesn't grant them to its children */
|
||||
const worker = new Worker(
|
||||
new URL("./parent_read_check_worker.js", import.meta.url).href,
|
||||
{
|
||||
|
@ -519,104 +516,65 @@ Deno.test("Nested worker limit children permissions", async function () {
|
|||
},
|
||||
},
|
||||
);
|
||||
|
||||
worker.onmessage = ({ data }) => {
|
||||
assert(data.parentHasPermission);
|
||||
assert(!data.childHasPermission);
|
||||
promise.resolve();
|
||||
};
|
||||
|
||||
worker.postMessage(null);
|
||||
|
||||
await promise;
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
Deno.test("Nested worker limit children permissions granularly", async function () {
|
||||
const promise = deferred();
|
||||
|
||||
/** This worker has read permissions but doesn't grant them to its children */
|
||||
const worker = new Worker(
|
||||
new URL("./parent_read_check_granular_worker.js", import.meta.url)
|
||||
.href,
|
||||
{
|
||||
type: "module",
|
||||
deno: {
|
||||
namespace: true,
|
||||
permissions: {
|
||||
read: [
|
||||
new URL("./read_check_granular_worker.js", import.meta.url),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
//Routes are relative to the spawned worker location
|
||||
const routes = [
|
||||
{
|
||||
childHasPermission: false,
|
||||
parentHasPermission: true,
|
||||
path: fromFileUrl(
|
||||
new URL("read_check_granular_worker.js", import.meta.url),
|
||||
),
|
||||
},
|
||||
{
|
||||
childHasPermission: false,
|
||||
parentHasPermission: false,
|
||||
path: fromFileUrl(new URL("read_check_worker.js", import.meta.url)),
|
||||
},
|
||||
];
|
||||
|
||||
let checked = 0;
|
||||
worker.onmessage = ({ data }) => {
|
||||
checked++;
|
||||
assertEquals(
|
||||
data.childHasPermission,
|
||||
routes[data.index].childHasPermission,
|
||||
);
|
||||
assertEquals(
|
||||
data.parentHasPermission,
|
||||
routes[data.index].parentHasPermission,
|
||||
);
|
||||
if (checked === routes.length) {
|
||||
promise.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// Index needed cause requests will be handled asynchronously
|
||||
routes.forEach(({ path }, index) =>
|
||||
worker.postMessage({
|
||||
index,
|
||||
path,
|
||||
})
|
||||
);
|
||||
|
||||
await promise;
|
||||
worker.onmessage = ({ data }) => promise.resolve(data);
|
||||
assertEquals(await promise, {
|
||||
envGlobal: "prompt",
|
||||
envFoo: "prompt",
|
||||
envAbsent: "prompt",
|
||||
hrtime: "prompt",
|
||||
netGlobal: "prompt",
|
||||
netFoo: "prompt",
|
||||
netFoo8000: "prompt",
|
||||
netBar: "prompt",
|
||||
netBar8000: "prompt",
|
||||
ffiGlobal: "prompt",
|
||||
ffiFoo: "prompt",
|
||||
ffiBar: "prompt",
|
||||
ffiAbsent: "prompt",
|
||||
readGlobal: "prompt",
|
||||
readFoo: "prompt",
|
||||
readBar: "prompt",
|
||||
readAbsent: "prompt",
|
||||
runGlobal: "prompt",
|
||||
runFoo: "prompt",
|
||||
runBar: "prompt",
|
||||
runBaz: "prompt",
|
||||
runAbsent: "prompt",
|
||||
writeGlobal: "prompt",
|
||||
writeFoo: "prompt",
|
||||
writeBar: "prompt",
|
||||
writeAbsent: "prompt",
|
||||
});
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
// This test relies on env permissions not being granted on main thread
|
||||
Deno.test("Worker initialization throws on worker permissions greater than parent thread permissions", function () {
|
||||
assertThrows(
|
||||
() => {
|
||||
const worker = new Worker(
|
||||
new URL("./deno_worker.ts", import.meta.url).href,
|
||||
{
|
||||
type: "module",
|
||||
deno: {
|
||||
namespace: true,
|
||||
permissions: {
|
||||
env: true,
|
||||
Deno.test({
|
||||
name:
|
||||
"Worker initialization throws on worker permissions greater than parent thread permissions",
|
||||
permissions: { env: false },
|
||||
fn: function () {
|
||||
assertThrows(
|
||||
() => {
|
||||
const worker = new Worker(
|
||||
new URL("./deno_worker.ts", import.meta.url).href,
|
||||
{
|
||||
type: "module",
|
||||
deno: {
|
||||
namespace: true,
|
||||
permissions: {
|
||||
env: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
worker.terminate();
|
||||
},
|
||||
Deno.errors.PermissionDenied,
|
||||
"Can't escalate parent thread permissions",
|
||||
);
|
||||
);
|
||||
worker.terminate();
|
||||
},
|
||||
Deno.errors.PermissionDenied,
|
||||
"Can't escalate parent thread permissions",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("Worker with disabled permissions", async function () {
|
||||
|
@ -643,6 +601,19 @@ Deno.test("Worker with disabled permissions", async function () {
|
|||
worker.terminate();
|
||||
});
|
||||
|
||||
Deno.test("Worker with invalid permission arg", function () {
|
||||
assertThrows(
|
||||
() =>
|
||||
new Worker(`data:,close();`, {
|
||||
type: "module",
|
||||
// @ts-expect-error invalid env value
|
||||
deno: { permissions: { env: "foo" } },
|
||||
}),
|
||||
TypeError,
|
||||
'Error parsing args: (deno.permissions.env) invalid value: string "foo", expected "inherit" or boolean or string[]',
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "worker location",
|
||||
fn: async function () {
|
||||
|
|
|
@ -20,6 +20,8 @@ use std::cell::RefCell;
|
|||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::c_void;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Unstable(pub bool);
|
||||
|
@ -37,7 +39,7 @@ fn check_unstable(state: &OpState, api_name: &str) {
|
|||
}
|
||||
|
||||
pub trait FfiPermissions {
|
||||
fn check(&mut self, path: &str) -> Result<(), AnyError>;
|
||||
fn check(&mut self, path: &Path) -> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -366,7 +368,7 @@ where
|
|||
|
||||
check_unstable(state, "Deno.dlopen");
|
||||
let permissions = state.borrow_mut::<FP>();
|
||||
permissions.check(&path)?;
|
||||
permissions.check(&PathBuf::from(&path))?;
|
||||
|
||||
let lib = Library::open(&path).map_err(|e| {
|
||||
dlopen::Error::OpeningLibraryError(std::io::Error::new(
|
||||
|
|
|
@ -83,7 +83,10 @@ mod not_docs {
|
|||
}
|
||||
|
||||
impl deno_ffi::FfiPermissions for Permissions {
|
||||
fn check(&mut self, _path: &str) -> Result<(), deno_core::error::AnyError> {
|
||||
fn check(
|
||||
&mut self,
|
||||
_path: &Path,
|
||||
) -> Result<(), deno_core::error::AnyError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
} = window;
|
||||
const { pathFromURL } = window.__bootstrap.util;
|
||||
const {
|
||||
ArrayIsArray,
|
||||
ArrayPrototypeIncludes,
|
||||
ArrayPrototypeMap,
|
||||
ArrayPrototypeSlice,
|
||||
Map,
|
||||
MapPrototypeGet,
|
||||
MapPrototypeHas,
|
||||
|
@ -162,7 +165,9 @@
|
|||
);
|
||||
}
|
||||
|
||||
if (desc.name === "read" || desc.name === "write") {
|
||||
if (
|
||||
desc.name === "read" || desc.name === "write" || desc.name === "ffi"
|
||||
) {
|
||||
desc.path = pathFromURL(desc.path);
|
||||
} else if (desc.name === "run") {
|
||||
desc.command = pathFromURL(desc.command);
|
||||
|
@ -213,7 +218,34 @@
|
|||
|
||||
const permissions = new Permissions(illegalConstructorKey);
|
||||
|
||||
/** Converts all file URLs in FS allowlists to paths. */
|
||||
function serializePermissions(permissions) {
|
||||
if (typeof permissions == "object" && permissions != null) {
|
||||
const serializedPermissions = {};
|
||||
for (const key of ["read", "write", "run", "ffi"]) {
|
||||
if (ArrayIsArray(permissions[key])) {
|
||||
serializedPermissions[key] = ArrayPrototypeMap(
|
||||
permissions[key],
|
||||
(path) => pathFromURL(path),
|
||||
);
|
||||
} else {
|
||||
serializedPermissions[key] = permissions[key];
|
||||
}
|
||||
}
|
||||
for (const key of ["env", "hrtime", "net"]) {
|
||||
if (ArrayIsArray(permissions[key])) {
|
||||
serializedPermissions[key] = ArrayPrototypeSlice(permissions[key]);
|
||||
} else {
|
||||
serializedPermissions[key] = permissions[key];
|
||||
}
|
||||
}
|
||||
return serializedPermissions;
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
|
||||
window.__bootstrap.permissions = {
|
||||
serializePermissions,
|
||||
permissions,
|
||||
Permissions,
|
||||
PermissionStatus,
|
|
@ -4,8 +4,6 @@
|
|||
((window) => {
|
||||
const core = window.Deno.core;
|
||||
const {
|
||||
ArrayIsArray,
|
||||
ArrayPrototypeMap,
|
||||
Error,
|
||||
StringPrototypeStartsWith,
|
||||
String,
|
||||
|
@ -15,7 +13,8 @@
|
|||
const webidl = window.__bootstrap.webidl;
|
||||
const { URL } = window.__bootstrap.url;
|
||||
const { getLocationHref } = window.__bootstrap.location;
|
||||
const { log, pathFromURL } = window.__bootstrap.util;
|
||||
const { serializePermissions } = window.__bootstrap.permissions;
|
||||
const { log } = window.__bootstrap.util;
|
||||
const { defineEventHandler } = window.__bootstrap.event;
|
||||
const { deserializeJsMessageData, serializeJsMessageData } =
|
||||
window.__bootstrap.messagePort;
|
||||
|
@ -32,7 +31,7 @@
|
|||
return core.opSync("op_create_worker", {
|
||||
hasSourceCode,
|
||||
name,
|
||||
permissions,
|
||||
permissions: serializePermissions(permissions),
|
||||
sourceCode,
|
||||
specifier,
|
||||
useDenoNamespace,
|
||||
|
@ -56,87 +55,6 @@
|
|||
return core.opAsync("op_host_recv_message", id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {"inherit" | boolean} value
|
||||
* @param {string} permission
|
||||
* @return {boolean}
|
||||
*/
|
||||
function parseUnitPermission(
|
||||
value,
|
||||
permission,
|
||||
) {
|
||||
if (value !== "inherit" && typeof value !== "boolean") {
|
||||
throw new Error(
|
||||
`Expected 'boolean' for ${permission} permission, ${typeof value} received`,
|
||||
);
|
||||
}
|
||||
return value === "inherit" ? undefined : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} permission
|
||||
* @return {(boolean | string[])}
|
||||
*/
|
||||
function parseArrayPermission(
|
||||
value,
|
||||
permission,
|
||||
) {
|
||||
if (typeof value === "string") {
|
||||
if (value !== "inherit") {
|
||||
throw new Error(
|
||||
`Expected 'array' or 'boolean' for ${permission} permission, "${value}" received`,
|
||||
);
|
||||
}
|
||||
} else if (!ArrayIsArray(value) && typeof value !== "boolean") {
|
||||
throw new Error(
|
||||
`Expected 'array' or 'boolean' for ${permission} permission, ${typeof value} received`,
|
||||
);
|
||||
//Casts URLs to absolute routes
|
||||
} else if (ArrayIsArray(value)) {
|
||||
value = ArrayPrototypeMap(value, (route) => {
|
||||
if (route instanceof URL) {
|
||||
if (permission === "net") {
|
||||
throw new Error(
|
||||
`Expected 'string' for net permission, received 'URL'`,
|
||||
);
|
||||
} else if (permission === "env") {
|
||||
throw new Error(
|
||||
`Expected 'string' for env permission, received 'URL'`,
|
||||
);
|
||||
} else {
|
||||
route = pathFromURL(route);
|
||||
}
|
||||
}
|
||||
return route;
|
||||
});
|
||||
}
|
||||
|
||||
return value === "inherit" ? undefined : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes data, runs checks on parameters and deletes inherited permissions
|
||||
*/
|
||||
function parsePermissions({
|
||||
env = "inherit",
|
||||
hrtime = "inherit",
|
||||
net = "inherit",
|
||||
ffi = "inherit",
|
||||
read = "inherit",
|
||||
run = "inherit",
|
||||
write = "inherit",
|
||||
}) {
|
||||
return {
|
||||
env: parseArrayPermission(env, "env"),
|
||||
hrtime: parseUnitPermission(hrtime, "hrtime"),
|
||||
net: parseArrayPermission(net, "net"),
|
||||
ffi: parseUnitPermission(ffi, "ffi"),
|
||||
read: parseArrayPermission(read, "read"),
|
||||
run: parseUnitPermission(run, "run"),
|
||||
write: parseArrayPermission(write, "write"),
|
||||
};
|
||||
}
|
||||
|
||||
class Worker extends EventTarget {
|
||||
#id = 0;
|
||||
#name = "";
|
||||
|
@ -152,43 +70,23 @@
|
|||
super();
|
||||
specifier = String(specifier);
|
||||
const {
|
||||
deno = {},
|
||||
name = "unknown",
|
||||
deno,
|
||||
name,
|
||||
type = "classic",
|
||||
} = options;
|
||||
|
||||
// TODO(Soremwar)
|
||||
// `deno: boolean` is kept for backwards compatibility with the previous
|
||||
// worker options implementation. Remove for 2.0
|
||||
let workerDenoAttributes;
|
||||
if (typeof deno == "boolean") {
|
||||
workerDenoAttributes = {
|
||||
// Change this to enable the Deno namespace by default
|
||||
namespace: deno,
|
||||
permissions: null,
|
||||
};
|
||||
let namespace;
|
||||
let permissions;
|
||||
if (typeof deno == "object") {
|
||||
namespace = deno.namespace ?? false;
|
||||
permissions = deno.permissions ?? undefined;
|
||||
} else {
|
||||
workerDenoAttributes = {
|
||||
// Change this to enable the Deno namespace by default
|
||||
namespace: !!(deno?.namespace ?? false),
|
||||
permissions: (deno?.permissions ?? "inherit") === "inherit"
|
||||
? null
|
||||
: deno?.permissions,
|
||||
};
|
||||
|
||||
// If the permission option is set to "none", all permissions
|
||||
// must be removed from the worker
|
||||
if (workerDenoAttributes.permissions === "none") {
|
||||
workerDenoAttributes.permissions = {
|
||||
env: false,
|
||||
hrtime: false,
|
||||
net: false,
|
||||
ffi: false,
|
||||
read: false,
|
||||
run: false,
|
||||
write: false,
|
||||
};
|
||||
}
|
||||
// Assume `deno: boolean | undefined`.
|
||||
// TODO(Soremwar)
|
||||
// `deno: boolean` is kept for backwards compatibility with the previous
|
||||
// worker options implementation. Remove for 2.0
|
||||
namespace = !!deno;
|
||||
permissions = undefined;
|
||||
}
|
||||
|
||||
const workerType = webidl.converters["WorkerType"](type);
|
||||
|
@ -218,17 +116,16 @@
|
|||
specifier,
|
||||
hasSourceCode,
|
||||
sourceCode,
|
||||
workerDenoAttributes.namespace,
|
||||
workerDenoAttributes.permissions === null
|
||||
? null
|
||||
: parsePermissions(workerDenoAttributes.permissions),
|
||||
options?.name,
|
||||
namespace,
|
||||
permissions,
|
||||
name,
|
||||
workerType,
|
||||
);
|
||||
this.#id = id;
|
||||
this.#pollControl();
|
||||
this.#pollMessages();
|
||||
}
|
||||
|
||||
#handleError(e) {
|
||||
const event = new ErrorEvent("error", {
|
||||
cancelable: true,
|
||||
|
@ -359,7 +256,6 @@
|
|||
]);
|
||||
|
||||
window.__bootstrap.worker = {
|
||||
parsePermissions,
|
||||
Worker,
|
||||
};
|
||||
})(this);
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
((window) => {
|
||||
const core = window.Deno.core;
|
||||
const { parsePermissions } = window.__bootstrap.worker;
|
||||
const { setExitHandler } = window.__bootstrap.os;
|
||||
const { Console, inspectArgs } = window.__bootstrap.console;
|
||||
const { metrics } = core;
|
||||
const { serializePermissions } = window.__bootstrap.permissions;
|
||||
const { assert } = window.__bootstrap.util;
|
||||
const {
|
||||
ArrayPrototypeFilter,
|
||||
|
@ -230,7 +230,7 @@ finishing test case.`;
|
|||
function pledgePermissions(permissions) {
|
||||
return core.opSync(
|
||||
"op_pledge_test_permissions",
|
||||
parsePermissions(permissions),
|
||||
serializePermissions(permissions),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -289,7 +289,7 @@ finishing test case.`;
|
|||
if (testDef.permissions) {
|
||||
testDef.fn = withPermissions(
|
||||
testDef.fn,
|
||||
parsePermissions(testDef.permissions),
|
||||
testDef.permissions,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ pub struct PermissionArgs {
|
|||
host: Option<String>,
|
||||
variable: Option<String>,
|
||||
command: Option<String>,
|
||||
library: Option<String>,
|
||||
}
|
||||
|
||||
pub fn op_query_permission(
|
||||
|
@ -50,7 +49,7 @@ pub fn op_query_permission(
|
|||
),
|
||||
"env" => permissions.env.query(args.variable.as_deref()),
|
||||
"run" => permissions.run.query(args.command.as_deref()),
|
||||
"ffi" => permissions.ffi.query(args.library.as_deref()),
|
||||
"ffi" => permissions.ffi.query(args.path.as_deref().map(Path::new)),
|
||||
"hrtime" => permissions.hrtime.query(),
|
||||
n => {
|
||||
return Err(custom_error(
|
||||
|
@ -81,7 +80,7 @@ pub fn op_revoke_permission(
|
|||
),
|
||||
"env" => permissions.env.revoke(args.variable.as_deref()),
|
||||
"run" => permissions.run.revoke(args.command.as_deref()),
|
||||
"ffi" => permissions.ffi.revoke(args.library.as_deref()),
|
||||
"ffi" => permissions.ffi.revoke(args.path.as_deref().map(Path::new)),
|
||||
"hrtime" => permissions.hrtime.revoke(),
|
||||
n => {
|
||||
return Err(custom_error(
|
||||
|
@ -112,7 +111,7 @@ pub fn op_request_permission(
|
|||
),
|
||||
"env" => permissions.env.request(args.variable.as_deref()),
|
||||
"run" => permissions.run.request(args.command.as_deref()),
|
||||
"ffi" => permissions.ffi.request(args.library.as_deref()),
|
||||
"ffi" => permissions.ffi.request(args.path.as_deref().map(Path::new)),
|
||||
"hrtime" => permissions.hrtime.request(),
|
||||
n => {
|
||||
return Err(custom_error(
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::ops::TestingFeaturesEnabled;
|
||||
use crate::permissions::resolve_read_allowlist;
|
||||
use crate::permissions::resolve_write_allowlist;
|
||||
use crate::permissions::EnvDescriptor;
|
||||
use crate::permissions::FfiDescriptor;
|
||||
use crate::permissions::NetDescriptor;
|
||||
use crate::permissions::PermissionState;
|
||||
use crate::permissions::create_child_permissions;
|
||||
use crate::permissions::ChildPermissionsArg;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::permissions::ReadDescriptor;
|
||||
use crate::permissions::RunDescriptor;
|
||||
use crate::permissions::UnaryPermission;
|
||||
use crate::permissions::UnitPermission;
|
||||
use crate::permissions::WriteDescriptor;
|
||||
use crate::web_worker::run_web_worker;
|
||||
use crate::web_worker::SendableWebWorkerHandle;
|
||||
use crate::web_worker::WebWorker;
|
||||
|
@ -20,14 +11,10 @@ use crate::web_worker::WebWorkerHandle;
|
|||
use crate::web_worker::WebWorkerType;
|
||||
use crate::web_worker::WorkerControlEvent;
|
||||
use crate::web_worker::WorkerId;
|
||||
use deno_core::error::custom_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::op_async;
|
||||
use deno_core::op_sync;
|
||||
use deno_core::serde::de;
|
||||
use deno_core::serde::de::SeqAccess;
|
||||
use deno_core::serde::Deserialize;
|
||||
use deno_core::serde::Deserializer;
|
||||
use deno_core::Extension;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
|
@ -35,10 +22,6 @@ use deno_web::JsMessageData;
|
|||
use log::debug;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::convert::From;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
|
@ -131,369 +114,12 @@ pub fn init(create_web_worker_cb: Arc<CreateWebWorkerCb>) -> Extension {
|
|||
.build()
|
||||
}
|
||||
|
||||
fn merge_boolean_permission(
|
||||
mut main: UnitPermission,
|
||||
worker: Option<PermissionState>,
|
||||
) -> Result<UnitPermission, AnyError> {
|
||||
if let Some(worker) = worker {
|
||||
if worker < main.state {
|
||||
return Err(custom_error(
|
||||
"PermissionDenied",
|
||||
"Can't escalate parent thread permissions",
|
||||
));
|
||||
} else {
|
||||
main.state = worker;
|
||||
}
|
||||
}
|
||||
Ok(main)
|
||||
}
|
||||
|
||||
fn merge_net_permission(
|
||||
mut main: UnaryPermission<NetDescriptor>,
|
||||
worker: Option<UnaryPermission<NetDescriptor>>,
|
||||
) -> Result<UnaryPermission<NetDescriptor>, AnyError> {
|
||||
if let Some(worker) = worker {
|
||||
if (worker.global_state < main.global_state)
|
||||
|| !worker
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|x| main.check(&(&x.0, x.1)).is_ok())
|
||||
{
|
||||
return Err(custom_error(
|
||||
"PermissionDenied",
|
||||
"Can't escalate parent thread permissions",
|
||||
));
|
||||
} else {
|
||||
main.global_state = worker.global_state;
|
||||
main.granted_list = worker.granted_list;
|
||||
}
|
||||
}
|
||||
Ok(main)
|
||||
}
|
||||
|
||||
fn merge_read_permission(
|
||||
mut main: UnaryPermission<ReadDescriptor>,
|
||||
worker: Option<UnaryPermission<ReadDescriptor>>,
|
||||
) -> Result<UnaryPermission<ReadDescriptor>, AnyError> {
|
||||
if let Some(worker) = worker {
|
||||
if (worker.global_state < main.global_state)
|
||||
|| !worker
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|x| main.check(x.0.as_path()).is_ok())
|
||||
{
|
||||
return Err(custom_error(
|
||||
"PermissionDenied",
|
||||
"Can't escalate parent thread permissions",
|
||||
));
|
||||
} else {
|
||||
main.global_state = worker.global_state;
|
||||
main.granted_list = worker.granted_list;
|
||||
}
|
||||
}
|
||||
Ok(main)
|
||||
}
|
||||
|
||||
fn merge_write_permission(
|
||||
mut main: UnaryPermission<WriteDescriptor>,
|
||||
worker: Option<UnaryPermission<WriteDescriptor>>,
|
||||
) -> Result<UnaryPermission<WriteDescriptor>, AnyError> {
|
||||
if let Some(worker) = worker {
|
||||
if (worker.global_state < main.global_state)
|
||||
|| !worker
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|x| main.check(x.0.as_path()).is_ok())
|
||||
{
|
||||
return Err(custom_error(
|
||||
"PermissionDenied",
|
||||
"Can't escalate parent thread permissions",
|
||||
));
|
||||
} else {
|
||||
main.global_state = worker.global_state;
|
||||
main.granted_list = worker.granted_list;
|
||||
}
|
||||
}
|
||||
Ok(main)
|
||||
}
|
||||
|
||||
fn merge_env_permission(
|
||||
mut main: UnaryPermission<EnvDescriptor>,
|
||||
worker: Option<UnaryPermission<EnvDescriptor>>,
|
||||
) -> Result<UnaryPermission<EnvDescriptor>, AnyError> {
|
||||
if let Some(worker) = worker {
|
||||
if (worker.global_state < main.global_state)
|
||||
|| !worker
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|x| main.check(x.as_ref()).is_ok())
|
||||
{
|
||||
return Err(custom_error(
|
||||
"PermissionDenied",
|
||||
"Can't escalate parent thread permissions",
|
||||
));
|
||||
} else {
|
||||
main.global_state = worker.global_state;
|
||||
main.granted_list = worker.granted_list;
|
||||
}
|
||||
}
|
||||
Ok(main)
|
||||
}
|
||||
|
||||
fn merge_run_permission(
|
||||
mut main: UnaryPermission<RunDescriptor>,
|
||||
worker: Option<UnaryPermission<RunDescriptor>>,
|
||||
) -> Result<UnaryPermission<RunDescriptor>, AnyError> {
|
||||
if let Some(worker) = worker {
|
||||
if (worker.global_state < main.global_state)
|
||||
|| !worker.granted_list.iter().all(|x| main.check(&x.0).is_ok())
|
||||
{
|
||||
return Err(custom_error(
|
||||
"PermissionDenied",
|
||||
"Can't escalate parent thread permissions",
|
||||
));
|
||||
} else {
|
||||
main.global_state = worker.global_state;
|
||||
main.granted_list = worker.granted_list;
|
||||
}
|
||||
}
|
||||
Ok(main)
|
||||
}
|
||||
|
||||
fn merge_ffi_permission(
|
||||
mut main: UnaryPermission<FfiDescriptor>,
|
||||
worker: Option<UnaryPermission<FfiDescriptor>>,
|
||||
) -> Result<UnaryPermission<FfiDescriptor>, AnyError> {
|
||||
if let Some(worker) = worker {
|
||||
if (worker.global_state < main.global_state)
|
||||
|| !worker.granted_list.iter().all(|x| main.check(&x.0).is_ok())
|
||||
{
|
||||
return Err(custom_error(
|
||||
"PermissionDenied",
|
||||
"Can't escalate parent thread permissions",
|
||||
));
|
||||
} else {
|
||||
main.global_state = worker.global_state;
|
||||
main.granted_list = worker.granted_list;
|
||||
}
|
||||
}
|
||||
Ok(main)
|
||||
}
|
||||
|
||||
pub fn create_worker_permissions(
|
||||
main_perms: Permissions,
|
||||
worker_perms: PermissionsArg,
|
||||
) -> Result<Permissions, AnyError> {
|
||||
Ok(Permissions {
|
||||
env: merge_env_permission(main_perms.env, worker_perms.env)?,
|
||||
hrtime: merge_boolean_permission(main_perms.hrtime, worker_perms.hrtime)?,
|
||||
net: merge_net_permission(main_perms.net, worker_perms.net)?,
|
||||
ffi: merge_ffi_permission(main_perms.ffi, worker_perms.ffi)?,
|
||||
read: merge_read_permission(main_perms.read, worker_perms.read)?,
|
||||
run: merge_run_permission(main_perms.run, worker_perms.run)?,
|
||||
write: merge_write_permission(main_perms.write, worker_perms.write)?,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PermissionsArg {
|
||||
#[serde(default, deserialize_with = "as_unary_env_permission")]
|
||||
env: Option<UnaryPermission<EnvDescriptor>>,
|
||||
#[serde(default, deserialize_with = "as_permission_state")]
|
||||
hrtime: Option<PermissionState>,
|
||||
#[serde(default, deserialize_with = "as_unary_net_permission")]
|
||||
net: Option<UnaryPermission<NetDescriptor>>,
|
||||
#[serde(default, deserialize_with = "as_unary_ffi_permission")]
|
||||
ffi: Option<UnaryPermission<FfiDescriptor>>,
|
||||
#[serde(default, deserialize_with = "as_unary_read_permission")]
|
||||
read: Option<UnaryPermission<ReadDescriptor>>,
|
||||
#[serde(default, deserialize_with = "as_unary_run_permission")]
|
||||
run: Option<UnaryPermission<RunDescriptor>>,
|
||||
#[serde(default, deserialize_with = "as_unary_write_permission")]
|
||||
write: Option<UnaryPermission<WriteDescriptor>>,
|
||||
}
|
||||
|
||||
fn as_permission_state<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<PermissionState>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value: bool = Deserialize::deserialize(deserializer)?;
|
||||
|
||||
match value {
|
||||
true => Ok(Some(PermissionState::Granted)),
|
||||
false => Ok(Some(PermissionState::Denied)),
|
||||
}
|
||||
}
|
||||
|
||||
struct UnaryPermissionBase {
|
||||
global_state: PermissionState,
|
||||
paths: Vec<String>,
|
||||
}
|
||||
|
||||
struct ParseBooleanOrStringVec;
|
||||
|
||||
impl<'de> de::Visitor<'de> for ParseBooleanOrStringVec {
|
||||
type Value = UnaryPermissionBase;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a vector of strings or a boolean")
|
||||
}
|
||||
|
||||
// visit_unit maps undefined/missing values to false
|
||||
fn visit_unit<E>(self) -> Result<UnaryPermissionBase, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
self.visit_bool(false)
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, v: bool) -> Result<UnaryPermissionBase, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(UnaryPermissionBase {
|
||||
global_state: match v {
|
||||
true => PermissionState::Granted,
|
||||
false => PermissionState::Denied,
|
||||
},
|
||||
paths: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut visitor: V) -> Result<UnaryPermissionBase, V::Error>
|
||||
where
|
||||
V: SeqAccess<'de>,
|
||||
{
|
||||
let mut vec: Vec<String> = Vec::new();
|
||||
|
||||
let mut value = visitor.next_element::<String>()?;
|
||||
while value.is_some() {
|
||||
vec.push(value.unwrap());
|
||||
value = visitor.next_element()?;
|
||||
}
|
||||
Ok(UnaryPermissionBase {
|
||||
global_state: PermissionState::Prompt,
|
||||
paths: vec,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn as_unary_net_permission<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<UnaryPermission<NetDescriptor>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value: UnaryPermissionBase =
|
||||
deserializer.deserialize_any(ParseBooleanOrStringVec)?;
|
||||
|
||||
let allowed: HashSet<NetDescriptor> = value
|
||||
.paths
|
||||
.into_iter()
|
||||
.map(NetDescriptor::from_string)
|
||||
.collect();
|
||||
|
||||
Ok(Some(UnaryPermission::<NetDescriptor> {
|
||||
global_state: value.global_state,
|
||||
granted_list: allowed,
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
fn as_unary_read_permission<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<UnaryPermission<ReadDescriptor>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value: UnaryPermissionBase =
|
||||
deserializer.deserialize_any(ParseBooleanOrStringVec)?;
|
||||
|
||||
let paths: Vec<PathBuf> =
|
||||
value.paths.into_iter().map(PathBuf::from).collect();
|
||||
|
||||
Ok(Some(UnaryPermission::<ReadDescriptor> {
|
||||
global_state: value.global_state,
|
||||
granted_list: resolve_read_allowlist(&Some(paths)),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
fn as_unary_write_permission<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<UnaryPermission<WriteDescriptor>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value: UnaryPermissionBase =
|
||||
deserializer.deserialize_any(ParseBooleanOrStringVec)?;
|
||||
|
||||
let paths: Vec<PathBuf> =
|
||||
value.paths.into_iter().map(PathBuf::from).collect();
|
||||
|
||||
Ok(Some(UnaryPermission::<WriteDescriptor> {
|
||||
global_state: value.global_state,
|
||||
granted_list: resolve_write_allowlist(&Some(paths)),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
fn as_unary_env_permission<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<UnaryPermission<EnvDescriptor>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value: UnaryPermissionBase =
|
||||
deserializer.deserialize_any(ParseBooleanOrStringVec)?;
|
||||
|
||||
Ok(Some(UnaryPermission::<EnvDescriptor> {
|
||||
global_state: value.global_state,
|
||||
granted_list: value.paths.into_iter().map(EnvDescriptor::new).collect(),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
fn as_unary_run_permission<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<UnaryPermission<RunDescriptor>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value: UnaryPermissionBase =
|
||||
deserializer.deserialize_any(ParseBooleanOrStringVec)?;
|
||||
|
||||
Ok(Some(UnaryPermission::<RunDescriptor> {
|
||||
global_state: value.global_state,
|
||||
granted_list: value.paths.into_iter().map(RunDescriptor).collect(),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
fn as_unary_ffi_permission<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<UnaryPermission<FfiDescriptor>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value: UnaryPermissionBase =
|
||||
deserializer.deserialize_any(ParseBooleanOrStringVec)?;
|
||||
|
||||
Ok(Some(UnaryPermission::<FfiDescriptor> {
|
||||
global_state: value.global_state,
|
||||
granted_list: value.paths.into_iter().map(FfiDescriptor).collect(),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateWorkerArgs {
|
||||
has_source_code: bool,
|
||||
name: Option<String>,
|
||||
permissions: Option<PermissionsArg>,
|
||||
permissions: Option<ChildPermissionsArg>,
|
||||
source_code: String,
|
||||
specifier: String,
|
||||
use_deno_namespace: bool,
|
||||
|
@ -528,13 +154,18 @@ fn op_create_worker(
|
|||
);
|
||||
}
|
||||
}
|
||||
let parent_permissions = state.borrow::<Permissions>().clone();
|
||||
let worker_permissions = if let Some(permissions) = args.permissions {
|
||||
|
||||
if args.permissions.is_some() {
|
||||
super::check_unstable(state, "Worker.deno.permissions");
|
||||
create_worker_permissions(parent_permissions.clone(), permissions)?
|
||||
}
|
||||
let parent_permissions = state.borrow_mut::<Permissions>();
|
||||
let worker_permissions = if let Some(child_permissions_arg) = args.permissions
|
||||
{
|
||||
create_child_permissions(parent_permissions, child_permissions_arg)?
|
||||
} else {
|
||||
parent_permissions.clone()
|
||||
};
|
||||
let parent_permissions = parent_permissions.clone();
|
||||
|
||||
let worker_id = state.take::<WorkerId>();
|
||||
let create_module_loader = state.take::<CreateWebWorkerCbHolder>();
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue