mirror of
https://github.com/denoland/deno.git
synced 2025-09-30 14:11:14 +00:00
feat: move unstable Deno.permissions to navigator.permissions (#6244)
This commit is contained in:
parent
e92cf5b9e8
commit
202e7fa6ad
15 changed files with 403 additions and 243 deletions
|
@ -19,9 +19,6 @@ export { shutdown, ShutdownMode } from "./net.ts";
|
||||||
export { listen, listenDatagram, connect } from "./net_unstable.ts";
|
export { listen, listenDatagram, connect } from "./net_unstable.ts";
|
||||||
export { startTls } from "./tls.ts";
|
export { startTls } from "./tls.ts";
|
||||||
export { kill } from "./ops/process.ts";
|
export { kill } from "./ops/process.ts";
|
||||||
export { permissions, Permissions } from "./permissions.ts";
|
|
||||||
export { PermissionStatus } from "./permissions.ts";
|
|
||||||
export type { PermissionName, PermissionState } from "./permissions.ts";
|
|
||||||
export { DiagnosticCategory } from "./diagnostics.ts";
|
export { DiagnosticCategory } from "./diagnostics.ts";
|
||||||
export type {
|
export type {
|
||||||
Diagnostic,
|
Diagnostic,
|
||||||
|
|
|
@ -7,7 +7,6 @@ import * as abortSignal from "./web/abort_signal.ts";
|
||||||
import * as blob from "./web/blob.ts";
|
import * as blob from "./web/blob.ts";
|
||||||
import * as consoleTypes from "./web/console.ts";
|
import * as consoleTypes from "./web/console.ts";
|
||||||
import * as csprng from "./ops/get_random_values.ts";
|
import * as csprng from "./ops/get_random_values.ts";
|
||||||
import type * as promiseTypes from "./web/promise.ts";
|
|
||||||
import * as customEvent from "./web/custom_event.ts";
|
import * as customEvent from "./web/custom_event.ts";
|
||||||
import * as domException from "./web/dom_exception.ts";
|
import * as domException from "./web/dom_exception.ts";
|
||||||
import * as domFile from "./web/dom_file.ts";
|
import * as domFile from "./web/dom_file.ts";
|
||||||
|
@ -17,16 +16,19 @@ import * as eventTarget from "./web/event_target.ts";
|
||||||
import * as formData from "./web/form_data.ts";
|
import * as formData from "./web/form_data.ts";
|
||||||
import * as fetchTypes from "./web/fetch.ts";
|
import * as fetchTypes from "./web/fetch.ts";
|
||||||
import * as headers from "./web/headers.ts";
|
import * as headers from "./web/headers.ts";
|
||||||
|
import * as navigator from "./web/navigator.ts";
|
||||||
|
import * as permissions from "./web/permissions.ts";
|
||||||
|
import * as performanceUtil from "./web/performance.ts";
|
||||||
|
import type * as promiseTypes from "./web/promise.ts";
|
||||||
|
import * as queuingStrategy from "./web/streams/queuing_strategy.ts";
|
||||||
|
import * as readableStream from "./web/streams/readable_stream.ts";
|
||||||
|
import * as request from "./web/request.ts";
|
||||||
import * as textEncoding from "./web/text_encoding.ts";
|
import * as textEncoding from "./web/text_encoding.ts";
|
||||||
import * as timers from "./web/timers.ts";
|
import * as timers from "./web/timers.ts";
|
||||||
|
import * as transformStream from "./web/streams/transform_stream.ts";
|
||||||
import * as url from "./web/url.ts";
|
import * as url from "./web/url.ts";
|
||||||
import * as urlSearchParams from "./web/url_search_params.ts";
|
import * as urlSearchParams from "./web/url_search_params.ts";
|
||||||
import * as workers from "./web/workers.ts";
|
import * as workers from "./web/workers.ts";
|
||||||
import * as performanceUtil from "./web/performance.ts";
|
|
||||||
import * as request from "./web/request.ts";
|
|
||||||
import * as readableStream from "./web/streams/readable_stream.ts";
|
|
||||||
import * as transformStream from "./web/streams/transform_stream.ts";
|
|
||||||
import * as queuingStrategy from "./web/streams/queuing_strategy.ts";
|
|
||||||
import * as writableStream from "./web/streams/writable_stream.ts";
|
import * as writableStream from "./web/streams/writable_stream.ts";
|
||||||
|
|
||||||
// These imports are not exposed and therefore are fine to just import the
|
// These imports are not exposed and therefore are fine to just import the
|
||||||
|
@ -221,24 +223,28 @@ export const windowOrWorkerGlobalScopeProperties = {
|
||||||
queuingStrategy.ByteLengthQueuingStrategyImpl
|
queuingStrategy.ByteLengthQueuingStrategyImpl
|
||||||
),
|
),
|
||||||
CountQueuingStrategy: nonEnumerable(queuingStrategy.CountQueuingStrategyImpl),
|
CountQueuingStrategy: nonEnumerable(queuingStrategy.CountQueuingStrategyImpl),
|
||||||
crypto: readOnly(csprng),
|
|
||||||
File: nonEnumerable(domFile.DomFileImpl),
|
|
||||||
CustomEvent: nonEnumerable(customEvent.CustomEventImpl),
|
CustomEvent: nonEnumerable(customEvent.CustomEventImpl),
|
||||||
|
crypto: readOnly(csprng),
|
||||||
DOMException: nonEnumerable(domException.DOMExceptionImpl),
|
DOMException: nonEnumerable(domException.DOMExceptionImpl),
|
||||||
ErrorEvent: nonEnumerable(errorEvent.ErrorEventImpl),
|
ErrorEvent: nonEnumerable(errorEvent.ErrorEventImpl),
|
||||||
Event: nonEnumerable(event.EventImpl),
|
Event: nonEnumerable(event.EventImpl),
|
||||||
EventTarget: nonEnumerable(eventTarget.EventTargetImpl),
|
EventTarget: nonEnumerable(eventTarget.EventTargetImpl),
|
||||||
URL: nonEnumerable(url.URLImpl),
|
File: nonEnumerable(domFile.DomFileImpl),
|
||||||
URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParamsImpl),
|
|
||||||
Headers: nonEnumerable(headers.HeadersImpl),
|
|
||||||
FormData: nonEnumerable(formData.FormDataImpl),
|
FormData: nonEnumerable(formData.FormDataImpl),
|
||||||
TextEncoder: nonEnumerable(textEncoding.TextEncoder),
|
Headers: nonEnumerable(headers.HeadersImpl),
|
||||||
TextDecoder: nonEnumerable(textEncoding.TextDecoder),
|
navigator: nonEnumerable(new navigator.NavigatorImpl()),
|
||||||
|
Navigator: nonEnumerable(navigator.NavigatorImpl),
|
||||||
|
performance: writable(new performanceUtil.Performance()),
|
||||||
|
Permissions: nonEnumerable(permissions.PermissionsImpl),
|
||||||
|
PermissionStatus: nonEnumerable(permissions.PermissionStatusImpl),
|
||||||
ReadableStream: nonEnumerable(readableStream.ReadableStreamImpl),
|
ReadableStream: nonEnumerable(readableStream.ReadableStreamImpl),
|
||||||
TransformStream: nonEnumerable(transformStream.TransformStreamImpl),
|
|
||||||
Request: nonEnumerable(request.Request),
|
Request: nonEnumerable(request.Request),
|
||||||
Response: nonEnumerable(fetchTypes.Response),
|
Response: nonEnumerable(fetchTypes.Response),
|
||||||
performance: writable(new performanceUtil.Performance()),
|
TextDecoder: nonEnumerable(textEncoding.TextDecoder),
|
||||||
|
TextEncoder: nonEnumerable(textEncoding.TextEncoder),
|
||||||
|
TransformStream: nonEnumerable(transformStream.TransformStreamImpl),
|
||||||
|
URL: nonEnumerable(url.URLImpl),
|
||||||
|
URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParamsImpl),
|
||||||
Worker: nonEnumerable(workers.WorkerImpl),
|
Worker: nonEnumerable(workers.WorkerImpl),
|
||||||
WritableStream: nonEnumerable(writableStream.WritableStreamImpl),
|
WritableStream: nonEnumerable(writableStream.WritableStreamImpl),
|
||||||
};
|
};
|
||||||
|
|
93
cli/js/lib.deno.ns.d.ts
vendored
93
cli/js/lib.deno.ns.d.ts
vendored
|
@ -19,6 +19,40 @@ declare interface ImportMeta {
|
||||||
main: boolean;
|
main: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare interface Permissions {
|
||||||
|
/** Resolves to the current status of a permission.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* const status = await navigator.permissions.query({ name: "read", path: "/etc" });
|
||||||
|
* if (status.state === "granted") {
|
||||||
|
* data = await Deno.readFile("/etc/passwd");
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
query(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>;
|
||||||
|
|
||||||
|
/** Requests the permission, and resolves to the state of the permission.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* const status = await navigator.permissions.request({ name: "env" });
|
||||||
|
* if (status.state === "granted") {
|
||||||
|
* console.log(Deno.dir("home");
|
||||||
|
* } else {
|
||||||
|
* console.log("'env' permission is denied.");
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
request(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>;
|
||||||
|
|
||||||
|
/** Revokes a permission, and resolves to the state of the permission.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* const status = await Deno.revoke({ name: "run" });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
revoke(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>;
|
||||||
|
}
|
||||||
|
|
||||||
declare namespace Deno {
|
declare namespace Deno {
|
||||||
/** A set of error constructors that are raised by Deno APIs. */
|
/** A set of error constructors that are raised by Deno APIs. */
|
||||||
export const errors: {
|
export const errors: {
|
||||||
|
@ -1897,6 +1931,65 @@ declare namespace Deno {
|
||||||
* Requires `allow-run` permission. */
|
* Requires `allow-run` permission. */
|
||||||
export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>;
|
export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>;
|
||||||
|
|
||||||
|
/** 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";
|
||||||
|
|
||||||
|
export interface RunPermissionDescriptor {
|
||||||
|
name: "run";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReadPermissionDescriptor {
|
||||||
|
name: "read";
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WritePermissionDescriptor {
|
||||||
|
name: "write";
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NetPermissionDescriptor {
|
||||||
|
name: "net";
|
||||||
|
url?: 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;
|
||||||
|
|
||||||
interface InspectOptions {
|
interface InspectOptions {
|
||||||
depth?: number;
|
depth?: number;
|
||||||
}
|
}
|
||||||
|
|
54
cli/js/lib.deno.shared_globals.d.ts
vendored
54
cli/js/lib.deno.shared_globals.d.ts
vendored
|
@ -1556,6 +1556,60 @@ declare const AbortSignal: {
|
||||||
new (): AbortSignal;
|
new (): AbortSignal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type PermissionState = "denied" | "granted" | "prompt";
|
||||||
|
|
||||||
|
interface PermissionStatusEventMap {
|
||||||
|
change: Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PermissionStatus extends EventTarget {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deno does not currently support any of the browser permissions, and so the
|
||||||
|
* `name` property of the global types is `undefined`. The Deno permissions
|
||||||
|
* that are supported are defined in the `lib.deno.ns.d.ts` and pull from the
|
||||||
|
* `Deno` namespace. */
|
||||||
|
declare interface PermissionDescriptor {
|
||||||
|
name: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface Permissions {
|
||||||
|
query(permissionDesc: PermissionDescriptor): Promise<PermissionStatus>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const Permissions: {
|
||||||
|
prototype: Permissions;
|
||||||
|
new (): Permissions;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare class Navigator {
|
||||||
|
readonly permissions: Permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const navigator: Navigator;
|
||||||
|
|
||||||
interface ErrorConstructor {
|
interface ErrorConstructor {
|
||||||
/** See https://v8.dev/docs/stack-trace-api#stack-trace-collection-for-custom-exceptions. */
|
/** See https://v8.dev/docs/stack-trace-api#stack-trace-collection-for-custom-exceptions. */
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
|
114
cli/js/lib.deno.unstable.d.ts
vendored
114
cli/js/lib.deno.unstable.d.ts
vendored
|
@ -956,120 +956,6 @@ declare namespace Deno {
|
||||||
* Requires `allow-run` permission. */
|
* Requires `allow-run` permission. */
|
||||||
export function kill(pid: number, signo: number): void;
|
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 url associated with this descriptor.
|
|
||||||
*
|
|
||||||
* If specified: must be a valid url. Expected format: <scheme>://<host_or_ip>[:port][/path]
|
|
||||||
* If the scheme is unknown, callers should specify some scheme, such as x:// na:// unknown://
|
|
||||||
*
|
|
||||||
* See: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml */
|
|
||||||
url?: 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(Deno.dir("home");
|
|
||||||
* } 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(state: PermissionState);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** **UNSTABLE**: New API, yet to be vetted. Additional consideration is still
|
/** **UNSTABLE**: New API, yet to be vetted. Additional consideration is still
|
||||||
* necessary around the permissions required.
|
* necessary around the permissions required.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
import { sendSync } from "./dispatch_json.ts";
|
import { sendSync } from "./dispatch_json.ts";
|
||||||
import type { PermissionState } from "../permissions.ts";
|
|
||||||
|
|
||||||
interface PermissionRequest {
|
interface PermissionRequest {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
||||||
|
|
||||||
import * as permissionsOps from "./ops/permissions.ts";
|
|
||||||
|
|
||||||
export type PermissionName =
|
|
||||||
| "read"
|
|
||||||
| "write"
|
|
||||||
| "net"
|
|
||||||
| "env"
|
|
||||||
| "run"
|
|
||||||
| "plugin"
|
|
||||||
| "hrtime";
|
|
||||||
// NOTE: Keep in sync with cli/permissions.rs
|
|
||||||
|
|
||||||
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";
|
|
||||||
url?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EnvPermissionDescriptor {
|
|
||||||
name: "env";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PluginPermissionDescriptor {
|
|
||||||
name: "plugin";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HrtimePermissionDescriptor {
|
|
||||||
name: "hrtime";
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PermissionDescriptor =
|
|
||||||
| RunPermissionDescriptor
|
|
||||||
| ReadPermissionDescriptor
|
|
||||||
| WritePermissionDescriptor
|
|
||||||
| NetPermissionDescriptor
|
|
||||||
| EnvPermissionDescriptor
|
|
||||||
| PluginPermissionDescriptor
|
|
||||||
| HrtimePermissionDescriptor;
|
|
||||||
|
|
||||||
export class PermissionStatus {
|
|
||||||
constructor(public state: PermissionState) {}
|
|
||||||
// TODO(kt3k): implement onchange handler
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Permissions {
|
|
||||||
query(desc: PermissionDescriptor): Promise<PermissionStatus> {
|
|
||||||
const state = permissionsOps.query(desc);
|
|
||||||
return Promise.resolve(new PermissionStatus(state));
|
|
||||||
}
|
|
||||||
|
|
||||||
revoke(desc: PermissionDescriptor): Promise<PermissionStatus> {
|
|
||||||
const state = permissionsOps.revoke(desc);
|
|
||||||
return Promise.resolve(new PermissionStatus(state));
|
|
||||||
}
|
|
||||||
|
|
||||||
request(desc: PermissionDescriptor): Promise<PermissionStatus> {
|
|
||||||
const state = permissionsOps.request(desc);
|
|
||||||
return Promise.resolve(new PermissionStatus(state));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const permissions = new Permissions();
|
|
12
cli/js/web/navigator.ts
Normal file
12
cli/js/web/navigator.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
import { PermissionsImpl as Permissions } from "./permissions.ts";
|
||||||
|
|
||||||
|
export class NavigatorImpl implements Navigator {
|
||||||
|
permissions = new Permissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(NavigatorImpl, "name", {
|
||||||
|
value: "Navigator",
|
||||||
|
configurable: true,
|
||||||
|
});
|
181
cli/js/web/permissions.ts
Normal file
181
cli/js/web/permissions.ts
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
import * as permissionsOps from "../ops/permissions.ts";
|
||||||
|
import { EventTargetImpl as EventTarget } from "./event_target.ts";
|
||||||
|
|
||||||
|
const permissionNames = [
|
||||||
|
"read",
|
||||||
|
"write",
|
||||||
|
"net",
|
||||||
|
"env",
|
||||||
|
"run",
|
||||||
|
"plugin",
|
||||||
|
"hrtime",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
type PermissionName = typeof permissionNames[number];
|
||||||
|
|
||||||
|
interface RunPermissionDescriptor {
|
||||||
|
name: "run";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadPermissionDescriptor {
|
||||||
|
name: "read";
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WritePermissionDescriptor {
|
||||||
|
name: "write";
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NetPermissionDescriptor {
|
||||||
|
name: "net";
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EnvPermissionDescriptor {
|
||||||
|
name: "env";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PluginPermissionDescriptor {
|
||||||
|
name: "plugin";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HrtimePermissionDescriptor {
|
||||||
|
name: "hrtime";
|
||||||
|
}
|
||||||
|
|
||||||
|
type DenoPermissionDescriptor =
|
||||||
|
| RunPermissionDescriptor
|
||||||
|
| ReadPermissionDescriptor
|
||||||
|
| WritePermissionDescriptor
|
||||||
|
| NetPermissionDescriptor
|
||||||
|
| EnvPermissionDescriptor
|
||||||
|
| PluginPermissionDescriptor
|
||||||
|
| HrtimePermissionDescriptor;
|
||||||
|
|
||||||
|
interface StatusCacheValue {
|
||||||
|
state: PermissionState;
|
||||||
|
status: PermissionStatusImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PermissionStatusImpl extends EventTarget
|
||||||
|
implements PermissionStatus {
|
||||||
|
#state: { state: PermissionState };
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
onchange: ((this: PermissionStatus, event: Event) => any) | null = null;
|
||||||
|
|
||||||
|
get state(): PermissionState {
|
||||||
|
return this.#state.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(state: { state: PermissionState }) {
|
||||||
|
super();
|
||||||
|
this.#state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvent(event: Event): boolean {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
let dispatched = super.dispatchEvent(event as any);
|
||||||
|
if (dispatched && this.onchange) {
|
||||||
|
this.onchange.call(this, event);
|
||||||
|
dispatched = !event.defaultPrevented;
|
||||||
|
}
|
||||||
|
return dispatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
get [Symbol.toStringTag](): string {
|
||||||
|
return "PermissionStatus";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A cache of `PermissionStatus` objects and their last known state. */
|
||||||
|
const statusCache = new Map<string, StatusCacheValue>();
|
||||||
|
|
||||||
|
/** Cache the state of a descriptor and return its `PermissionStatus`. */
|
||||||
|
function cache(
|
||||||
|
desc: DenoPermissionDescriptor,
|
||||||
|
state: PermissionState
|
||||||
|
): PermissionStatusImpl {
|
||||||
|
let key = desc.name;
|
||||||
|
if ((desc.name === "read" || desc.name === "write") && desc.path) {
|
||||||
|
key += `-${desc.path}`;
|
||||||
|
} else if (desc.name === "net" && desc.url) {
|
||||||
|
key += `-${desc.url}`;
|
||||||
|
}
|
||||||
|
if (statusCache.has(key)) {
|
||||||
|
const status = statusCache.get(key)!;
|
||||||
|
if (status.state !== state) {
|
||||||
|
status.state = state;
|
||||||
|
status.status.dispatchEvent(new Event("change", { cancelable: false }));
|
||||||
|
}
|
||||||
|
return status.status;
|
||||||
|
}
|
||||||
|
const status: { state: PermissionState; status?: PermissionStatusImpl } = {
|
||||||
|
state,
|
||||||
|
};
|
||||||
|
status.status = new PermissionStatusImpl(status);
|
||||||
|
statusCache.set(key, status as StatusCacheValue);
|
||||||
|
return status.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidDescriptor(
|
||||||
|
desc: PermissionDescriptor | DenoPermissionDescriptor
|
||||||
|
): desc is DenoPermissionDescriptor {
|
||||||
|
return permissionNames.includes(desc.name as PermissionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PermissionsImpl implements Permissions {
|
||||||
|
query(
|
||||||
|
desc: PermissionDescriptor | DenoPermissionDescriptor
|
||||||
|
): Promise<PermissionStatus> {
|
||||||
|
if (!isValidDescriptor(desc)) {
|
||||||
|
return Promise.reject(
|
||||||
|
new TypeError(
|
||||||
|
`The provided value "${desc.name}" is not a valid permission name.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const state = permissionsOps.query(desc);
|
||||||
|
return Promise.resolve(cache(desc, state) as PermissionStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
revoke(
|
||||||
|
desc: PermissionDescriptor | DenoPermissionDescriptor
|
||||||
|
): Promise<PermissionStatus> {
|
||||||
|
if (!isValidDescriptor(desc)) {
|
||||||
|
return Promise.reject(
|
||||||
|
new TypeError(
|
||||||
|
`The provided value "${desc.name}" is not a valid permission name.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const state = permissionsOps.revoke(desc);
|
||||||
|
return Promise.resolve(cache(desc, state) as PermissionStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
request(
|
||||||
|
desc: PermissionDescriptor | DenoPermissionDescriptor
|
||||||
|
): Promise<PermissionStatus> {
|
||||||
|
if (!isValidDescriptor(desc)) {
|
||||||
|
return Promise.reject(
|
||||||
|
new TypeError(
|
||||||
|
`The provided value "${desc.name}" is not a valid permission name.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const state = permissionsOps.request(desc);
|
||||||
|
return Promise.resolve(cache(desc, state) as PermissionStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(PermissionStatusImpl, "name", {
|
||||||
|
value: "PermissionStatus",
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
Object.defineProperty(PermissionsImpl, "name", {
|
||||||
|
value: "Permissions",
|
||||||
|
configurable: true,
|
||||||
|
});
|
|
@ -1,5 +1,5 @@
|
||||||
window.onload = async (): Promise<void> => {
|
window.onload = async (): Promise<void> => {
|
||||||
console.log(performance.now() % 2 !== 0);
|
console.log(performance.now() % 2 !== 0);
|
||||||
await Deno.permissions.revoke({ name: "hrtime" });
|
await navigator.permissions.revoke({ name: "hrtime" });
|
||||||
console.log(performance.now() % 2 === 0);
|
console.log(performance.now() % 2 === 0);
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,11 +18,11 @@ export function assert(cond: unknown): asserts cond {
|
||||||
|
|
||||||
function genFunc(grant: Deno.PermissionName): [string, () => Promise<void>] {
|
function genFunc(grant: Deno.PermissionName): [string, () => Promise<void>] {
|
||||||
const gen: () => Promise<void> = async function Granted(): Promise<void> {
|
const gen: () => Promise<void> = async function Granted(): Promise<void> {
|
||||||
const status0 = await Deno.permissions.query({ name: grant });
|
const status0 = await navigator.permissions.query({ name: grant });
|
||||||
assert(status0 != null);
|
assert(status0 != null);
|
||||||
assert(status0.state === "granted");
|
assert(status0.state === "granted");
|
||||||
|
|
||||||
const status1 = await Deno.permissions.revoke({ name: grant });
|
const status1 = await navigator.permissions.revoke({ name: grant });
|
||||||
assert(status1 != null);
|
assert(status1 != null);
|
||||||
assert(status1.state === "prompt");
|
assert(status1.state === "prompt");
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,27 +1,40 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
import { unitTest, assert } from "./test_util.ts";
|
|
||||||
|
import { unitTest, assert, assertThrowsAsync } from "./test_util.ts";
|
||||||
|
|
||||||
unitTest(async function permissionInvalidName(): Promise<void> {
|
unitTest(async function permissionInvalidName(): Promise<void> {
|
||||||
let thrown = false;
|
await assertThrowsAsync(async () => {
|
||||||
try {
|
// @ts-expect-error name should not accept "foo"
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
await navigator.permissions.query({ name: "foo" });
|
||||||
await Deno.permissions.query({ name: "foo" as any });
|
}, TypeError);
|
||||||
} catch (e) {
|
|
||||||
thrown = true;
|
|
||||||
assert(e instanceof Error);
|
|
||||||
} finally {
|
|
||||||
assert(thrown);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest(async function permissionNetInvalidUrl(): Promise<void> {
|
unitTest(async function permissionNetInvalidUrl(): Promise<void> {
|
||||||
let thrown = false;
|
await assertThrowsAsync(async () => {
|
||||||
try {
|
await navigator.permissions.query({ name: "net", url: ":" });
|
||||||
await Deno.permissions.query({ name: "net", url: ":" });
|
}, URIError);
|
||||||
} catch (e) {
|
});
|
||||||
thrown = true;
|
|
||||||
assert(e instanceof URIError);
|
unitTest(async function permissionQueryReturnsEventTarget(): Promise<void> {
|
||||||
} finally {
|
const status = await navigator.permissions.query({ name: "hrtime" });
|
||||||
assert(thrown);
|
assert(["granted", "denied", "prompt"].includes(status.state));
|
||||||
}
|
let called = false;
|
||||||
|
status.addEventListener("change", () => {
|
||||||
|
called = true;
|
||||||
|
});
|
||||||
|
status.dispatchEvent(new Event("change"));
|
||||||
|
assert(called);
|
||||||
|
assert(status === (await navigator.permissions.query({ name: "hrtime" })));
|
||||||
|
});
|
||||||
|
|
||||||
|
unitTest(async function permissionQueryForReadReturnsSameStatus() {
|
||||||
|
const status1 = await navigator.permissions.query({
|
||||||
|
name: "read",
|
||||||
|
path: ".",
|
||||||
|
});
|
||||||
|
const status2 = await navigator.permissions.query({
|
||||||
|
name: "read",
|
||||||
|
path: ".",
|
||||||
|
});
|
||||||
|
assert(status1 === status2);
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,7 +42,7 @@ export function fmtPerms(perms: Permissions): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const isGranted = async (name: Deno.PermissionName): Promise<boolean> =>
|
const isGranted = async (name: Deno.PermissionName): Promise<boolean> =>
|
||||||
(await Deno.permissions.query({ name })).state === "granted";
|
(await navigator.permissions.query({ name })).state === "granted";
|
||||||
|
|
||||||
export async function getProcessPermissions(): Promise<Permissions> {
|
export async function getProcessPermissions(): Promise<Permissions> {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -49,7 +49,7 @@ async function dropWorkerPermissions(
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const perm of permsToDrop) {
|
for (const perm of permsToDrop) {
|
||||||
await Deno.permissions.revoke({ name: perm });
|
await navigator.permissions.revoke({ name: perm });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
const { PermissionDenied } = Deno.errors;
|
|
||||||
|
|
||||||
function getPermissionString(descriptors: Deno.PermissionDescriptor[]): string {
|
function getPermissionString(descriptors: Deno.PermissionDescriptor[]): string {
|
||||||
return descriptors.length
|
return descriptors.length
|
||||||
? ` ${descriptors
|
? ` ${descriptors
|
||||||
|
@ -63,9 +61,9 @@ export async function grant(
|
||||||
? descriptor
|
? descriptor
|
||||||
: [descriptor, ...descriptors];
|
: [descriptor, ...descriptors];
|
||||||
for (const descriptor of descriptors) {
|
for (const descriptor of descriptors) {
|
||||||
let state = (await Deno.permissions.query(descriptor)).state;
|
let state = (await navigator.permissions.query(descriptor)).state;
|
||||||
if (state === "prompt") {
|
if (state === "prompt") {
|
||||||
state = (await Deno.permissions.request(descriptor)).state;
|
state = (await navigator.permissions.request(descriptor)).state;
|
||||||
}
|
}
|
||||||
if (state === "granted") {
|
if (state === "granted") {
|
||||||
result.push(descriptor);
|
result.push(descriptor);
|
||||||
|
@ -105,13 +103,13 @@ export async function grantOrThrow(
|
||||||
? descriptor
|
? descriptor
|
||||||
: [descriptor, ...descriptors];
|
: [descriptor, ...descriptors];
|
||||||
for (const descriptor of descriptors) {
|
for (const descriptor of descriptors) {
|
||||||
const { state } = await Deno.permissions.request(descriptor);
|
const { state } = await navigator.permissions.request(descriptor);
|
||||||
if (state !== "granted") {
|
if (state !== "granted") {
|
||||||
denied.push(descriptor);
|
denied.push(descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (denied.length) {
|
if (denied.length) {
|
||||||
throw new PermissionDenied(
|
throw new Deno.errors.PermissionDenied(
|
||||||
`The following permissions have not been granted:\n${getPermissionString(
|
`The following permissions have not been granted:\n${getPermissionString(
|
||||||
denied
|
denied
|
||||||
)}`
|
)}`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue