Skip to content

Commit d5dc993

Browse files
authored
SR-184: WAC (#22)
1 parent dacbf93 commit d5dc993

8 files changed

Lines changed: 311 additions & 0 deletions

File tree

src/vocabulary/acl.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
export const ACL = {
2+
/**
3+
* Allows access to a class of append operations on a resource, e.g., to add information, but not remove, information on HTTP POST, PATCH requests.
4+
*
5+
* @see https://solidproject.org/TR/wac#acl-mode-append
6+
*/
7+
Append: "http://www.w3.org/ns/auth/acl#Append",
8+
9+
/**
10+
* Allows access to any authenticated agent.
11+
*
12+
* @see https://solidproject.org/TR/wac#acl-agentclass-authenticated-agent
13+
*/
14+
AuthenticatedAgent: "http://www.w3.org/ns/auth/acl#AuthenticatedAgent",
15+
16+
Authorization: "http://www.w3.org/ns/auth/acl#Authorization",
17+
18+
accessTo: "http://www.w3.org/ns/auth/acl#accessTo",
19+
20+
agent: "http://www.w3.org/ns/auth/acl#agent",
21+
22+
agentClass: "http://www.w3.org/ns/auth/acl#agentClass",
23+
24+
agentGroup: "http://www.w3.org/ns/auth/acl#agentGroup",
25+
26+
/**
27+
* Allows access to a class of read and write operations on an ACL resource associated with a resource.
28+
*
29+
* @see https://solidproject.org/TR/wac#acl-mode-control
30+
*/
31+
Control: "http://www.w3.org/ns/auth/acl#Control",
32+
33+
default: "http://www.w3.org/ns/auth/acl#default",
34+
35+
mode: "http://www.w3.org/ns/auth/acl#mode",
36+
37+
origin: "http://www.w3.org/ns/auth/acl#origin",
38+
39+
/**
40+
* Allows access to a class of read operations on a resource, e.g., to view the contents of a resource on HTTP GET requests.
41+
*
42+
* @see https://solidproject.org/TR/wac#acl-mode-read
43+
*/
44+
Read: "http://www.w3.org/ns/auth/acl#Read",
45+
46+
/**
47+
* Allows access to a class of write operations on a resource, e.g., to create, delete or modify resources on HTTP PUT, POST, PATCH, DELETE requests.
48+
*
49+
* @see https://solidproject.org/TR/wac#acl-mode-write
50+
*/
51+
Write: "http://www.w3.org/ns/auth/acl#Write",
52+
} as const;

src/vocabulary/foaf.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ export const FOAF = {
55
email: "http://xmlns.com/foaf/0.1/email",
66
homepage: "http://xmlns.com/foaf/0.1/homepage",
77
knows: "http://xmlns.com/foaf/0.1/knows",
8+
9+
/**
10+
* @remarks [When used in WAC](https://solidproject.org/TR/wac#acl-agentclass-foaf-agent), allows access to any agent, i.e., the public.
11+
*/
12+
Agent: "http://xmlns.com/foaf/0.1/Agent",
813
} as const;

src/vocabulary/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from "./acl.js"
12
export * from "./acp.js"
23
export * from "./dc.js"
34
export * from "./foaf.js"

src/vocabulary/vcard.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export const VCARD = {
33
Email: "http://www.w3.org/2006/vcard/ns#Email",
44
email: "http://www.w3.org/2006/vcard/ns#email",
55
hasEmail: "http://www.w3.org/2006/vcard/ns#hasEmail",
6+
hasMember: "http://www.w3.org/2006/vcard/ns#hasMember",
67
hasValue: "http://www.w3.org/2006/vcard/ns#hasValue",
78
hasPhoto: "http://www.w3.org/2006/vcard/ns#hasPhoto",
89
tel: "http://www.w3.org/2006/vcard/ns#tel",

src/wac/AclResource.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { DatasetWrapper } from "@rdfjs/wrapper"
2+
import { Authorization } from "./Authorization.js"
3+
import { ACL } from "../vocabulary/mod.js"
4+
5+
/**
6+
* Represents an ACL Resource according to the Web Access Control specification.
7+
*
8+
* @see https://solidproject.org/TR/wac#acl-resource-representation
9+
*/
10+
class AclResource extends DatasetWrapper {
11+
/**
12+
* Gets all authorizations from the ACL Resource.
13+
*
14+
* @return {Iterable<Authorization>} Authorizations, any of which could permit an attempted access.
15+
*/
16+
get authorizations(): Iterable<Authorization> {
17+
return this.instancesOf(ACL.Authorization, Authorization)
18+
}
19+
}

src/wac/Authorization.ts

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import {
2+
NamedNodeAs,
3+
NamedNodeFrom,
4+
OptionalAs,
5+
OptionalFrom,
6+
SetFrom,
7+
TermAs,
8+
TermFrom,
9+
TermWrapper
10+
} from "@rdfjs/wrapper"
11+
import { ACL, FOAF, RDF } from "../vocabulary/mod.js"
12+
import { Group } from "./Group.js"
13+
14+
/**
15+
* Represents an Authorization according to the Web Access Control specification.
16+
*
17+
* Authorization is the most fundamental unit of access control describing access permissions granting to agents the ability to perform operations on resources.
18+
*
19+
* @see https://solidproject.org/TR/wac#authorization-rule
20+
*/
21+
22+
export class Authorization extends TermWrapper {
23+
//#region Data
24+
25+
//#region Access Objects
26+
27+
/**
28+
* Denotes the resource to which access is being granted.
29+
*
30+
* @see https://solidproject.org/TR/wac#acl-accessto
31+
*/
32+
get accessTo(): string | undefined {
33+
return OptionalFrom.subjectPredicate(this, ACL.accessTo, NamedNodeAs.string)
34+
}
35+
36+
set accessTo(value: string | undefined) {
37+
OptionalAs.object(this, ACL.accessTo, value, NamedNodeFrom.string)
38+
}
39+
40+
/**
41+
* Denotes the container resource whose Authorization can be applied to a resource lower in the collection hierarchy.
42+
*
43+
* @see https://solidproject.org/TR/wac#acl-default
44+
*/
45+
get default(): string | undefined {
46+
return OptionalFrom.subjectPredicate(this, ACL.default, NamedNodeAs.string)
47+
}
48+
49+
set default(value: string | undefined) {
50+
OptionalAs.object(this, ACL.default, value, NamedNodeFrom.string)
51+
}
52+
53+
//#endregion
54+
55+
//#region Access Modes
56+
57+
/**
58+
* Denotes a class of operations that the agents can perform on a resource.
59+
*
60+
* @see https://solidproject.org/TR/wac#acl-mode
61+
*/
62+
get mode(): Set<string> {
63+
return SetFrom.subjectPredicate(this, ACL.mode, NamedNodeAs.string, NamedNodeFrom.string)
64+
}
65+
66+
//#endregion
67+
68+
//#region Access Subjects
69+
70+
/**
71+
* Denotes an agent being given the access permission.
72+
*
73+
* @see https://solidproject.org/TR/wac#acl-agent
74+
*/
75+
get agent(): Set<string> {
76+
return SetFrom.subjectPredicate(this, ACL.agent, NamedNodeAs.string, NamedNodeFrom.string)
77+
}
78+
79+
/**
80+
* Denotes a class of agents being given the access permission.
81+
*
82+
* @see https://solidproject.org/TR/wac#acl-agentclass
83+
*/
84+
get agentClass(): Set<string> {
85+
return SetFrom.subjectPredicate(this, ACL.agentClass, NamedNodeAs.string, NamedNodeFrom.string)
86+
}
87+
88+
/**
89+
* Denotes a group of agents being given the access permission.
90+
*
91+
* @see https://solidproject.org/TR/wac#acl-agentgroup
92+
*/
93+
get agentGroup(): Group | undefined {
94+
return OptionalFrom.subjectPredicate(this, ACL.agentGroup, TermAs.instance(Group))
95+
}
96+
97+
set agentGroup(value: Group | undefined) {
98+
OptionalAs.object(this, ACL.agentGroup, value, TermFrom.instance)
99+
}
100+
101+
/**
102+
* Denotes the origin of an HTTP request that is being given the access permission.
103+
*
104+
* @see https://solidproject.org/TR/wac#acl-origin
105+
*/
106+
get origin(): Set<string> {
107+
return SetFrom.subjectPredicate(this, ACL.origin, NamedNodeAs.string, NamedNodeFrom.string)
108+
}
109+
110+
//#endregion
111+
112+
get type(): Set<string> {
113+
return SetFrom.subjectPredicate(this, RDF.type, NamedNodeAs.string, NamedNodeFrom.string)
114+
}
115+
116+
//#endregion
117+
118+
//#region Computed
119+
120+
/**
121+
* @see https://solidproject.org/TR/wac#authorization-conformance
122+
*/
123+
get conforms(): boolean {
124+
if (!this.type.has(ACL.Authorization)) {
125+
return false
126+
}
127+
128+
if (this.accessTo === undefined || this.default === undefined) {
129+
return false
130+
}
131+
132+
if (this.mode.size === 0) {
133+
return false
134+
}
135+
136+
if (this.agent.size === 0 && (this.agentGroup == undefined || this.agentGroup.hasMember.size === 0) && this.agentClass.size === 0 && this.origin.size === 0) {
137+
return false
138+
}
139+
140+
return true
141+
}
142+
143+
get accessibleToAny(): boolean {
144+
return this.agentClass.has(FOAF.Agent)
145+
}
146+
147+
set accessibleToAny(value: boolean) {
148+
this.overwrite(this.agentClass, FOAF.Agent, value)
149+
}
150+
151+
get accessibleToAuthenticated(): boolean {
152+
return this.agentClass.has(ACL.AuthenticatedAgent)
153+
}
154+
155+
set accessibleToAuthenticated(value: boolean) {
156+
this.overwrite(this.agentClass, ACL.AuthenticatedAgent, value)
157+
}
158+
159+
get canRead(): boolean {
160+
return this.mode.has(ACL.Read)
161+
}
162+
163+
set canRead(value: boolean) {
164+
this.overwrite(this.mode, ACL.Read, value)
165+
}
166+
167+
get canWrite(): boolean {
168+
return this.mode.has(ACL.Write)
169+
}
170+
171+
set canWrite(value: boolean) {
172+
this.overwrite(this.mode, ACL.Write, value)
173+
}
174+
175+
get canAppend(): boolean {
176+
return this.mode.has(ACL.Append)
177+
}
178+
179+
set canAppend(value: boolean) {
180+
this.overwrite(this.mode, ACL.Append, value)
181+
}
182+
183+
get canCreate(): boolean {
184+
return this.canWrite || this.canAppend
185+
}
186+
187+
get canUpdate(): boolean {
188+
return this.canCreate
189+
}
190+
191+
get canDelete(): boolean {
192+
return this.canWrite
193+
}
194+
195+
set canDelete(value: boolean) {
196+
this.canWrite = value
197+
}
198+
199+
get canReadWriteAcl(): boolean {
200+
return this.mode.has(ACL.Control)
201+
}
202+
203+
set canReadWriteAcl(value: boolean) {
204+
this.overwrite(this.mode, ACL.Control, value)
205+
}
206+
207+
//#endregion
208+
209+
//#region Utilities
210+
211+
private overwrite(set: Set<string>, object: string, value: boolean) {
212+
set.delete(object)
213+
214+
if (!value) {
215+
return
216+
}
217+
218+
set.add(object)
219+
}
220+
221+
//#endregion
222+
}

src/wac/Group.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { NamedNodeAs, NamedNodeFrom, SetFrom, TermWrapper } from "@rdfjs/wrapper"
2+
import { VCARD } from "../vocabulary/mod.js"
3+
4+
export class Group extends TermWrapper {
5+
get hasMember(): Set<string> {
6+
return SetFrom.subjectPredicate(this, VCARD.hasMember, NamedNodeAs.string, NamedNodeFrom.string)
7+
}
8+
}

src/wac/mod.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from "./AclResource.js"
2+
export * from "./Authorization.js"
3+
export * from "./Group.js"

0 commit comments

Comments
 (0)