~james/core

core/web/src/lib/auth/scopes.test.ts -rw-r--r-- 2.5 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { describe, expect, it } from "vitest";
import { missingPermissions, type Permission } from "#lib/auth/scopes.ts";

const KNOT = "did:web:knot.example.com";

const write: Permission = {
	resource: "repo",
	collection: "sh.tangled.repo.collaboratorAcceptance",
	actions: ["create", "update"]
};

const call: Permission = {
	resource: "rpc",
	lxm: "sh.tangled.repo.acceptCollaboration",
	aud: KNOT
};

const wanted = [write, call];

const handle: Permission = { resource: "identity", attr: "handle" };

const covering: [string, readonly Permission[]][] = [
	["repo:sh.tangled.repo.collaboratorAcceptance", [write]],
	["repo?collection=sh.tangled.repo.collaboratorAcceptance", [write]],
	["repo:*", [write]],
	[
		"repo:sh.tangled.repo.collaboratorAcceptance?action=create&action=update&action=delete",
		[write]
	],
	["rpc:sh.tangled.repo.acceptCollaboration?aud=*", [call]],
	[`rpc?lxm=sh.tangled.repo.acceptCollaboration&aud=${KNOT}`, [call]],
	[
		`rpc:sh.tangled.repo.acceptCollaboration?aud=${KNOT}%23tangled_knot`,
		[{ ...call, aud: `${KNOT}#tangled_knot` }]
	],
	[`rpc:*?aud=${KNOT}`, [call]],
	["identity:handle", [handle]],
	["identity:*", [handle]],
	["identity?attr=handle", [handle]],
	["atproto include:sh.tangled.authKnot", wanted],
	["atproto transition:generic", wanted]
];

const coveringNothing: [string, readonly Permission[]][] = [
	["repo", [write]],
	["repo:", [write]],
	["repo?action=create", [write]],
	["repo:sh.tangled.knot.member", [write]],
	["repo:sh.tangled.repo.collaboratorAcceptance?action=create", [write]],
	["rpc:sh.tangled.repo.acceptCollaboration", [call]],
	["rpc?lxm=sh.tangled.repo.acceptCollaboration", [call]],
	["rpc:sh.tangled.knot.*?aud=*", [call]],
	["rpc:sh.tangled.knot.addMember?aud=*", wanted],
	["", wanted],
	["identity", [handle]],
	["identity:", [handle]],
	["atproto repo:* rpc:*?aud=*", [handle]],
	["atproto repo:sh.tangled.knot repo:sh.tangled.knot.member blob:*/*", wanted]
];

describe("a granted scope", () => {
	it.each(covering)("covers %s", (granted, permissions) => {
		expect(missingPermissions(granted, permissions)).toEqual([]);
	});

	it.each(coveringNothing)("covers nothing under %s", (granted, missing) => {
		expect(missingPermissions(granted, missing)).toEqual(missing);
	});

	it("covers its own audience and nobody else's", () => {
		const mine = `rpc?lxm=sh.tangled.repo.acceptCollaboration&aud=${KNOT}`;
		const theirs = "rpc?lxm=sh.tangled.repo.acceptCollaboration&aud=did:web:other.example";

		expect(missingPermissions(mine, [call])).toEqual([]);
		expect(missingPermissions(theirs, [call])).toEqual([call]);
	});
});