Skip to content

Commit

Permalink
feat(runtime): stabilise permissions and add event target capabilities (
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk authored Feb 25, 2021
1 parent 90e4c5d commit 097e9c4
Show file tree
Hide file tree
Showing 17 changed files with 333 additions and 176 deletions.
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 @@ -2076,6 +2076,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 @@ -2226,7 +2226,7 @@ mod tests {
},
"end": {
"line": 0,
"character": 28
"character": 27
}
}
}),
Expand Down Expand Up @@ -2255,9 +2255,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 @@ -2266,7 +2266,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

0 comments on commit 097e9c4

Please sign in to comment.