diff options
-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 | ||||
-rw-r--r-- | cli/tests/025_hrtime.ts | 2 | ||||
-rw-r--r-- | cli/tests/057_revoke_permissions.ts | 4 | ||||
-rw-r--r-- | cli/tests/unit/permissions_test.ts | 53 | ||||
-rw-r--r-- | cli/tests/unit/test_util.ts | 2 | ||||
-rwxr-xr-x | cli/tests/unit/unit_test_runner.ts | 2 | ||||
-rw-r--r-- | std/permissions/mod.ts | 10 |
15 files changed, 236 insertions, 396 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, -}); diff --git a/cli/tests/025_hrtime.ts b/cli/tests/025_hrtime.ts index fef39ffdb..9f60b7a77 100644 --- a/cli/tests/025_hrtime.ts +++ b/cli/tests/025_hrtime.ts @@ -1,5 +1,5 @@ window.onload = async (): Promise<void> => { console.log(performance.now() % 2 !== 0); - await navigator.permissions.revoke({ name: "hrtime" }); + await Deno.permissions.revoke({ name: "hrtime" }); console.log(performance.now() % 2 === 0); }; diff --git a/cli/tests/057_revoke_permissions.ts b/cli/tests/057_revoke_permissions.ts index 4a39112d2..de8deecb4 100644 --- a/cli/tests/057_revoke_permissions.ts +++ b/cli/tests/057_revoke_permissions.ts @@ -18,11 +18,11 @@ export function assert(cond: unknown): asserts cond { function genFunc(grant: Deno.PermissionName): [string, () => Promise<void>] { const gen: () => Promise<void> = async function Granted(): Promise<void> { - const status0 = await navigator.permissions.query({ name: grant }); + const status0 = await Deno.permissions.query({ name: grant }); assert(status0 != null); assert(status0.state === "granted"); - const status1 = await navigator.permissions.revoke({ name: grant }); + const status1 = await Deno.permissions.revoke({ name: grant }); assert(status1 != null); assert(status1.state === "prompt"); }; diff --git a/cli/tests/unit/permissions_test.ts b/cli/tests/unit/permissions_test.ts index 0de6a774b..7528768a1 100644 --- a/cli/tests/unit/permissions_test.ts +++ b/cli/tests/unit/permissions_test.ts @@ -1,40 +1,27 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { unitTest, assert, assertThrowsAsync } from "./test_util.ts"; +import { unitTest, assert } from "./test_util.ts"; unitTest(async function permissionInvalidName(): Promise<void> { - await assertThrowsAsync(async () => { - // @ts-expect-error name should not accept "foo" - await navigator.permissions.query({ name: "foo" }); - }, TypeError); + let thrown = false; + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + await Deno.permissions.query({ name: "foo" as any }); + } catch (e) { + thrown = true; + assert(e instanceof Error); + } finally { + assert(thrown); + } }); unitTest(async function permissionNetInvalidUrl(): Promise<void> { - await assertThrowsAsync(async () => { - await navigator.permissions.query({ name: "net", url: ":" }); - }, URIError); -}); - -unitTest(async function permissionQueryReturnsEventTarget(): Promise<void> { - const status = await navigator.permissions.query({ name: "hrtime" }); - 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); + let thrown = false; + try { + await Deno.permissions.query({ name: "net", url: ":" }); + } catch (e) { + thrown = true; + assert(e instanceof URIError); + } finally { + assert(thrown); + } }); diff --git a/cli/tests/unit/test_util.ts b/cli/tests/unit/test_util.ts index dd6c858d2..25da7a638 100644 --- a/cli/tests/unit/test_util.ts +++ b/cli/tests/unit/test_util.ts @@ -42,7 +42,7 @@ export function fmtPerms(perms: Permissions): string { } const isGranted = async (name: Deno.PermissionName): Promise<boolean> => - (await navigator.permissions.query({ name })).state === "granted"; + (await Deno.permissions.query({ name })).state === "granted"; export async function getProcessPermissions(): Promise<Permissions> { return { diff --git a/cli/tests/unit/unit_test_runner.ts b/cli/tests/unit/unit_test_runner.ts index c7c494278..b2e872200 100755 --- a/cli/tests/unit/unit_test_runner.ts +++ b/cli/tests/unit/unit_test_runner.ts @@ -49,7 +49,7 @@ async function dropWorkerPermissions( }); for (const perm of permsToDrop) { - await navigator.permissions.revoke({ name: perm }); + await Deno.permissions.revoke({ name: perm }); } } diff --git a/std/permissions/mod.ts b/std/permissions/mod.ts index d27b0c80d..b7f80117b 100644 --- a/std/permissions/mod.ts +++ b/std/permissions/mod.ts @@ -1,5 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +const { PermissionDenied } = Deno.errors; + function getPermissionString(descriptors: Deno.PermissionDescriptor[]): string { return descriptors.length ? ` ${descriptors @@ -61,9 +63,9 @@ export async function grant( ? descriptor : [descriptor, ...descriptors]; for (const descriptor of descriptors) { - let state = (await navigator.permissions.query(descriptor)).state; + let state = (await Deno.permissions.query(descriptor)).state; if (state === "prompt") { - state = (await navigator.permissions.request(descriptor)).state; + state = (await Deno.permissions.request(descriptor)).state; } if (state === "granted") { result.push(descriptor); @@ -103,13 +105,13 @@ export async function grantOrThrow( ? descriptor : [descriptor, ...descriptors]; for (const descriptor of descriptors) { - const { state } = await navigator.permissions.request(descriptor); + const { state } = await Deno.permissions.request(descriptor); if (state !== "granted") { denied.push(descriptor); } } if (denied.length) { - throw new Deno.errors.PermissionDenied( + throw new PermissionDenied( `The following permissions have not been granted:\n${getPermissionString( denied )}` |