Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/vocabulary/acl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export const ACL = {
/**
* 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.
*
* @see https://solidproject.org/TR/wac#acl-mode-append
*/
Append: "http://www.w3.org/ns/auth/acl#Append",

/**
* Allows access to any authenticated agent.
*
* @see https://solidproject.org/TR/wac#acl-agentclass-authenticated-agent
*/
AuthenticatedAgent: "http://www.w3.org/ns/auth/acl#AuthenticatedAgent",

Authorization: "http://www.w3.org/ns/auth/acl#Authorization",

accessTo: "http://www.w3.org/ns/auth/acl#accessTo",

agent: "http://www.w3.org/ns/auth/acl#agent",

agentClass: "http://www.w3.org/ns/auth/acl#agentClass",

agentGroup: "http://www.w3.org/ns/auth/acl#agentGroup",

/**
* Allows access to a class of read and write operations on an ACL resource associated with a resource.
*
* @see https://solidproject.org/TR/wac#acl-mode-control
*/
Control: "http://www.w3.org/ns/auth/acl#Control",

default: "http://www.w3.org/ns/auth/acl#default",

mode: "http://www.w3.org/ns/auth/acl#mode",

origin: "http://www.w3.org/ns/auth/acl#origin",

/**
* Allows access to a class of read operations on a resource, e.g., to view the contents of a resource on HTTP GET requests.
*
* @see https://solidproject.org/TR/wac#acl-mode-read
*/
Read: "http://www.w3.org/ns/auth/acl#Read",

/**
* 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.
*
* @see https://solidproject.org/TR/wac#acl-mode-write
*/
Write: "http://www.w3.org/ns/auth/acl#Write",
} as const;
5 changes: 5 additions & 0 deletions src/vocabulary/foaf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ export const FOAF = {
email: "http://xmlns.com/foaf/0.1/email",
homepage: "http://xmlns.com/foaf/0.1/homepage",
knows: "http://xmlns.com/foaf/0.1/knows",

/**
* @remarks [When used in WAC](https://solidproject.org/TR/wac#acl-agentclass-foaf-agent), allows access to any agent, i.e., the public.
*/
Agent: "http://xmlns.com/foaf/0.1/Agent",
} as const;
1 change: 1 addition & 0 deletions src/vocabulary/mod.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./acl.js"
export * from "./acp.js"
export * from "./dc.js"
export * from "./foaf.js"
Expand Down
1 change: 1 addition & 0 deletions src/vocabulary/vcard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const VCARD = {
Email: "http://www.w3.org/2006/vcard/ns#Email",
email: "http://www.w3.org/2006/vcard/ns#email",
hasEmail: "http://www.w3.org/2006/vcard/ns#hasEmail",
hasMember: "http://www.w3.org/2006/vcard/ns#hasMember",
hasValue: "http://www.w3.org/2006/vcard/ns#hasValue",
hasPhoto: "http://www.w3.org/2006/vcard/ns#hasPhoto",
tel: "http://www.w3.org/2006/vcard/ns#tel",
Expand Down
19 changes: 19 additions & 0 deletions src/wac/AclResource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { DatasetWrapper } from "@rdfjs/wrapper"
import { Authorization } from "./Authorization.js"
import { ACL } from "../vocabulary/mod.js"

/**
* Represents an ACL Resource according to the Web Access Control specification.
*
* @see https://solidproject.org/TR/wac#acl-resource-representation
*/
class AclResource extends DatasetWrapper {
/**
* Gets all authorizations from the ACL Resource.
*
* @return {Iterable<Authorization>} Authorizations, any of which could permit an attempted access.
*/
get authorizations(): Iterable<Authorization> {
return this.instancesOf(ACL.Authorization, Authorization)
}
}
222 changes: 222 additions & 0 deletions src/wac/Authorization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import {
NamedNodeAs,
NamedNodeFrom,
OptionalAs,
OptionalFrom,
SetFrom,
TermAs,
TermFrom,
TermWrapper
} from "@rdfjs/wrapper"
import { ACL, FOAF, RDF } from "../vocabulary/mod.js"
import { Group } from "./Group.js"

/**
* Represents an Authorization according to the Web Access Control specification.
*
* Authorization is the most fundamental unit of access control describing access permissions granting to agents the ability to perform operations on resources.
*
* @see https://solidproject.org/TR/wac#authorization-rule
*/

export class Authorization extends TermWrapper {
//#region Data

//#region Access Objects

/**
* Denotes the resource to which access is being granted.
*
* @see https://solidproject.org/TR/wac#acl-accessto
*/
get accessTo(): string | undefined {
return OptionalFrom.subjectPredicate(this, ACL.accessTo, NamedNodeAs.string)
}

set accessTo(value: string | undefined) {
OptionalAs.object(this, ACL.accessTo, value, NamedNodeFrom.string)
}

/**
* Denotes the container resource whose Authorization can be applied to a resource lower in the collection hierarchy.
*
* @see https://solidproject.org/TR/wac#acl-default
*/
get default(): string | undefined {
return OptionalFrom.subjectPredicate(this, ACL.default, NamedNodeAs.string)
}

set default(value: string | undefined) {
OptionalAs.object(this, ACL.default, value, NamedNodeFrom.string)
}

//#endregion

//#region Access Modes

/**
* Denotes a class of operations that the agents can perform on a resource.
*
* @see https://solidproject.org/TR/wac#acl-mode
*/
get mode(): Set<string> {
return SetFrom.subjectPredicate(this, ACL.mode, NamedNodeAs.string, NamedNodeFrom.string)
}

//#endregion

//#region Access Subjects

/**
* Denotes an agent being given the access permission.
*
* @see https://solidproject.org/TR/wac#acl-agent
*/
get agent(): Set<string> {
return SetFrom.subjectPredicate(this, ACL.agent, NamedNodeAs.string, NamedNodeFrom.string)
}

/**
* Denotes a class of agents being given the access permission.
*
* @see https://solidproject.org/TR/wac#acl-agentclass
*/
get agentClass(): Set<string> {
return SetFrom.subjectPredicate(this, ACL.agentClass, NamedNodeAs.string, NamedNodeFrom.string)
}

/**
* Denotes a group of agents being given the access permission.
*
* @see https://solidproject.org/TR/wac#acl-agentgroup
*/
get agentGroup(): Group | undefined {
return OptionalFrom.subjectPredicate(this, ACL.agentGroup, TermAs.instance(Group))
}

set agentGroup(value: Group | undefined) {
OptionalAs.object(this, ACL.agentGroup, value, TermFrom.instance)
}

/**
* Denotes the origin of an HTTP request that is being given the access permission.
*
* @see https://solidproject.org/TR/wac#acl-origin
*/
get origin(): Set<string> {
return SetFrom.subjectPredicate(this, ACL.origin, NamedNodeAs.string, NamedNodeFrom.string)
}

//#endregion

get type(): Set<string> {
return SetFrom.subjectPredicate(this, RDF.type, NamedNodeAs.string, NamedNodeFrom.string)
}

//#endregion

//#region Computed

/**
* @see https://solidproject.org/TR/wac#authorization-conformance
*/
get conforms(): boolean {
if (!this.type.has(ACL.Authorization)) {
return false
}

if (this.accessTo === undefined || this.default === undefined) {
return false
}

if (this.mode.size === 0) {
return false
}

if (this.agent.size === 0 && (this.agentGroup == undefined || this.agentGroup.hasMember.size === 0) && this.agentClass.size === 0 && this.origin.size === 0) {
return false
}

return true
}

get accessibleToAny(): boolean {
return this.agentClass.has(FOAF.Agent)
}

set accessibleToAny(value: boolean) {
this.overwrite(this.agentClass, FOAF.Agent, value)
}

get accessibleToAuthenticated(): boolean {
return this.agentClass.has(ACL.AuthenticatedAgent)
}

set accessibleToAuthenticated(value: boolean) {
this.overwrite(this.agentClass, ACL.AuthenticatedAgent, value)
}

get canRead(): boolean {
return this.mode.has(ACL.Read)
}

set canRead(value: boolean) {
this.overwrite(this.mode, ACL.Read, value)
}

get canWrite(): boolean {
return this.mode.has(ACL.Write)
}

set canWrite(value: boolean) {
this.overwrite(this.mode, ACL.Write, value)
}

get canAppend(): boolean {
return this.mode.has(ACL.Append)
}

set canAppend(value: boolean) {
this.overwrite(this.mode, ACL.Append, value)
}

get canCreate(): boolean {
return this.canWrite || this.canAppend
}

get canUpdate(): boolean {
return this.canCreate
}

get canDelete(): boolean {
return this.canWrite
}

set canDelete(value: boolean) {
this.canWrite = value
}

get canReadWriteAcl(): boolean {
return this.mode.has(ACL.Control)
}

set canReadWriteAcl(value: boolean) {
this.overwrite(this.mode, ACL.Control, value)
}

//#endregion

//#region Utilities

private overwrite(set: Set<string>, object: string, value: boolean) {
set.delete(object)

if (!value) {
return
}

set.add(object)
}

//#endregion
}
8 changes: 8 additions & 0 deletions src/wac/Group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { NamedNodeAs, NamedNodeFrom, SetFrom, TermWrapper } from "@rdfjs/wrapper"
import { VCARD } from "../vocabulary/mod.js"

export class Group extends TermWrapper {
get hasMember(): Set<string> {
return SetFrom.subjectPredicate(this, VCARD.hasMember, NamedNodeAs.string, NamedNodeFrom.string)
}
}
3 changes: 3 additions & 0 deletions src/wac/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./AclResource.js"
export * from "./Authorization.js"
export * from "./Group.js"