UNPKG

solid-permissions

Version:

Web Access Control based permissions library

124 lines (116 loc) 3.66 kB
const vocab = require('solid-namespace') const debug = require('debug')('solid:permissions') /** * ACL Group Listing * @see https://github.com/solid/web-access-control-spec#groups-of-agents * @class GroupListing */ class GroupListing { /** * @constructor * @param [options={}] {Object} Options hashmap * @param [options.uri] {string|NamedNode} Group URI as appears in ACL file * (e.g. `https://example.com/groups#management`) * @param [options.uid] {string} Value of `vcard:hasUID` object * @param [options.members={}] {Set} Set of group members, by webId * @param [options.listing] {string|NamedNode} Group listing document URI * @param [options.rdf] {RDF} RDF library * @param [options.graph] {Graph} Parsed graph of the group listing document */ constructor (options = {}) { this.uri = options.uri this.uid = options.uid this.members = options.members || new Set() this.listing = options.listing this.rdf = options.rdf this.graph = options.graph if (this.rdf && this.graph) { this.initFromGraph(this.graph, this.rdf) } } /** * Factory function, returns a group listing, loaded and initialized * with the graph from its uri. Will return null if parsing fails, * which can be used to deny access to the resource. * @static * @param uri {string} * @param fetchGraph {Function} * @param rdf {RDF} * @param options {Object} Options hashmap, passed through to fetchGraph() * @return {Promise<GroupListing|null>} */ static loadFrom (uri, fetchGraph, rdf, options = {}) { debug('Trying to find a Group Listing in ' + uri) let group = new GroupListing({ uri, rdf }) return fetchGraph(uri, options) .then(graph => { return group.initFromGraph(uri, graph) }) .catch(err => { // Returning null will result in deny, which is suitable in this case console.error(err) return null }) } /** * Adds a member's web id uri to the listing * @param webId {string|NamedNode} * @return {GroupListing} Chainable */ addMember (webId) { if (webId.value) { webId = webId.value } this.members.add(webId) return this } /** * Returns the number of members in this listing * @return {Number} */ get count () { return this.members.size } /** * Tests if a webId uri is present in the members list * @param webId {string|NamedNode} * @return {Boolean} */ hasMember (webId) { if (webId.value) { webId = webId.value } return this.members.has(webId) } /** * @method initFromGraph * @param [uri] {string|NamedNode} Group URI as appears in ACL file * (e.g. `https://example.com/groups#management`) * @param [graph] {Graph} Parsed graph * @param [rdf] {RDF} * @throws {Error} * @return {GroupListing} Chainable */ initFromGraph (uri = this.uri, graph = this.graph, rdf = this.rdf) { if (!uri) { throw new Error('Group URI required to init from graph') } if (!graph || !rdf) { throw new Error('initFromGraph() - graph or rdf library missing') } let ns = vocab(rdf) let group = rdf.namedNode(uri) let rdfType = graph.any(group, null, ns.vcard('Group')) if (!rdfType) { console.warn(`Possibly invalid group '${uri}', missing type vcard:Group`) } this.uid = graph.anyValue(group, ns.vcard('hasUID')) debug('Found Group Listing with ' + group) graph.match(group, ns.vcard('hasMember')) .forEach(memberMatch => { this.addMember(memberMatch.object) }) return this } } module.exports = GroupListing