diff options
Diffstat (limited to 'cli/js')
-rw-r--r-- | cli/js/deno_unstable.ts | 3 | ||||
-rw-r--r-- | cli/js/globals.ts | 22 | ||||
-rw-r--r-- | cli/js/lib.deno.ns.d.ts | 93 | ||||
-rw-r--r-- | cli/js/lib.deno.shared_globals.d.ts | 54 | ||||
-rw-r--r-- | cli/js/lib.deno.unstable.d.ts | 114 | ||||
-rw-r--r-- | cli/js/ops/permissions.ts | 1 | ||||
-rw-r--r-- | cli/js/permissions.ts | 79 | ||||
-rw-r--r-- | cli/js/web/navigator.ts | 12 | ||||
-rw-r--r-- | cli/js/web/permissions.ts | 181 |
9 files changed, 205 insertions, 354 deletions
diff --git a/cli/js/deno_unstable.ts b/cli/js/deno_unstable.ts index f92d767b3..6e334e223 100644 --- a/cli/js/deno_unstable.ts +++ b/cli/js/deno_unstable.ts @@ -19,6 +19,9 @@ export { shutdown, ShutdownMode } from "./net.ts"; export { listen, listenDatagram, connect } from "./net_unstable.ts"; export { startTls } from "./tls.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 type { Diagnostic, diff --git a/cli/js/globals.ts b/cli/js/globals.ts index 394460848..ff2ff8f4d 100644 --- a/cli/js/globals.ts +++ b/cli/js/globals.ts @@ -7,6 +7,7 @@ import * as abortSignal from "./web/abort_signal.ts"; import * as blob from "./web/blob.ts"; import * as consoleTypes from "./web/console.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 domException from "./web/dom_exception.ts"; import * as domFile from "./web/dom_file.ts"; @@ -16,19 +17,16 @@ import * as eventTarget from "./web/event_target.ts"; import * as formData from "./web/form_data.ts"; import * as fetchTypes from "./web/fetch.ts"; import * as headers from "./web/headers.ts"; -import * as navigator from "./web/navigator.ts"; -import * as permissions from "./web/permissions.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 timers from "./web/timers.ts"; -import * as transformStream from "./web/streams/transform_stream.ts"; import * as url from "./web/url.ts"; import * as urlSearchParams from "./web/url_search_params.ts"; import * as workers from "./web/workers.ts"; import * as performance 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"; // These imports are not exposed and therefore are fine to just import the @@ -223,19 +221,15 @@ export const windowOrWorkerGlobalScopeProperties = { queuingStrategy.ByteLengthQueuingStrategyImpl ), CountQueuingStrategy: nonEnumerable(queuingStrategy.CountQueuingStrategyImpl), - CustomEvent: nonEnumerable(customEvent.CustomEventImpl), crypto: readOnly(csprng), + File: nonEnumerable(domFile.DomFileImpl), + CustomEvent: nonEnumerable(customEvent.CustomEventImpl), DOMException: nonEnumerable(domException.DOMExceptionImpl), ErrorEvent: nonEnumerable(errorEvent.ErrorEventImpl), Event: nonEnumerable(event.EventImpl), EventTarget: nonEnumerable(eventTarget.EventTargetImpl), - File: nonEnumerable(domFile.DomFileImpl), - FormData: nonEnumerable(formData.FormDataImpl), Headers: nonEnumerable(headers.HeadersImpl), - navigator: nonEnumerable(new navigator.NavigatorImpl()), - Navigator: nonEnumerable(navigator.NavigatorImpl), - Permissions: nonEnumerable(permissions.PermissionsImpl), - PermissionStatus: nonEnumerable(permissions.PermissionStatusImpl), + FormData: nonEnumerable(formData.FormDataImpl), ReadableStream: nonEnumerable(readableStream.ReadableStreamImpl), Request: nonEnumerable(request.Request), Response: nonEnumerable(fetchTypes.Response), diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index 373f3be2f..47402187d 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -63,40 +63,6 @@ declare interface PerformanceMeasureOptions { end?: string | number; } -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 { /** A set of error constructors that are raised by Deno APIs. */ export const errors: { @@ -1977,65 +1943,6 @@ declare namespace Deno { * Requires `allow-run` permission. */ 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; - export interface InspectOptions { /** Traversal depth for nested objects. Defaults to 4. */ depth?: number; diff --git a/cli/js/lib.deno.shared_globals.d.ts b/cli/js/lib.deno.shared_globals.d.ts index 893af8bbe..f37dfa366 100644 --- a/cli/js/lib.deno.shared_globals.d.ts +++ b/cli/js/lib.deno.shared_globals.d.ts @@ -1646,60 +1646,6 @@ declare const 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 { /** See https://v8.dev/docs/stack-trace-api#stack-trace-collection-for-custom-exceptions. */ // eslint-disable-next-line @typescript-eslint/ban-types diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts index a6547ebca..05508a363 100644 --- a/cli/js/lib.deno.unstable.d.ts +++ b/cli/js/lib.deno.unstable.d.ts @@ -971,6 +971,120 @@ 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 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 * necessary around the permissions required. * diff --git a/cli/js/ops/permissions.ts b/cli/js/ops/permissions.ts index cb1cd7402..74b9ba0f0 100644 --- a/cli/js/ops/permissions.ts +++ b/cli/js/ops/permissions.ts @@ -1,6 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { sendSync } from "./dispatch_json.ts"; +import type { PermissionState } from "../permissions.ts"; interface PermissionRequest { name: string; diff --git a/cli/js/permissions.ts b/cli/js/permissions.ts new file mode 100644 index 000000000..ab0612ad4 --- /dev/null +++ b/cli/js/permissions.ts @@ -0,0 +1,79 @@ +// 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(); diff --git a/cli/js/web/navigator.ts b/cli/js/web/navigator.ts deleted file mode 100644 index 351c311d0..000000000 --- a/cli/js/web/navigator.ts +++ /dev/null @@ -1,12 +0,0 @@ -// 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, -}); diff --git a/cli/js/web/permissions.ts b/cli/js/web/permissions.ts deleted file mode 100644 index b8ddc26a7..000000000 --- a/cli/js/web/permissions.ts +++ /dev/null @@ -1,181 +0,0 @@ -// 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, -}); |