diff options
Diffstat (limited to 'cli/js')
-rw-r--r-- | cli/js/deno.ts | 5 | ||||
-rw-r--r-- | cli/js/dispatch.ts | 2 | ||||
-rw-r--r-- | cli/js/errors.ts | 3 | ||||
-rw-r--r-- | cli/js/lib.deno_runtime.d.ts | 84 | ||||
-rw-r--r-- | cli/js/permissions.ts | 94 | ||||
-rw-r--r-- | cli/js/permissions_test.ts | 41 | ||||
-rw-r--r-- | cli/js/test_util.ts | 37 | ||||
-rwxr-xr-x | cli/js/unit_test_runner.ts | 10 |
8 files changed, 191 insertions, 85 deletions
diff --git a/cli/js/deno.ts b/cli/js/deno.ts index 4b0e3ff96..cac730249 100644 --- a/cli/js/deno.ts +++ b/cli/js/deno.ts @@ -68,8 +68,9 @@ export { applySourceMap } from "./error_stack.ts"; export { ErrorKind, DenoError } from "./errors.ts"; export { permissions, - revokePermission, - Permission, + PermissionName, + PermissionState, + PermissionStatus, Permissions } from "./permissions.ts"; export { truncateSync, truncate } from "./truncate.ts"; diff --git a/cli/js/dispatch.ts b/cli/js/dispatch.ts index 38405a866..d66467011 100644 --- a/cli/js/dispatch.ts +++ b/cli/js/dispatch.ts @@ -36,7 +36,7 @@ export let OP_GET_RANDOM_VALUES: number; export let OP_GLOBAL_TIMER_STOP: number; export let OP_GLOBAL_TIMER: number; export let OP_NOW: number; -export let OP_PERMISSIONS: number; +export let OP_QUERY_PERMISSION: number; export let OP_REVOKE_PERMISSION: number; export let OP_CREATE_WORKER: number; export let OP_HOST_GET_WORKER_CLOSED: number; diff --git a/cli/js/errors.ts b/cli/js/errors.ts index 02ddfa2f2..8cd7a76be 100644 --- a/cli/js/errors.ts +++ b/cli/js/errors.ts @@ -75,5 +75,6 @@ export enum ErrorKind { UnsupportedFetchScheme = 47, TooManyRedirects = 48, Diagnostic = 49, - JSError = 50 + JSError = 50, + TypeError = 51 } diff --git a/cli/js/lib.deno_runtime.d.ts b/cli/js/lib.deno_runtime.d.ts index 3036ea2d1..c0bebf461 100644 --- a/cli/js/lib.deno_runtime.d.ts +++ b/cli/js/lib.deno_runtime.d.ts @@ -883,34 +883,64 @@ declare namespace Deno { } // @url js/permissions.d.ts + /** Permissions as granted by the caller + * See: https://w3c.github.io/permissions/#permission-registry + */ + export type PermissionName = + | "run" + | "read" + | "write" + | "net" + | "env" + | "hrtime"; + /** https://w3c.github.io/permissions/#status-of-a-permission */ + export type PermissionState = "granted" | "denied" | "prompt"; + interface RunPermissionDescriptor { + name: "run"; + } + interface ReadWritePermissionDescriptor { + name: "read" | "write"; + path?: string; + } + interface NetPermissionDescriptor { + name: "net"; + url?: string; + } + interface EnvPermissionDescriptor { + name: "env"; + } + interface HrtimePermissionDescriptor { + name: "hrtime"; + } + /** See: https://w3c.github.io/permissions/#permission-descriptor */ + type PermissionDescriptor = + | RunPermissionDescriptor + | ReadWritePermissionDescriptor + | NetPermissionDescriptor + | EnvPermissionDescriptor + | HrtimePermissionDescriptor; + + export class Permissions { + /** Queries the permission. + * const status = await Deno.permissions.query({ name: "read", path: "/etc" }); + * if (status.state === "granted") { + * data = await Deno.readFile("/etc/passwd"); + * } + */ + query(d: PermissionDescriptor): Promise<PermissionStatus>; + /** Revokes the permission. + * const status = await Deno.permissions.revoke({ name: "run" }); + * assert(status.state !== "granted") + */ + revoke(d: PermissionDescriptor): Promise<PermissionStatus>; + } + export const permissions: Permissions; - /** Permissions as granted by the caller */ - export interface Permissions { - read: boolean; - write: boolean; - net: boolean; - env: boolean; - run: boolean; - hrtime: boolean; - } - export type Permission = keyof Permissions; - /** Inspect granted permissions for the current program. - * - * if (Deno.permissions().read) { - * const file = await Deno.readFile("example.test"); - * // ... - * } - */ - export function permissions(): Permissions; - /** Revoke a permission. When the permission was already revoked nothing changes - * - * if (Deno.permissions().read) { - * const file = await Deno.readFile("example.test"); - * Deno.revokePermission('read'); - * } - * Deno.readFile("example.test"); // -> error or permission prompt - */ - export function revokePermission(permission: Permission): void; + /** https://w3c.github.io/permissions/#permissionstatus */ + export class PermissionStatus { + state: PermissionState; + constructor(state: PermissionState); + } // @url js/truncate.d.ts diff --git a/cli/js/permissions.ts b/cli/js/permissions.ts index 4f393501c..16ea3e5c2 100644 --- a/cli/js/permissions.ts +++ b/cli/js/permissions.ts @@ -2,38 +2,72 @@ import * as dispatch from "./dispatch.ts"; import { sendSync } from "./dispatch_json.ts"; -/** Permissions as granted by the caller */ -export interface Permissions { - read: boolean; - write: boolean; - net: boolean; - env: boolean; - run: boolean; - hrtime: boolean; - // NOTE: Keep in sync with src/permissions.rs -} +/** Permissions as granted by the caller + * See: https://w3c.github.io/permissions/#permission-registry + */ +export type PermissionName = + | "read" + | "write" + | "net" + | "env" + | "run" + | "hrtime"; +// NOTE: Keep in sync with cli/permissions.rs -export type Permission = keyof Permissions; +/** https://w3c.github.io/permissions/#status-of-a-permission */ +export type PermissionState = "granted" | "denied" | "prompt"; -/** Inspect granted permissions for the current program. - * - * if (Deno.permissions().read) { - * const file = await Deno.readFile("example.test"); - * // ... - * } - */ -export function permissions(): Permissions { - return sendSync(dispatch.OP_PERMISSIONS) as Permissions; +interface RunPermissionDescriptor { + name: "run"; +} +interface ReadWritePermissionDescriptor { + name: "read" | "write"; + path?: string; +} +interface NetPermissionDescriptor { + name: "net"; + url?: string; +} +interface EnvPermissionDescriptor { + name: "env"; } +interface HrtimePermissionDescriptor { + name: "hrtime"; +} +/** See: https://w3c.github.io/permissions/#permission-descriptor */ +type PermissionDescriptor = + | RunPermissionDescriptor + | ReadWritePermissionDescriptor + | NetPermissionDescriptor + | EnvPermissionDescriptor + | HrtimePermissionDescriptor; -/** Revoke a permission. When the permission was already revoked nothing changes - * - * if (Deno.permissions().read) { - * const file = await Deno.readFile("example.test"); - * Deno.revokePermission('read'); - * } - * Deno.readFile("example.test"); // -> error or permission prompt - */ -export function revokePermission(permission: Permission): void { - sendSync(dispatch.OP_REVOKE_PERMISSION, { permission }); +/** https://w3c.github.io/permissions/#permissionstatus */ +export class PermissionStatus { + constructor(public state: PermissionState) {} + // TODO(kt3k): implement onchange handler +} + +export class Permissions { + /** Queries the permission. + * const status = await Deno.permissions.query({ name: "read", path: "/etc" }); + * if (status.state === "granted") { + * file = await Deno.readFile("/etc/passwd"); + * } + */ + async query(desc: PermissionDescriptor): Promise<PermissionStatus> { + const { state } = sendSync(dispatch.OP_QUERY_PERMISSION, desc); + return new PermissionStatus(state); + } + + /** Revokes the permission. + * const status = await Deno.permissions.revoke({ name: "run" }); + * assert(status.state !== "granted") + */ + async revoke(desc: PermissionDescriptor): Promise<PermissionStatus> { + const { state } = sendSync(dispatch.OP_REVOKE_PERMISSION, desc); + return new PermissionStatus(state); + } } + +export const permissions = new Permissions(); diff --git a/cli/js/permissions_test.ts b/cli/js/permissions_test.ts index 6511c2dcb..d9ba538f0 100644 --- a/cli/js/permissions_test.ts +++ b/cli/js/permissions_test.ts @@ -1,7 +1,7 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { testPerm, assert, assertEquals } from "./test_util.ts"; +import { test, testPerm, assert, assertEquals } from "./test_util.ts"; -const knownPermissions: Deno.Permission[] = [ +const knownPermissions: Deno.PermissionName[] = [ "run", "read", "write", @@ -11,18 +11,31 @@ const knownPermissions: Deno.Permission[] = [ ]; for (const grant of knownPermissions) { - testPerm({ [grant]: true }, function envGranted(): void { - const perms = Deno.permissions(); - assert(perms !== null); - for (const perm in perms) { - assertEquals(perms[perm], perm === grant); - } + testPerm({ [grant]: true }, async function envGranted(): Promise<void> { + const status0 = await Deno.permissions.query({ name: grant }); + assert(status0 != null); + assertEquals(status0.state, "granted"); - Deno.revokePermission(grant); - - const revoked = Deno.permissions(); - for (const perm in revoked) { - assertEquals(revoked[perm], false); - } + const status1 = await Deno.permissions.revoke({ name: grant }); + assert(status1 != null); + assertEquals(status1.state, "prompt"); }); } + +test(async function permissionInvalidName(): Promise<void> { + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + await Deno.permissions.query({ name: "foo" as any }); + } catch (e) { + assert(e.name === "TypeError"); + } +}); + +test(async function permissionNetInvalidUrl(): Promise<void> { + try { + // Invalid url causes TypeError. + await Deno.permissions.query({ name: "net", url: ":" }); + } catch (e) { + assert(e.name === "TypeError"); + } +}); diff --git a/cli/js/test_util.ts b/cli/js/test_util.ts index 2f2916e11..85fffabe6 100644 --- a/cli/js/test_util.ts +++ b/cli/js/test_util.ts @@ -29,11 +29,34 @@ interface TestPermissions { hrtime?: boolean; } -const processPerms = Deno.permissions(); +export interface Permissions { + read: boolean; + write: boolean; + net: boolean; + env: boolean; + run: boolean; + hrtime: boolean; +} + +const isGranted = async (name: Deno.PermissionName): Promise<boolean> => + (await Deno.permissions.query({ name })).state === "granted"; + +async function getProcessPermissions(): Promise<Permissions> { + return { + run: await isGranted("run"), + read: await isGranted("read"), + write: await isGranted("write"), + net: await isGranted("net"), + env: await isGranted("env"), + hrtime: await isGranted("hrtime") + }; +} + +const processPerms = await getProcessPermissions(); function permissionsMatch( - processPerms: Deno.Permissions, - requiredPerms: Deno.Permissions + processPerms: Permissions, + requiredPerms: Permissions ): boolean { for (const permName in processPerms) { if (processPerms[permName] !== requiredPerms[permName]) { @@ -44,9 +67,9 @@ function permissionsMatch( return true; } -export const permissionCombinations: Map<string, Deno.Permissions> = new Map(); +export const permissionCombinations: Map<string, Permissions> = new Map(); -function permToString(perms: Deno.Permissions): string { +function permToString(perms: Permissions): string { const r = perms.read ? 1 : 0; const w = perms.write ? 1 : 0; const n = perms.net ? 1 : 0; @@ -56,14 +79,14 @@ function permToString(perms: Deno.Permissions): string { return `permR${r}W${w}N${n}E${e}U${u}H${h}`; } -function registerPermCombination(perms: Deno.Permissions): void { +function registerPermCombination(perms: Permissions): void { const key = permToString(perms); if (!permissionCombinations.has(key)) { permissionCombinations.set(key, perms); } } -function normalizeTestPermissions(perms: TestPermissions): Deno.Permissions { +function normalizeTestPermissions(perms: TestPermissions): Permissions { return { read: !!perms.read, write: !!perms.write, diff --git a/cli/js/unit_test_runner.ts b/cli/js/unit_test_runner.ts index 913c575b2..ae255c385 100755 --- a/cli/js/unit_test_runner.ts +++ b/cli/js/unit_test_runner.ts @@ -1,7 +1,11 @@ #!/usr/bin/env -S deno run --reload --allow-run // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. import "./unit_tests.ts"; -import { permissionCombinations, parseUnitTestOutput } from "./test_util.ts"; +import { + permissionCombinations, + parseUnitTestOutput, + Permissions +} from "./test_util.ts"; interface TestResult { perms: string; @@ -9,7 +13,7 @@ interface TestResult { result: number; } -function permsToCliFlags(perms: Deno.Permissions): string[] { +function permsToCliFlags(perms: Permissions): string[] { return Object.keys(perms) .map( (key): string => { @@ -25,7 +29,7 @@ function permsToCliFlags(perms: Deno.Permissions): string[] { .filter((e): boolean => e.length > 0); } -function fmtPerms(perms: Deno.Permissions): string { +function fmtPerms(perms: Permissions): string { let fmt = permsToCliFlags(perms).join(" "); if (!fmt) { |