mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05: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 { 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,
|
||||
|
|
|
@ -7,7 +7,6 @@ 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";
|
||||
|
@ -17,16 +16,19 @@ 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 * 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 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 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";
|
||||
|
||||
// These imports are not exposed and therefore are fine to just import the
|
||||
|
@ -221,24 +223,28 @@ export const windowOrWorkerGlobalScopeProperties = {
|
|||
queuingStrategy.ByteLengthQueuingStrategyImpl
|
||||
),
|
||||
CountQueuingStrategy: nonEnumerable(queuingStrategy.CountQueuingStrategyImpl),
|
||||
crypto: readOnly(csprng),
|
||||
File: nonEnumerable(domFile.DomFileImpl),
|
||||
CustomEvent: nonEnumerable(customEvent.CustomEventImpl),
|
||||
crypto: readOnly(csprng),
|
||||
DOMException: nonEnumerable(domException.DOMExceptionImpl),
|
||||
ErrorEvent: nonEnumerable(errorEvent.ErrorEventImpl),
|
||||
Event: nonEnumerable(event.EventImpl),
|
||||
EventTarget: nonEnumerable(eventTarget.EventTargetImpl),
|
||||
URL: nonEnumerable(url.URLImpl),
|
||||
URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParamsImpl),
|
||||
Headers: nonEnumerable(headers.HeadersImpl),
|
||||
File: nonEnumerable(domFile.DomFileImpl),
|
||||
FormData: nonEnumerable(formData.FormDataImpl),
|
||||
TextEncoder: nonEnumerable(textEncoding.TextEncoder),
|
||||
TextDecoder: nonEnumerable(textEncoding.TextDecoder),
|
||||
Headers: nonEnumerable(headers.HeadersImpl),
|
||||
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),
|
||||
TransformStream: nonEnumerable(transformStream.TransformStreamImpl),
|
||||
Request: nonEnumerable(request.Request),
|
||||
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),
|
||||
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;
|
||||
}
|
||||
|
||||
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: {
|
||||
|
@ -1897,6 +1931,65 @@ 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;
|
||||
|
||||
interface InspectOptions {
|
||||
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;
|
||||
};
|
||||
|
||||
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
|
||||
|
|
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. */
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// 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;
|
||||
|
|
|
@ -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> => {
|
||||
console.log(performance.now() % 2 !== 0);
|
||||
await Deno.permissions.revoke({ name: "hrtime" });
|
||||
await navigator.permissions.revoke({ name: "hrtime" });
|
||||
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>] {
|
||||
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.state === "granted");
|
||||
|
||||
const status1 = await Deno.permissions.revoke({ name: grant });
|
||||
const status1 = await navigator.permissions.revoke({ name: grant });
|
||||
assert(status1 != null);
|
||||
assert(status1.state === "prompt");
|
||||
};
|
||||
|
|
|
@ -1,27 +1,40 @@
|
|||
// 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> {
|
||||
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);
|
||||
}
|
||||
await assertThrowsAsync(async () => {
|
||||
// @ts-expect-error name should not accept "foo"
|
||||
await navigator.permissions.query({ name: "foo" });
|
||||
}, TypeError);
|
||||
});
|
||||
|
||||
unitTest(async function permissionNetInvalidUrl(): Promise<void> {
|
||||
let thrown = false;
|
||||
try {
|
||||
await Deno.permissions.query({ name: "net", url: ":" });
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
assert(e instanceof URIError);
|
||||
} finally {
|
||||
assert(thrown);
|
||||
}
|
||||
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);
|
||||
});
|
||||
|
|
|
@ -42,7 +42,7 @@ export function fmtPerms(perms: Permissions): string {
|
|||
}
|
||||
|
||||
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> {
|
||||
return {
|
||||
|
|
|
@ -49,7 +49,7 @@ async function dropWorkerPermissions(
|
|||
});
|
||||
|
||||
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.
|
||||
|
||||
const { PermissionDenied } = Deno.errors;
|
||||
|
||||
function getPermissionString(descriptors: Deno.PermissionDescriptor[]): string {
|
||||
return descriptors.length
|
||||
? ` ${descriptors
|
||||
|
@ -63,9 +61,9 @@ export async function grant(
|
|||
? descriptor
|
||||
: [descriptor, ...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") {
|
||||
state = (await Deno.permissions.request(descriptor)).state;
|
||||
state = (await navigator.permissions.request(descriptor)).state;
|
||||
}
|
||||
if (state === "granted") {
|
||||
result.push(descriptor);
|
||||
|
@ -105,13 +103,13 @@ export async function grantOrThrow(
|
|||
? descriptor
|
||||
: [descriptor, ...descriptors];
|
||||
for (const descriptor of descriptors) {
|
||||
const { state } = await Deno.permissions.request(descriptor);
|
||||
const { state } = await navigator.permissions.request(descriptor);
|
||||
if (state !== "granted") {
|
||||
denied.push(descriptor);
|
||||
}
|
||||
}
|
||||
if (denied.length) {
|
||||
throw new PermissionDenied(
|
||||
throw new Deno.errors.PermissionDenied(
|
||||
`The following permissions have not been granted:\n${getPermissionString(
|
||||
denied
|
||||
)}`
|
||||
|
|
Loading…
Reference in a new issue