char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somport base extension to typescript9cca521

main
2.5 KiB84 linesraw
1import {
2  ArrayIsArray,
3  ArrayPrototypePush,
4  ObjectSetPrototypeOf,
5  ReflectOwnKeys,
6  TypeError,
7} from "ext:core/primordials";
8import { op_pledge } from "ext:core/ops";
9import { usv } from "ext:web/idl.js";
10
11const categories = [
12  "net",
13  "read",
14  "write",
15  "jsExec",
16  "env",
17  "sys",
18  "run",
19  "ffi",
20] as const;
21export type PledgeRow = [
22  category: typeof categories[number],
23  allow: string[] | null,
24  deny: string[],
25];
26function object(value: unknown): value is Record<PropertyKey, unknown> {
27  return value !== null &&
28    (typeof value === "object" || typeof value === "function");
29}
30function keys(value: object, allowed: readonly string[]): void {
31  const names = ReflectOwnKeys(value);
32  for (let index = 0; index < names.length; index++) {
33    let known = false;
34    for (let key = 0; key < allowed.length; key++) {
35      if (names[index] === allowed[key]) known = true;
36    }
37    if (!known) throw new TypeError("Unknown pledge member");
38  }
39}
40function list(value: unknown): string[] | null {
41  if (value === undefined) return null;
42  if (!ArrayIsArray(value)) throw new TypeError("Pledge grants must be arrays");
43  const result: string[] = [];
44  ObjectSetPrototypeOf(result, null);
45  const length = value.length;
46  for (let index = 0; index < length; index++) {
47    const item = value[index];
48    ArrayPrototypePush(result, usv(item));
49  }
50  return result;
51}
52export function preparePledge(restrictions: unknown): PledgeRow[] {
53  if (!object(restrictions) || ArrayIsArray(restrictions)) {
54    throw new TypeError("Pledge requires a restrictions object");
55  }
56  keys(restrictions, categories);
57  const request: PledgeRow[] = [];
58  ObjectSetPrototypeOf(request, null);
59  for (let index = 0; index < categories.length; index++) {
60    const category = categories[index];
61    const value = restrictions[category];
62    if (value === undefined) continue;
63    let allow: string[] | null, deny: string[];
64    if (value === false) {
65      allow = [];
66      deny = [];
67    } else {
68      if (!object(value) || ArrayIsArray(value)) {
69        throw new TypeError(
70          "Pledge restrictions must be false or { allow, deny }",
71        );
72      }
73      keys(value, ["allow", "deny"]);
74      allow = list(value.allow);
75      deny = list(value.deny) ?? [];
76    }
77    ArrayPrototypePush(request, [category, allow, deny]);
78  }
79  return request;
80}
81export function pledge(restrictions: unknown): void {
82  const error = op_pledge(preparePledge(restrictions));
83  if (error !== null) throw new TypeError(error);
84}