@dwk/solid-pod 0.1.0-beta.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 +15 -0
- package/README.md +108 -0
- package/dist/auth.d.ts +33 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +160 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +181 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/encoding.d.ts +13 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +31 -0
- package/dist/encoding.js.map +1 -0
- package/dist/gc.d.ts +22 -0
- package/dist/gc.d.ts.map +1 -0
- package/dist/gc.js +33 -0
- package/dist/gc.js.map +1 -0
- package/dist/handler.d.ts +20 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +155 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/jwt.d.ts +36 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +120 -0
- package/dist/jwt.js.map +1 -0
- package/dist/ldp.d.ts +37 -0
- package/dist/ldp.d.ts.map +1 -0
- package/dist/ldp.js +85 -0
- package/dist/ldp.js.map +1 -0
- package/dist/log.d.ts +55 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +51 -0
- package/dist/log.js.map +1 -0
- package/dist/negotiation.d.ts +23 -0
- package/dist/negotiation.d.ts.map +1 -0
- package/dist/negotiation.js +80 -0
- package/dist/negotiation.js.map +1 -0
- package/dist/patch.d.ts +80 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +425 -0
- package/dist/patch.js.map +1 -0
- package/dist/pod.d.ts +20 -0
- package/dist/pod.d.ts.map +1 -0
- package/dist/pod.js +860 -0
- package/dist/pod.js.map +1 -0
- package/dist/wac.d.ts +33 -0
- package/dist/wac.d.ts.map +1 -0
- package/dist/wac.js +84 -0
- package/dist/wac.js.map +1 -0
- package/package.json +55 -0
- package/src/auth.ts +203 -0
- package/src/config.ts +254 -0
- package/src/encoding.ts +32 -0
- package/src/gc.ts +47 -0
- package/src/handler.ts +199 -0
- package/src/index.ts +32 -0
- package/src/jwt.ts +166 -0
- package/src/ldp.ts +99 -0
- package/src/log.ts +59 -0
- package/src/negotiation.ts +97 -0
- package/src/patch.ts +539 -0
- package/src/pod.ts +1195 -0
- package/src/wac.ts +119 -0
package/src/wac.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Access Control enforcement: resolve the effective `.acl` for a resource
|
|
3
|
+
* from the DO quad store, then defer the decision to `@dwk/wac`.
|
|
4
|
+
*
|
|
5
|
+
* The effective-ACL walk is the WAC algorithm: a resource's own `.acl`
|
|
6
|
+
* (`acl:accessTo`) is authoritative when present; otherwise the nearest
|
|
7
|
+
* ancestor container's `.acl` applies via `acl:default`. We read only the one
|
|
8
|
+
* effective document and hand it to `@dwk/wac`, which performs the mode/agent
|
|
9
|
+
* matching. ACL state lives in strongly-consistent DO SQLite, so no decision is
|
|
10
|
+
* ever cached.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { Store } from "@dwk/store";
|
|
14
|
+
import {
|
|
15
|
+
evaluateAccess,
|
|
16
|
+
type AccessDecision,
|
|
17
|
+
type AccessMode,
|
|
18
|
+
type AccessRequest,
|
|
19
|
+
type AclQuad,
|
|
20
|
+
type AclResource,
|
|
21
|
+
} from "@dwk/wac";
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
aclPath,
|
|
25
|
+
ancestorContainers,
|
|
26
|
+
isAclPath,
|
|
27
|
+
resourceForAcl,
|
|
28
|
+
toIri,
|
|
29
|
+
} from "./ldp";
|
|
30
|
+
|
|
31
|
+
/** Map the store's quads for an ACL document into `@dwk/wac` input. */
|
|
32
|
+
function toAclQuads(store: Store, aclKey: string): AclQuad[] {
|
|
33
|
+
return store.readQuads(aclKey).map((q) => ({
|
|
34
|
+
subject: q.subject.value,
|
|
35
|
+
predicate: q.predicate.value,
|
|
36
|
+
object: q.object,
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Build the single effective ACL document for `path`, or `null` when no `.acl`
|
|
42
|
+
* governs it anywhere up to the root (default-deny).
|
|
43
|
+
*/
|
|
44
|
+
function effectiveAcl(
|
|
45
|
+
store: Store,
|
|
46
|
+
origin: string,
|
|
47
|
+
path: string,
|
|
48
|
+
): AclResource | null {
|
|
49
|
+
const ownAcl = aclPath(path);
|
|
50
|
+
if (store.head(ownAcl)) {
|
|
51
|
+
return {
|
|
52
|
+
target: toIri(origin, path),
|
|
53
|
+
scope: "accessTo",
|
|
54
|
+
quads: toAclQuads(store, ownAcl),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
for (const container of ancestorContainers(path)) {
|
|
58
|
+
const containerAcl = aclPath(container);
|
|
59
|
+
if (store.head(containerAcl)) {
|
|
60
|
+
return {
|
|
61
|
+
target: toIri(origin, container),
|
|
62
|
+
scope: "default",
|
|
63
|
+
quads: toAclQuads(store, containerAcl),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Authorize a request against the effective ACL for `path`. Returns the
|
|
72
|
+
* `@dwk/wac` decision; with no governing ACL the result is a default-deny.
|
|
73
|
+
*/
|
|
74
|
+
export function authorize(
|
|
75
|
+
store: Store,
|
|
76
|
+
origin: string,
|
|
77
|
+
path: string,
|
|
78
|
+
request: AccessRequest,
|
|
79
|
+
): AccessDecision {
|
|
80
|
+
const acl = effectiveAcl(store, origin, path);
|
|
81
|
+
if (acl === null) return { granted: false, modes: [] };
|
|
82
|
+
return evaluateAccess(request, [acl]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* For each agent context (a WebID, or `undefined` for the public), the set of
|
|
87
|
+
* access modes the effective ACL grants over `path`. Used to populate the
|
|
88
|
+
* `WAC-Allow` header, which needs both the authenticated agent's and the
|
|
89
|
+
* public's privileges — resolving the effective ACL once and evaluating every
|
|
90
|
+
* context against it avoids re-walking the container hierarchy and re-reading
|
|
91
|
+
* the store per agent.
|
|
92
|
+
*
|
|
93
|
+
* Mirrors the `.acl`-path remapping the handler applies before authorizing: a
|
|
94
|
+
* request against an ACL document is decided by Control on the resource it
|
|
95
|
+
* governs. `@dwk/wac` reports the full granted mode set on any decision, so the
|
|
96
|
+
* requested `mode` here only seeds the evaluation — `read` is a safe probe.
|
|
97
|
+
*/
|
|
98
|
+
export function grantedModes(
|
|
99
|
+
store: Store,
|
|
100
|
+
origin: string,
|
|
101
|
+
path: string,
|
|
102
|
+
agents: ReadonlyArray<string | undefined>,
|
|
103
|
+
requestOrigin: string | undefined,
|
|
104
|
+
): Set<AccessMode>[] {
|
|
105
|
+
const wacPath = isAclPath(path) ? resourceForAcl(path) : path;
|
|
106
|
+
const acl = effectiveAcl(store, origin, wacPath);
|
|
107
|
+
return agents.map((agent) => {
|
|
108
|
+
if (acl === null) return new Set<AccessMode>();
|
|
109
|
+
const decision = evaluateAccess(
|
|
110
|
+
{
|
|
111
|
+
mode: "read",
|
|
112
|
+
...(agent ? { agent } : {}),
|
|
113
|
+
...(requestOrigin ? { origin: requestOrigin } : {}),
|
|
114
|
+
},
|
|
115
|
+
[acl],
|
|
116
|
+
);
|
|
117
|
+
return new Set(decision.modes);
|
|
118
|
+
});
|
|
119
|
+
}
|