@statewalker/webrun-biscuit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +262 -0
- package/dist/authorizer.d.ts +112 -0
- package/dist/authorizer.d.ts.map +1 -0
- package/dist/base64.d.ts +3 -0
- package/dist/base64.d.ts.map +1 -0
- package/dist/builder.d.ts +52 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/crypto.d.ts +22 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/datalog.d.ts +203 -0
- package/dist/datalog.d.ts.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3130 -0
- package/dist/parser.d.ts +80 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/print.d.ts +12 -0
- package/dist/print.d.ts.map +1 -0
- package/dist/proto.d.ts +132 -0
- package/dist/proto.d.ts.map +1 -0
- package/dist/version.d.ts +42 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +58 -0
- package/src/authorizer.ts +581 -0
- package/src/base64.ts +42 -0
- package/src/builder.ts +360 -0
- package/src/crypto.ts +208 -0
- package/src/datalog.ts +722 -0
- package/src/index.ts +93 -0
- package/src/parser.ts +606 -0
- package/src/print.ts +147 -0
- package/src/proto.ts +770 -0
- package/src/version.ts +158 -0
package/src/print.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/** Datalog pretty-printer (used for error messages and world snapshots). */
|
|
2
|
+
import {
|
|
3
|
+
BinaryOp as B,
|
|
4
|
+
type Check,
|
|
5
|
+
type MapKey,
|
|
6
|
+
type Op,
|
|
7
|
+
type Predicate,
|
|
8
|
+
type Rule,
|
|
9
|
+
type Scope,
|
|
10
|
+
type Term,
|
|
11
|
+
UnaryOp as U,
|
|
12
|
+
} from "./datalog.js";
|
|
13
|
+
|
|
14
|
+
const hex = (b: Uint8Array): string =>
|
|
15
|
+
Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
16
|
+
|
|
17
|
+
/** Datalog string literal: only the quote and the backslash are escaped.
|
|
18
|
+
* Control characters are emitted raw, unlike JSON.stringify. */
|
|
19
|
+
const quote = (v: string): string => `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
20
|
+
|
|
21
|
+
export function printTerm(t: Term, varName: (id: number) => string): string {
|
|
22
|
+
switch (t.t) {
|
|
23
|
+
case "var":
|
|
24
|
+
return `$${varName(t.v)}`;
|
|
25
|
+
case "int":
|
|
26
|
+
return t.v.toString();
|
|
27
|
+
case "str":
|
|
28
|
+
return quote(t.v);
|
|
29
|
+
case "date":
|
|
30
|
+
return new Date(Number(t.v) * 1000).toISOString().replace(".000Z", "Z");
|
|
31
|
+
case "bytes":
|
|
32
|
+
return `hex:${hex(t.v)}`;
|
|
33
|
+
case "bool":
|
|
34
|
+
return t.v ? "true" : "false";
|
|
35
|
+
case "null":
|
|
36
|
+
return "null";
|
|
37
|
+
case "set":
|
|
38
|
+
return t.v.length === 0 ? "{,}" : `{${t.v.map((x) => printTerm(x, varName)).join(", ")}}`;
|
|
39
|
+
case "array":
|
|
40
|
+
return `[${t.v.map((x) => printTerm(x, varName)).join(", ")}]`;
|
|
41
|
+
case "map":
|
|
42
|
+
return t.v.length === 0
|
|
43
|
+
? "{}"
|
|
44
|
+
: `{${t.v.map(([k, v]: [MapKey, Term]) => `${k.t === "int" ? k.v : quote(k.v)}: ${printTerm(v, varName)}`).join(", ")}}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const printPredicate = (p: Predicate, varName: (id: number) => string): string =>
|
|
49
|
+
`${p.name}(${p.terms.map((t) => printTerm(t, varName)).join(", ")})`;
|
|
50
|
+
|
|
51
|
+
const UNARY: Record<number, (a: string) => string> = {
|
|
52
|
+
[U.Negate]: (a) => `!${a}`,
|
|
53
|
+
[U.Parens]: (a) => `(${a})`,
|
|
54
|
+
[U.Length]: (a) => `${a}.length()`,
|
|
55
|
+
[U.TypeOf]: (a) => `${a}.type()`,
|
|
56
|
+
};
|
|
57
|
+
const BINARY: Record<number, (a: string, b: string) => string> = {
|
|
58
|
+
[B.LessThan]: (a, b) => `${a} < ${b}`,
|
|
59
|
+
[B.GreaterThan]: (a, b) => `${a} > ${b}`,
|
|
60
|
+
[B.LessOrEqual]: (a, b) => `${a} <= ${b}`,
|
|
61
|
+
[B.GreaterOrEqual]: (a, b) => `${a} >= ${b}`,
|
|
62
|
+
[B.Equal]: (a, b) => `${a} === ${b}`,
|
|
63
|
+
[B.NotEqual]: (a, b) => `${a} !== ${b}`,
|
|
64
|
+
[B.HeterogeneousEqual]: (a, b) => `${a} == ${b}`,
|
|
65
|
+
[B.HeterogeneousNotEqual]: (a, b) => `${a} != ${b}`,
|
|
66
|
+
[B.Contains]: (a, b) => `${a}.contains(${b})`,
|
|
67
|
+
[B.Prefix]: (a, b) => `${a}.starts_with(${b})`,
|
|
68
|
+
[B.Suffix]: (a, b) => `${a}.ends_with(${b})`,
|
|
69
|
+
[B.Regex]: (a, b) => `${a}.matches(${b})`,
|
|
70
|
+
[B.Add]: (a, b) => `${a} + ${b}`,
|
|
71
|
+
[B.Sub]: (a, b) => `${a} - ${b}`,
|
|
72
|
+
[B.Mul]: (a, b) => `${a} * ${b}`,
|
|
73
|
+
[B.Div]: (a, b) => `${a} / ${b}`,
|
|
74
|
+
[B.And]: (a, b) => `${a} &&! ${b}`,
|
|
75
|
+
[B.Or]: (a, b) => `${a} ||! ${b}`,
|
|
76
|
+
[B.Intersection]: (a, b) => `${a}.intersection(${b})`,
|
|
77
|
+
[B.Union]: (a, b) => `${a}.union(${b})`,
|
|
78
|
+
[B.BitwiseAnd]: (a, b) => `${a} & ${b}`,
|
|
79
|
+
[B.BitwiseOr]: (a, b) => `${a} | ${b}`,
|
|
80
|
+
[B.BitwiseXor]: (a, b) => `${a} ^ ${b}`,
|
|
81
|
+
[B.LazyAnd]: (a, b) => `${a} && ${b}`,
|
|
82
|
+
[B.LazyOr]: (a, b) => `${a} || ${b}`,
|
|
83
|
+
[B.All]: (a, b) => `${a}.all(${b})`,
|
|
84
|
+
[B.Any]: (a, b) => `${a}.any(${b})`,
|
|
85
|
+
[B.Get]: (a, b) => `${a}.get(${b})`,
|
|
86
|
+
[B.TryOr]: (a, b) => `${a}.try_or(${b})`,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export function printExpression(ops: Op[], varName: (id: number) => string): string {
|
|
90
|
+
const stack: string[] = [];
|
|
91
|
+
for (const op of ops) {
|
|
92
|
+
if (op.kind === "value") stack.push(printTerm(op.value, varName));
|
|
93
|
+
else if (op.kind === "closure")
|
|
94
|
+
stack.push(
|
|
95
|
+
`${op.params.map((p) => `$${varName(p)}`).join(", ")}${op.params.length ? " -> " : ""}${printExpression(op.ops, varName)}`,
|
|
96
|
+
);
|
|
97
|
+
else if (op.kind === "unary") {
|
|
98
|
+
const a = stack.pop() ?? "";
|
|
99
|
+
stack.push(op.ffi ? `${a}.extern::${op.ffi}()` : (UNARY[op.op]?.(a) ?? a));
|
|
100
|
+
} else {
|
|
101
|
+
const b = stack.pop() ?? "";
|
|
102
|
+
const a = stack.pop() ?? "";
|
|
103
|
+
stack.push(
|
|
104
|
+
op.ffi ? `${a}.extern::${op.ffi}(${b})` : (BINARY[op.op]?.(a, b) ?? `${a} ? ${b}`),
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return stack.join(" ");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function printScopes(scopes: Scope[]): string {
|
|
112
|
+
if (scopes.length === 0) return "";
|
|
113
|
+
const parts = scopes.map((s) =>
|
|
114
|
+
s.kind === "authority" ? "authority" : s.kind === "previous" ? "previous" : s.key,
|
|
115
|
+
);
|
|
116
|
+
return ` trusting ${parts.join(", ")}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** the body of a rule, check or policy: predicates, then expressions */
|
|
120
|
+
export function printQuery(r: Rule, varName: (id: number) => string): string {
|
|
121
|
+
const parts = [
|
|
122
|
+
...r.body.map((p) => printPredicate(p, varName)),
|
|
123
|
+
...r.expressions.map((e) => printExpression(e, varName)),
|
|
124
|
+
];
|
|
125
|
+
return parts.join(", ") + printScopes(r.scopes);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function printCheck(c: Check, varName: (id: number) => string): string {
|
|
129
|
+
const head = c.kind === "all" ? "check all " : c.kind === "reject" ? "reject if " : "check if ";
|
|
130
|
+
return head + c.queries.map((q) => printQuery(q, varName)).join(" or ");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function printPolicy(
|
|
134
|
+
kind: "allow" | "deny",
|
|
135
|
+
queries: Rule[],
|
|
136
|
+
varName: (id: number) => string,
|
|
137
|
+
): string {
|
|
138
|
+
return `${kind} if ` + queries.map((q) => printQuery(q, varName)).join(" or ");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function printRule(r: Rule, varName: (id: number) => string): string {
|
|
142
|
+
const parts = [
|
|
143
|
+
...r.body.map((p) => printPredicate(p, varName)),
|
|
144
|
+
...r.expressions.map((e) => printExpression(e, varName)),
|
|
145
|
+
];
|
|
146
|
+
return `${printPredicate(r.head, varName)} <- ${parts.join(", ")}` + printScopes(r.scopes);
|
|
147
|
+
}
|