Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(runtime): stabilise permissions and add event target capabilities #9573

Merged
merged 4 commits into from
Feb 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions cli/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,17 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
"DiagnosticCategory",
"DiagnosticItem",
"DiagnosticMessageChain",
"EnvPermissionDescriptor",
"HrtimePermissionDescriptor",
"HttpClient",
"LinuxSignal",
"Location",
"MacOSSignal",
"NetPermissionDescriptor",
"PermissionDescriptor",
"PermissionName",
"PermissionState",
"PermissionStatus",
"Permissions",
"PluginPermissionDescriptor",
"ReadPermissionDescriptor",
"RunPermissionDescriptor",
"Signal",
"SignalStream",
"StartTlsOptions",
"SymlinkOptions",
"TranspileOnlyResult",
"UnixConnectOptions",
"UnixListenOptions",
"WritePermissionDescriptor",
"applySourceMap",
"connect",
"consoleSize",
Expand All @@ -64,7 +52,6 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
"mainModule",
"openPlugin",
"osRelease",
"permissions",
"ppid",
"setRaw",
"shutdown",
Expand Down
134 changes: 134 additions & 0 deletions cli/dts/lib.deno.ns.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2072,6 +2072,140 @@ declare namespace Deno {
*/
export function inspect(value: unknown, options?: InspectOptions): string;

/** The name of a "powerful feature" which needs permission. */
export type PermissionName =
| "run"
| "read"
| "write"
| "net"
| "env"
| "plugin"
| "hrtime";

/** The current status of the permission. */
export type PermissionState = "granted" | "denied" | "prompt";

export interface RunPermissionDescriptor {
name: "run";
}

export interface ReadPermissionDescriptor {
name: "read";
path?: string;
}

export interface WritePermissionDescriptor {
name: "write";
path?: string;
}

export interface NetPermissionDescriptor {
name: "net";
/** Optional host string of the form `"<hostname>[:<port>]"`. Examples:
*
* "github.com"
* "deno.land:8080"
*/
host?: string;
}

export interface EnvPermissionDescriptor {
name: "env";
}

export interface PluginPermissionDescriptor {
name: "plugin";
}

export interface HrtimePermissionDescriptor {
name: "hrtime";
}

/** Permission descriptors which define a permission and can be queried,
* requested, or revoked. */
export type PermissionDescriptor =
| RunPermissionDescriptor
| ReadPermissionDescriptor
| WritePermissionDescriptor
| NetPermissionDescriptor
| EnvPermissionDescriptor
| PluginPermissionDescriptor
| HrtimePermissionDescriptor;

export interface PermissionStatusEventMap {
"change": Event;
}

export class PermissionStatus extends EventTarget {
// deno-lint-ignore no-explicit-any
onchange: ((this: PermissionStatus, ev: Event) => any) | null;
readonly state: PermissionState;
addEventListener<K extends keyof PermissionStatusEventMap>(
type: K,
listener: (
this: PermissionStatus,
ev: PermissionStatusEventMap[K],
) => any,
options?: boolean | AddEventListenerOptions,
): void;
addEventListener(
type: string,
listener: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions,
): void;
removeEventListener<K extends keyof PermissionStatusEventMap>(
type: K,
listener: (
this: PermissionStatus,
ev: PermissionStatusEventMap[K],
) => any,
options?: boolean | EventListenerOptions,
): void;
removeEventListener(
type: string,
listener: EventListenerOrEventListenerObject,
options?: boolean | EventListenerOptions,
): void;
}

export class Permissions {
/** Resolves to the current status of a permission.
*
* ```ts
* const status = await Deno.permissions.query({ name: "read", path: "/etc" });
* if (status.state === "granted") {
* data = await Deno.readFile("/etc/passwd");
* }
* ```
*/
query(desc: PermissionDescriptor): Promise<PermissionStatus>;

/** Revokes a permission, and resolves to the state of the permission.
*
* ```ts
* const status = await Deno.permissions.revoke({ name: "run" });
* assert(status.state !== "granted")
* ```
*/
revoke(desc: PermissionDescriptor): Promise<PermissionStatus>;

/** Requests the permission, and resolves to the state of the permission.
*
* ```ts
* const status = await Deno.permissions.request({ name: "env" });
* if (status.state === "granted") {
* console.log("'env' permission is granted.");
* } else {
* console.log("'env' permission is denied.");
* }
* ```
*/
request(desc: PermissionDescriptor): Promise<PermissionStatus>;
}

/** Deno's permission management API. */
export const permissions: Permissions;

/** Build related information. */
export const build: {
/** The LLVM target triple */
Expand Down
113 changes: 0 additions & 113 deletions cli/dts/lib.deno.unstable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1071,119 +1071,6 @@ declare namespace Deno {
* Requires `allow-run` permission. */
export function kill(pid: number, signo: number): void;

/** The name of a "powerful feature" which needs permission.
*
* See: https://w3c.github.io/permissions/#permission-registry
*
* Note that the definition of `PermissionName` in the above spec is swapped
* out for a set of Deno permissions which are not web-compatible. */
export type PermissionName =
| "run"
| "read"
| "write"
| "net"
| "env"
| "plugin"
| "hrtime";

/** The current status of the permission.
*
* See: https://w3c.github.io/permissions/#status-of-a-permission */
export type PermissionState = "granted" | "denied" | "prompt";

export interface RunPermissionDescriptor {
name: "run";
}

export interface ReadPermissionDescriptor {
name: "read";
path?: string;
}

export interface WritePermissionDescriptor {
name: "write";
path?: string;
}

export interface NetPermissionDescriptor {
name: "net";
/** Optional host string of the form `"<hostname>[:<port>]"`. Examples:
*
* "github.com"
* "deno.land:8080"
*/
host?: string;
}

export interface EnvPermissionDescriptor {
name: "env";
}

export interface PluginPermissionDescriptor {
name: "plugin";
}

export interface HrtimePermissionDescriptor {
name: "hrtime";
}

/** Permission descriptors which define a permission and can be queried,
* requested, or revoked.
*
* See: https://w3c.github.io/permissions/#permission-descriptor */
export type PermissionDescriptor =
| RunPermissionDescriptor
| ReadPermissionDescriptor
| WritePermissionDescriptor
| NetPermissionDescriptor
| EnvPermissionDescriptor
| PluginPermissionDescriptor
| HrtimePermissionDescriptor;

export class Permissions {
/** Resolves to the current status of a permission.
*
* ```ts
* const status = await Deno.permissions.query({ name: "read", path: "/etc" });
* if (status.state === "granted") {
* data = await Deno.readFile("/etc/passwd");
* }
* ```
*/
query(desc: PermissionDescriptor): Promise<PermissionStatus>;

/** Revokes a permission, and resolves to the state of the permission.
*
* const status = await Deno.permissions.revoke({ name: "run" });
* assert(status.state !== "granted")
*/
revoke(desc: PermissionDescriptor): Promise<PermissionStatus>;

/** Requests the permission, and resolves to the state of the permission.
*
* ```ts
* const status = await Deno.permissions.request({ name: "env" });
* if (status.state === "granted") {
* console.log("'env' permission is granted.");
* } else {
* console.log("'env' permission is denied.");
* }
* ```
*/
request(desc: PermissionDescriptor): Promise<PermissionStatus>;
}

/** **UNSTABLE**: Under consideration to move to `navigator.permissions` to
* match web API. It could look like `navigator.permissions.query({ name: Deno.symbols.read })`.
*/
export const permissions: Permissions;

/** see: https://w3c.github.io/permissions/#permissionstatus */
export class PermissionStatus {
state: PermissionState;
constructor();
}

/** **UNSTABLE**: New API, yet to be vetted. Additional consideration is still
* necessary around the permissions required.
*
Expand Down
8 changes: 4 additions & 4 deletions cli/lsp/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2261,7 +2261,7 @@ mod tests {
},
"end": {
"line": 0,
"character": 28
"character": 27
}
}
}),
Expand Down Expand Up @@ -2290,9 +2290,9 @@ mod tests {
"contents": [
{
"language": "typescript",
"value": "const Deno.permissions: Deno.Permissions"
"value": "function Deno.openPlugin(filename: string): number"
},
"**UNSTABLE**: Under consideration to move to `navigator.permissions` to\nmatch web API. It could look like `navigator.permissions.query({ name: Deno.symbols.read })`."
"**UNSTABLE**: new API, yet to be vetted.\n\nOpen and initialize a plugin.\n\n```ts\nconst rid = Deno.openPlugin(\"./path/to/some/plugin.so\");\nconst opId = Deno.core.ops()[\"some_op\"];\nconst response = Deno.core.dispatch(opId, new Uint8Array([1,2,3,4]));\nconsole.log(`Response from plugin ${response}`);\n```\n\nRequires `allow-plugin` permission.\n\nThe plugin system is not stable and will change in the future, hence the\nlack of docs. For now take a look at the example\nhttps://github.com/denoland/deno/tree/master/test_plugin"
],
"range": {
"start": {
Expand All @@ -2301,7 +2301,7 @@ mod tests {
},
"end": {
"line": 0,
"character": 28
"character": 27
}
}
}),
Expand Down
9 changes: 6 additions & 3 deletions cli/tests/061_permissions_request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const status1 = await Deno.permissions.request({ name: "read", path: "foo" });
const status2 = await Deno.permissions.query({ name: "read", path: "bar" });
const status3 = await Deno.permissions.request({ name: "read", path: "bar" });
const status1 =
(await Deno.permissions.request({ name: "read", path: "foo" })).state;
const status2 =
(await Deno.permissions.query({ name: "read", path: "bar" })).state;
const status3 =
(await Deno.permissions.request({ name: "read", path: "bar" })).state;
console.log(status1);
console.log(status2);
console.log(status3);
6 changes: 3 additions & 3 deletions cli/tests/061_permissions_request.ts.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[WILDCARD]PermissionStatus { state: "granted" }
PermissionStatus { state: "prompt" }
PermissionStatus { state: "denied" }
[WILDCARD]granted
prompt
denied
4 changes: 2 additions & 2 deletions cli/tests/062_permissions_request_global.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const status1 = await Deno.permissions.request({ name: "read" });
const status2 = await Deno.permissions.query({ name: "read", path: "foo" });
const status3 = await Deno.permissions.query({ name: "read", path: "bar" });
console.log(status1);
const status2 = await Deno.permissions.query({ name: "read", path: "foo" });
console.log(status2);
const status3 = await Deno.permissions.query({ name: "read", path: "bar" });
console.log(status3);
6 changes: 3 additions & 3 deletions cli/tests/062_permissions_request_global.ts.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[WILDCARD]PermissionStatus { state: "granted" }
PermissionStatus { state: "granted" }
PermissionStatus { state: "granted" }
[WILDCARD]PermissionStatus { state: "granted", onchange: null }
PermissionStatus { state: "granted", onchange: null }
PermissionStatus { state: "granted", onchange: null }
4 changes: 2 additions & 2 deletions cli/tests/063_permissions_revoke.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const status1 = await Deno.permissions.revoke({ name: "read", path: "foo" });
const status2 = await Deno.permissions.query({ name: "read", path: "bar" });
const status3 = await Deno.permissions.revoke({ name: "read", path: "bar" });
console.log(status1);
const status2 = await Deno.permissions.query({ name: "read", path: "bar" });
console.log(status2);
const status3 = await Deno.permissions.revoke({ name: "read", path: "bar" });
console.log(status3);
6 changes: 3 additions & 3 deletions cli/tests/063_permissions_revoke.ts.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[WILDCARD]PermissionStatus { state: "prompt" }
PermissionStatus { state: "granted" }
PermissionStatus { state: "prompt" }
[WILDCARD]PermissionStatus { state: "prompt", onchange: null }
PermissionStatus { state: "granted", onchange: null }
PermissionStatus { state: "prompt", onchange: null }
4 changes: 2 additions & 2 deletions cli/tests/064_permissions_revoke_global.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const status1 = await Deno.permissions.revoke({ name: "read" });
const status2 = await Deno.permissions.query({ name: "read", path: "foo" });
const status3 = await Deno.permissions.query({ name: "read", path: "bar" });
console.log(status1);
const status2 = await Deno.permissions.query({ name: "read", path: "foo" });
console.log(status2);
const status3 = await Deno.permissions.query({ name: "read", path: "bar" });
console.log(status3);
6 changes: 3 additions & 3 deletions cli/tests/064_permissions_revoke_global.ts.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[WILDCARD]PermissionStatus { state: "prompt" }
PermissionStatus { state: "prompt" }
PermissionStatus { state: "prompt" }
[WILDCARD]PermissionStatus { state: "prompt", onchange: null }
PermissionStatus { state: "prompt", onchange: null }
PermissionStatus { state: "prompt", onchange: null }
Loading