Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add sync APIs for "Deno.permissions" #17019

Merged
merged 30 commits into from
Jan 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f8f58ec
feat: Deno.permissions.querySync()
iuioiua Dec 12, 2022
feb5090
fmt
iuioiua Dec 12, 2022
0fe6e4c
lint
iuioiua Dec 12, 2022
fc709fa
refactor: revert formDescriptor utility
iuioiua Dec 12, 2022
52ff542
more tests
iuioiua Dec 12, 2022
c70039b
format
iuioiua Dec 12, 2022
359edb0
feat: add revokeSync() and requestSync()
iuioiua Dec 13, 2022
f3de1e1
fix: requestSync()
iuioiua Dec 13, 2022
35aadcb
reset tests
iuioiua Dec 13, 2022
00c6bad
reset tests II
iuioiua Dec 13, 2022
8bc3646
tests
iuioiua Dec 13, 2022
259b468
Merge branch 'main' into Deno.permissions.querySync()
iuioiua Dec 13, 2022
b2ffdd1
fix
iuioiua Dec 13, 2022
9ebad97
Merge branch 'main' into Deno.permissions.querySync()
iuioiua Dec 13, 2022
d997e3c
Merge branch 'denoland:main' into Deno.permissions.querySync()
iuioiua Dec 20, 2022
896523d
Merge branch 'main' into Deno.permissions.querySync()
iuioiua Jan 3, 2023
54a488e
refactor: use formDescriptor
iuioiua Jan 3, 2023
f76df99
revert type changes
iuioiua Jan 4, 2023
9fd417f
Merge branch 'main' into Deno.permissions.querySync()
iuioiua Jan 11, 2023
451f6bf
Merge branch 'main' into Deno.permissions.querySync()
iuioiua Jan 11, 2023
9bacc1f
Merge branch 'denoland:main' into Deno.permissions.querySync()
iuioiua Jan 12, 2023
31ac7a4
fix conflicts
iuioiua Jan 15, 2023
6baa55e
revert
iuioiua Jan 15, 2023
9c2f33e
fix conflicts
iuioiua Jan 15, 2023
996615a
Merge branch 'main' into Deno.permissions.querySync()
iuioiua Jan 15, 2023
d60eb57
format
iuioiua Jan 15, 2023
aef6515
Merge branch 'main' into Deno.permissions.querySync()
bartlomieju Jan 17, 2023
cd588f0
Merge branch 'main' into Deno.permissions.querySync()
bartlomieju Jan 24, 2023
da489c3
revert
iuioiua Jan 24, 2023
f9f7406
cleanup
iuioiua Jan 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions cli/tests/integration/run_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,21 @@ fn _090_run_permissions_request() {
]);
}

#[test]
fn _090_run_permissions_request_sync() {
let args = "run --quiet run/090_run_permissions_request_sync.ts";
use util::PtyData::*;
util::test_pty2(args, vec![
Output("⚠️ ️Deno requests run access to \"ls\". Run again with --allow-run to bypass this prompt.\r\n Allow? [y/n (y = yes allow, n = no deny)]"),
Input("y\n"),
Output("⚠️ ️Deno requests run access to \"cat\". Run again with --allow-run to bypass this prompt.\r\n Allow? [y/n (y = yes allow, n = no deny)]"),
Input("n\n"),
Output("granted\r\n"),
Output("prompt\r\n"),
Output("denied\r\n"),
]);
}

itest!(_091_use_define_for_class_fields {
args: "run --check run/091_use_define_for_class_fields.ts",
output: "run/091_use_define_for_class_fields.ts.out",
Expand Down Expand Up @@ -2271,6 +2286,21 @@ mod permissions {
]);
}

#[test]
fn _061_permissions_request_sync() {
let args = "run --quiet run/061_permissions_request_sync.ts";
use util::PtyData::*;
util::test_pty2(args, vec![
Output("⚠️ ️Deno requests read access to \"foo\". Run again with --allow-read to bypass this prompt.\r\n Allow? [y/n (y = yes allow, n = no deny)] "),
Input("y\n"),
Output("⚠️ ️Deno requests read access to \"bar\". Run again with --allow-read to bypass this prompt.\r\n Allow? [y/n (y = yes allow, n = no deny)]"),
Input("n\n"),
Output("granted\r\n"),
Output("prompt\r\n"),
Output("denied\r\n"),
]);
}

#[test]
fn _062_permissions_request_global() {
let args = "run --quiet run/062_permissions_request_global.ts";
Expand All @@ -2284,16 +2314,39 @@ mod permissions {
]);
}

#[test]
fn _062_permissions_request_global_sync() {
let args = "run --quiet run/062_permissions_request_global_sync.ts";
use util::PtyData::*;
util::test_pty2(args, vec![
Output("⚠️ ️Deno requests read access. Run again with --allow-read to bypass this prompt.\r\n Allow? [y/n (y = yes allow, n = no deny)] "),
Input("y\n"),
Output("PermissionStatus { state: \"granted\", onchange: null }\r\n"),
Output("PermissionStatus { state: \"granted\", onchange: null }\r\n"),
Output("PermissionStatus { state: \"granted\", onchange: null }\r\n"),
]);
}

itest!(_063_permissions_revoke {
args: "run --allow-read=foo,bar run/063_permissions_revoke.ts",
output: "run/063_permissions_revoke.ts.out",
});

itest!(_063_permissions_revoke_sync {
args: "run --allow-read=foo,bar run/063_permissions_revoke_sync.ts",
output: "run/063_permissions_revoke.ts.out",
});

itest!(_064_permissions_revoke_global {
args: "run --allow-read=foo,bar run/064_permissions_revoke_global.ts",
output: "run/064_permissions_revoke_global.ts.out",
});

itest!(_064_permissions_revoke_global_sync {
args: "run --allow-read=foo,bar run/064_permissions_revoke_global_sync.ts",
output: "run/064_permissions_revoke_global.ts.out",
});

#[test]
fn _066_prompt() {
let args = "run --quiet --unstable run/066_prompt.ts";
Expand Down
8 changes: 8 additions & 0 deletions cli/tests/testdata/run/061_permissions_request_sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const status1 =
Deno.permissions.requestSync({ name: "read", path: "foo" }).state;
const status2 = Deno.permissions.querySync({ name: "read", path: "bar" }).state;
const status3 =
Deno.permissions.requestSync({ name: "read", path: "bar" }).state;
console.log(status1);
console.log(status2);
console.log(status3);
6 changes: 6 additions & 0 deletions cli/tests/testdata/run/062_permissions_request_global_sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const status1 = Deno.permissions.requestSync({ name: "read" });
console.log(status1);
const status2 = Deno.permissions.querySync({ name: "read", path: "foo" });
console.log(status2);
const status3 = Deno.permissions.querySync({ name: "read", path: "bar" });
console.log(status3);
6 changes: 6 additions & 0 deletions cli/tests/testdata/run/063_permissions_revoke_sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const status1 = Deno.permissions.revokeSync({ name: "read", path: "foo" });
console.log(status1);
const status2 = Deno.permissions.querySync({ name: "read", path: "bar" });
console.log(status2);
const status3 = Deno.permissions.revokeSync({ name: "read", path: "bar" });
console.log(status3);
6 changes: 6 additions & 0 deletions cli/tests/testdata/run/064_permissions_revoke_global_sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const status1 = Deno.permissions.revokeSync({ name: "read" });
console.log(status1);
const status2 = Deno.permissions.querySync({ name: "read", path: "foo" });
console.log(status2);
const status3 = Deno.permissions.querySync({ name: "read", path: "bar" });
console.log(status3);
18 changes: 18 additions & 0 deletions cli/tests/testdata/run/090_run_permissions_request_sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const status1 =
Deno.permissions.requestSync({ name: "run", command: "ls" }).state;
if (status1 != "granted") {
throw Error(`unexpected status1 ${status1}`);
}
const status2 =
Deno.permissions.querySync({ name: "run", command: "cat" }).state;
if (status2 != "prompt") {
throw Error(`unexpected status2 ${status2}`);
}
const status3 =
Deno.permissions.requestSync({ name: "run", command: "cat" }).state;
if (status3 != "denied") {
throw Error(`unexpected status3 ${status3}`);
}
console.log(status1);
console.log(status2);
console.log(status3);
91 changes: 91 additions & 0 deletions cli/tests/unit/permissions_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,25 @@ Deno.test(async function permissionInvalidName() {
}, TypeError);
});

Deno.test(function permissionInvalidNameSync() {
iuioiua marked this conversation as resolved.
Show resolved Hide resolved
assertThrows(() => {
// deno-lint-ignore no-explicit-any
Deno.permissions.querySync({ name: "foo" as any });
}, TypeError);
});

Deno.test(async function permissionNetInvalidHost() {
await assertRejects(async () => {
await Deno.permissions.query({ name: "net", host: ":" });
}, URIError);
});

Deno.test(function permissionNetInvalidHostSync() {
assertThrows(() => {
Deno.permissions.querySync({ name: "net", host: ":" });
}, URIError);
});

Deno.test(async function permissionSysValidKind() {
await Deno.permissions.query({ name: "sys", kind: "loadavg" });
await Deno.permissions.query({ name: "sys", kind: "osRelease" });
Expand All @@ -30,13 +43,30 @@ Deno.test(async function permissionSysValidKind() {
await Deno.permissions.query({ name: "sys", kind: "gid" });
});

Deno.test(function permissionSysValidKindSync() {
Deno.permissions.querySync({ name: "sys", kind: "loadavg" });
Deno.permissions.querySync({ name: "sys", kind: "osRelease" });
Deno.permissions.querySync({ name: "sys", kind: "networkInterfaces" });
Deno.permissions.querySync({ name: "sys", kind: "systemMemoryInfo" });
Deno.permissions.querySync({ name: "sys", kind: "hostname" });
Deno.permissions.querySync({ name: "sys", kind: "uid" });
Deno.permissions.querySync({ name: "sys", kind: "gid" });
});

Deno.test(async function permissionSysInvalidKind() {
await assertRejects(async () => {
// deno-lint-ignore no-explicit-any
await Deno.permissions.query({ name: "sys", kind: "abc" as any });
}, TypeError);
});

Deno.test(function permissionSysInvalidKindSync() {
assertThrows(() => {
// deno-lint-ignore no-explicit-any
Deno.permissions.querySync({ name: "sys", kind: "abc" as any });
}, TypeError);
});

Deno.test(async function permissionQueryReturnsEventTarget() {
const status = await Deno.permissions.query({ name: "hrtime" });
assert(["granted", "denied", "prompt"].includes(status.state));
Expand All @@ -49,6 +79,18 @@ Deno.test(async function permissionQueryReturnsEventTarget() {
assert(status === (await Deno.permissions.query({ name: "hrtime" })));
});

Deno.test(function permissionQueryReturnsEventTargetSync() {
const status = Deno.permissions.querySync({ 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 === Deno.permissions.querySync({ name: "hrtime" }));
});

Deno.test(async function permissionQueryForReadReturnsSameStatus() {
const status1 = await Deno.permissions.query({
name: "read",
Expand All @@ -61,6 +103,18 @@ Deno.test(async function permissionQueryForReadReturnsSameStatus() {
assert(status1 === status2);
});

Deno.test(function permissionQueryForReadReturnsSameStatusSync() {
const status1 = Deno.permissions.querySync({
name: "read",
path: ".",
});
const status2 = Deno.permissions.querySync({
name: "read",
path: ".",
});
assert(status1 === status2);
});

Deno.test(function permissionsIllegalConstructor() {
assertThrows(() => new Deno.Permissions(), TypeError, "Illegal constructor.");
assertEquals(Deno.Permissions.length, 0);
Expand All @@ -85,6 +139,21 @@ Deno.test(async function permissionURL() {
await Deno.permissions.query({ name: "run", command: path });
});

Deno.test(function permissionURLSync() {
Deno.permissions.querySync({
name: "read",
path: new URL(".", import.meta.url),
});
Deno.permissions.querySync({
name: "write",
path: new URL(".", import.meta.url),
});
Deno.permissions.querySync({
name: "run",
command: new URL(".", import.meta.url),
});
});

Deno.test(async function permissionDescriptorValidation() {
for (const value of [undefined, null, {}]) {
for (const method of ["query", "request", "revoke"]) {
Expand All @@ -100,10 +169,32 @@ Deno.test(async function permissionDescriptorValidation() {
}
});

Deno.test(function permissionDescriptorValidationSync() {
for (const value of [undefined, null, {}]) {
for (const method of ["querySync", "revokeSync", "requestSync"]) {
assertThrows(
() => {
// deno-lint-ignore no-explicit-any
(Deno.permissions as any)[method](value as any);
},
TypeError,
'"undefined" is not a valid permission name',
);
}
}
});

// Regression test for https://github.com/denoland/deno/issues/15894.
Deno.test(async function permissionStatusObjectsNotEqual() {
assert(
await Deno.permissions.query({ name: "env", variable: "A" }) !=
await Deno.permissions.query({ name: "env", variable: "B" }),
);
});

Deno.test(function permissionStatusObjectsNotEqualSync() {
assert(
Deno.permissions.querySync({ name: "env", variable: "A" }) !=
Deno.permissions.querySync({ name: "env", variable: "B" }),
);
});
63 changes: 63 additions & 0 deletions cli/tsc/dts/lib.deno.ns.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4279,6 +4279,20 @@ declare namespace Deno {
*/
query(desc: PermissionDescriptor): Promise<PermissionStatus>;

/** Returns the current status of a permission.
*
* Note, if the permission is already granted, `request()` will not prompt
* the user again, therefore `querySync()` is only necessary if you are going
* to react differently existing permissions without wanting to modify them
* or prompt the user to modify them.
*
* ```ts
* const status = Deno.permissions.querySync({ name: "read", path: "/etc" });
* console.log(status.state);
* ```
*/
querySync(desc: PermissionDescriptor): PermissionStatus;

/** Revokes a permission, and resolves to the state of the permission.
*
* ```ts
Expand All @@ -4290,6 +4304,17 @@ declare namespace Deno {
*/
revoke(desc: PermissionDescriptor): Promise<PermissionStatus>;

/** Revokes a permission, and returns the state of the permission.
*
* ```ts
* import { assert } from "https://deno.land/std/testing/asserts.ts";
*
* const status = Deno.permissions.revokeSync({ name: "run" });
* assert(status.state !== "granted")
* ```
*/
revokeSync(desc: PermissionDescriptor): PermissionStatus;

/** Requests the permission, and resolves to the state of the permission.
*
* If the permission is already granted, the user will not be prompted to
Expand All @@ -4305,6 +4330,23 @@ declare namespace Deno {
* ```
*/
request(desc: PermissionDescriptor): Promise<PermissionStatus>;


/** Requests the permission, and returns the state of the permission.
*
* If the permission is already granted, the user will not be prompted to
* grant the permission again.
*
* ```ts
* const status = Deno.permissions.requestSync({ name: "env" });
* if (status.state === "granted") {
* console.log("'env' permission is granted.");
* } else {
* console.log("'env' permission is denied.");
* }
* ```
*/
requestSync(desc: PermissionDescriptor): PermissionStatus;
}

/** Deno's permission management API.
Expand Down Expand Up @@ -4335,6 +4377,11 @@ declare namespace Deno {
* const status = await Deno.permissions.query({ name: "read", path: "/etc" });
* console.log(status.state);
* ```
*
* ```ts
* const status = Deno.permissions.querySync({ name: "read", path: "/etc" });
* console.log(status.state);
* ```
*
* ### Revoking
*
Expand All @@ -4344,6 +4391,13 @@ declare namespace Deno {
* const status = await Deno.permissions.revoke({ name: "run" });
* assert(status.state !== "granted")
* ```
*
* ```ts
* import { assert } from "https://deno.land/std/testing/asserts.ts";
*
* const status = Deno.permissions.revokeSync({ name: "run" });
* assert(status.state !== "granted")
* ```
*
* ### Requesting
*
Expand All @@ -4355,6 +4409,15 @@ declare namespace Deno {
* console.log("'env' permission is denied.");
* }
* ```
*
* ```ts
* const status = Deno.permissions.requestSync({ name: "env" });
* if (status.state === "granted") {
* console.log("'env' permission is granted.");
* } else {
* console.log("'env' permission is denied.");
* }
* ```
*
* @category Permissions
*/
Expand Down
Loading