Skip to content

Commit 0e6479b

Browse files
committed
ACP -> WAC
1 parent 3353726 commit 0e6479b

4 files changed

Lines changed: 108 additions & 33 deletions

File tree

src/acp/Matcher.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,16 @@ export class Matcher extends Typed {
66
get agent(): Set<string> {
77
return SetFrom.subjectPredicate(this, ACP.agent, NamedNodeAs.string, NamedNodeFrom.string)
88
}
9+
10+
get client(): Set<string> {
11+
return SetFrom.subjectPredicate(this, ACP.client, NamedNodeAs.string, NamedNodeFrom.string)
12+
}
13+
14+
get issuer(): Set<string> {
15+
return SetFrom.subjectPredicate(this, ACP.issuer, NamedNodeAs.string, NamedNodeFrom.string)
16+
}
17+
18+
get vc(): Set<string> {
19+
return SetFrom.subjectPredicate(this, ACP.vc, NamedNodeAs.string, NamedNodeFrom.string)
20+
}
921
}

src/acp/Policy.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,19 @@ export class Policy extends Typed {
88
return SetFrom.subjectPredicate(this, ACP.allow, NamedNodeAs.string, NamedNodeFrom.string)
99
}
1010

11+
get deny(): Set<string> {
12+
return SetFrom.subjectPredicate(this, ACP.deny, NamedNodeAs.string, NamedNodeFrom.string)
13+
}
14+
1115
get anyOf(): Set<Matcher> {
1216
return SetFrom.subjectPredicate(this, ACP.anyOf, TermAs.instance(Matcher), TermFrom.instance)
1317
}
1418

1519
get allOf(): Set<Matcher> {
1620
return SetFrom.subjectPredicate(this, ACP.allOf, TermAs.instance(Matcher), TermFrom.instance)
1721
}
22+
23+
get noneOf(): Set<Matcher> {
24+
return SetFrom.subjectPredicate(this, ACP.noneOf, TermAs.instance(Matcher), TermFrom.instance)
25+
}
1826
}

src/vocabulary/acp.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@ export const ACP = {
55
Policy: "http://www.w3.org/ns/solid/acp#Policy",
66
accessControl: "http://www.w3.org/ns/solid/acp#accessControl",
77
agent: "http://www.w3.org/ns/solid/acp#agent",
8+
client: "http://www.w3.org/ns/solid/acp#client",
9+
issuer: "http://www.w3.org/ns/solid/acp#issuer",
10+
vc: "http://www.w3.org/ns/solid/acp#vc",
811
allow: "http://www.w3.org/ns/solid/acp#allow",
12+
deny: "http://www.w3.org/ns/solid/acp#deny",
913
anyOf: "http://www.w3.org/ns/solid/acp#anyOf",
1014
allOf: "http://www.w3.org/ns/solid/acp#allOf",
15+
noneOf: "http://www.w3.org/ns/solid/acp#noneOf",
1116
apply: "http://www.w3.org/ns/solid/acp#apply",
1217
memberAccessControl: "http://www.w3.org/ns/solid/acp#memberAccessControl",
1318
mode: "http://www.w3.org/ns/solid/acp#mode",

test/unit/wac2acp.test.ts

Lines changed: 83 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,13 @@ async function wacToAcp() {
4444
const wac = new AclResource(read(wacRdf), DataFactory)
4545
const result = new Store()
4646

47-
for (const auth of wac.authorizations) {
48-
processAuthorization(auth, result)
49-
}
47+
for (const auth of wac.authorizations) processAuthorization(auth, result)
5048

51-
console.log("--------------------------")
52-
console.log("WAC -> ACP")
53-
console.log(await write(result))
54-
console.log("--------------------------")
49+
await log("WAC -> ACP", result)
5550
}
5651

5752
function processAuthorization(auth: Authorization, result: DatasetCore) {
58-
if (auth.origin.size > 0) {
59-
throw new Error("WAC origin cannot be translated to ACP")
60-
}
53+
if (any(auth.origin)) throw new Wac2AcpError("origin")
6154

6255
if (auth.accessTo !== undefined) {
6356
const acr = new AccessControlResource(auth.factory.blankNode(), result, auth.factory)
@@ -81,27 +74,15 @@ function populatePolicy(acr: AccessControlResource, auth: Authorization, resourc
8174

8275
acr.resource = resource
8376

84-
for (const mode of auth.mode) {
85-
policy.allow.add(mode)
86-
}
77+
for (const mode of auth.mode) policy.allow.add(mode)
8778

8879
for (const agent of auth.agent) {
89-
matcher.agent.add(agent)
80+
if (agent === FOAF.Agent) matcher.agent.add(ACP.PublicAgent)
81+
else if (agent === ACL.AuthenticatedAgent) matcher.agent.add(ACP.AuthenticatedAgent)
82+
else matcher.agent.add(agent)
9083
}
9184

92-
if (auth.agentGroup !== undefined) {
93-
for (const member of auth.agentGroup.hasMember) {
94-
matcher.agent.add(member)
95-
}
96-
}
97-
98-
if (auth.agentClass.has(ACL.AuthenticatedAgent)) {
99-
matcher.agent.add(ACP.AuthenticatedAgent)
100-
}
101-
102-
if (auth.agentClass.has(FOAF.Agent)) {
103-
matcher.agent.add(ACP.PublicAgent)
104-
}
85+
for (const member of auth.agentGroup?.hasMember ?? []) matcher.agent.add(member)
10586
}
10687

10788
//#endregion
@@ -111,16 +92,48 @@ function populatePolicy(acr: AccessControlResource, auth: Authorization, resourc
11192
const acpRdf = `
11293
`;
11394

114-
function acpToWac() {
95+
async function acpToWac() {
11596
const acp = new AcrDataset(read(acpRdf), DataFactory)
97+
const result = new Store()
11698

117-
if (acp.acr != undefined) {
118-
processAcr(acp.acr)
119-
}
99+
if (acp.acr != undefined) processAcr(acp.acr, result)
100+
101+
await log("ACP -> WAC", result)
102+
}
103+
104+
function processAcr(acr: AccessControlResource, result: DatasetCore) {
105+
const auth = new Authorization(acr.factory.blankNode(), result, acr.factory)
106+
107+
if (any(acr.accessControl)) auth.accessTo = acr.resource
108+
if (any(acr.memberAccessControl)) auth.default = acr.resource
109+
110+
for (const ac of acr.accessControl) processAc(ac, auth)
111+
for (const ac of acr.memberAccessControl) processAc(ac, auth)
120112
}
121113

122-
function processAcr(acr: AccessControlResource) {
114+
function processAc(ac: AccessControl, auth: Authorization) {
115+
for (const policy of ac.apply) {
116+
if (any(policy.deny)) throw new Acp2WacError("deny")
117+
if (any(policy.anyOf)) throw new Acp2WacError("anyOf")
118+
if (any(policy.noneOf)) throw new Acp2WacError("noneOf")
119+
120+
for (const mode of policy.allow) auth.mode.add(mode)
121+
122+
for (const matcher of policy.allOf) {
123+
if (any(matcher.client)) throw new Acp2WacError("client")
124+
if (any(matcher.issuer)) throw new Acp2WacError("issuer")
125+
if (any(matcher.vc)) throw new Acp2WacError("vc")
126+
127+
for (const agent of matcher.agent) {
128+
if (agent === ACP.CreatorAgent) throw new Acp2WacError("CreatorAgent")
129+
if (agent === ACP.OwnerAgent) throw new Acp2WacError("OwnerAgent")
123130

131+
if (agent === ACP.PublicAgent) auth.agent.add(FOAF.Agent)
132+
else if (agent === ACP.AuthenticatedAgent) auth.agent.add(ACL.AuthenticatedAgent)
133+
else auth.agent.add(agent)
134+
}
135+
}
136+
}
124137
}
125138

126139
//#endregion
@@ -135,6 +148,8 @@ const ACL = {
135148

136149
const ACP = {
137150
AuthenticatedAgent: "http://www.w3.org/ns/solid/acp#AuthenticatedAgent",
151+
CreatorAgent: "http://www.w3.org/ns/solid/acp#CreatorAgent",
152+
OwnerAgent: "http://www.w3.org/ns/solid/acp#OwnerAgent",
138153
PublicAgent: "http://www.w3.org/ns/solid/acp#PublicAgent",
139154
} as const
140155

@@ -156,7 +171,7 @@ function read(rdf: string): DatasetCore {
156171
return dataset
157172
}
158173

159-
export function write(dataset: DatasetCore): Promise<string> {
174+
function write(dataset: DatasetCore): Promise<string> {
160175
return new Promise((resolve, reject) => {
161176
const writer = new Writer({
162177
prefixes: {
@@ -178,4 +193,39 @@ export function write(dataset: DatasetCore): Promise<string> {
178193
})
179194
}
180195

196+
function any<T>(set: Set<T>) {
197+
return set.size > 0
198+
}
199+
200+
async function log(title: string, dataset: DatasetCore) {
201+
console.log("--------------------------")
202+
console.log(title)
203+
console.log(await write(dataset))
204+
console.log("--------------------------")
205+
}
206+
207+
//#region Errors
208+
209+
class TranslationError extends Error {
210+
constructor(prefix: string, property: string, target: string, cause?: any) {
211+
super(`${prefix}:${property} cannot be translated to ${target}`)
212+
this.name = this.constructor.name
213+
this.cause = cause
214+
}
215+
}
216+
217+
class Acp2WacError extends TranslationError {
218+
constructor(property: string, cause?: any) {
219+
super("acp", property, "WAC", cause)
220+
}
221+
}
222+
223+
class Wac2AcpError extends TranslationError {
224+
constructor(property: string, cause?: any) {
225+
super("acl", property, "ACP", cause)
226+
}
227+
}
228+
229+
//#endregion
230+
181231
//#endregion

0 commit comments

Comments
 (0)