mirror of
https://github.com/denoland/deno.git
synced 2025-08-03 18:38:33 +00:00
feat: Add configurable permissions for Workers (#8215)
This commit adds new option to "Worker" Web API that allows to configure permissions. New "Worker.deno.permissions" option can be used to define limited permissions to the worker thread by either: - inherit set of parent thread permissions - use limited subset of parent thread permissions - revoke all permissions (full sandbox) In order to achieve this functionality "CliModuleLoader" was modified to accept "initial permissions", which are used for top module loading (ie. uses parent thread permission set to load top level module of a worker).
This commit is contained in:
parent
2e18fcebcc
commit
adc2f08c17
33 changed files with 1062 additions and 73 deletions
|
@ -3,21 +3,24 @@
|
|||
((window) => {
|
||||
const core = window.Deno.core;
|
||||
const { Window } = window.__bootstrap.globalInterfaces;
|
||||
const { log } = window.__bootstrap.util;
|
||||
const { log, pathFromURL } = window.__bootstrap.util;
|
||||
const { defineEventHandler } = window.__bootstrap.webUtil;
|
||||
const build = window.__bootstrap.build.build;
|
||||
|
||||
function createWorker(
|
||||
specifier,
|
||||
hasSourceCode,
|
||||
sourceCode,
|
||||
useDenoNamespace,
|
||||
permissions,
|
||||
name,
|
||||
) {
|
||||
return core.jsonOpSync("op_create_worker", {
|
||||
specifier,
|
||||
hasSourceCode,
|
||||
sourceCode,
|
||||
name,
|
||||
permissions,
|
||||
sourceCode,
|
||||
specifier,
|
||||
useDenoNamespace,
|
||||
});
|
||||
}
|
||||
|
@ -47,14 +50,122 @@
|
|||
return JSON.parse(dataJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} permission
|
||||
* @return {boolean}
|
||||
*/
|
||||
function parseBooleanPermission(
|
||||
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 (!Array.isArray(value) && typeof value !== "boolean") {
|
||||
throw new Error(
|
||||
`Expected 'array' or 'boolean' for ${permission} permission, ${typeof value} received`,
|
||||
);
|
||||
//Casts URLs to absolute routes
|
||||
} else if (Array.isArray(value)) {
|
||||
value = value.map((route) => {
|
||||
if (route instanceof URL) {
|
||||
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",
|
||||
plugin = "inherit",
|
||||
read = "inherit",
|
||||
run = "inherit",
|
||||
write = "inherit",
|
||||
}) {
|
||||
return {
|
||||
env: parseBooleanPermission(env, "env"),
|
||||
hrtime: parseBooleanPermission(hrtime, "hrtime"),
|
||||
net: parseArrayPermission(net, "net"),
|
||||
plugin: parseBooleanPermission(plugin, "plugin"),
|
||||
read: parseArrayPermission(read, "read"),
|
||||
run: parseBooleanPermission(run, "run"),
|
||||
write: parseArrayPermission(write, "write"),
|
||||
};
|
||||
}
|
||||
|
||||
class Worker extends EventTarget {
|
||||
#id = 0;
|
||||
#name = "";
|
||||
#terminated = false;
|
||||
|
||||
constructor(specifier, options) {
|
||||
constructor(specifier, options = {}) {
|
||||
super();
|
||||
const { type = "classic", name = "unknown" } = options ?? {};
|
||||
const {
|
||||
deno = {},
|
||||
name = "unknown",
|
||||
type = "classic",
|
||||
} = options;
|
||||
|
||||
// TODO(Soremwar)
|
||||
// `deno: true` is kept for backwards compatibility with the previous worker
|
||||
// options implementation. Remove for 2.0
|
||||
let workerDenoAttributes;
|
||||
if (deno === true) {
|
||||
workerDenoAttributes = {
|
||||
// Change this to enable the Deno namespace by default
|
||||
namespace: deno,
|
||||
permissions: null,
|
||||
};
|
||||
} 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 false, all permissions
|
||||
// must be removed from the worker
|
||||
if (workerDenoAttributes.permissions === false) {
|
||||
workerDenoAttributes.permissions = {
|
||||
env: false,
|
||||
hrtime: false,
|
||||
net: false,
|
||||
plugin: false,
|
||||
read: false,
|
||||
run: false,
|
||||
write: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (type !== "module") {
|
||||
throw new Error(
|
||||
|
@ -66,13 +177,14 @@
|
|||
const hasSourceCode = false;
|
||||
const sourceCode = decoder.decode(new Uint8Array());
|
||||
|
||||
const useDenoNamespace = options ? !!options.deno : false;
|
||||
|
||||
const { id } = createWorker(
|
||||
specifier,
|
||||
hasSourceCode,
|
||||
sourceCode,
|
||||
useDenoNamespace,
|
||||
workerDenoAttributes.namespace,
|
||||
workerDenoAttributes.permissions === null
|
||||
? null
|
||||
: parsePermissions(workerDenoAttributes.permissions),
|
||||
options?.name,
|
||||
);
|
||||
this.#id = id;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue