Skip to content
This repository was archived by the owner on Sep 25, 2019. It is now read-only.

Commit e83d807

Browse files
Merge pull request #3 from solid/dz_allows_helpers
Implement PermissionSet.checkAccess() (for node-solid-server acl checker refactoring)
2 parents e84520d + ffc35d8 commit e83d807

6 files changed

Lines changed: 944 additions & 529 deletions

File tree

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
],
1313
"scripts": {
1414
"build": "babel src -d lib",
15+
"postinstall": "npm run build",
1516
"prepublish": "npm test && npm run build",
1617
"standard": "standard *.js src/*.js",
1718
"tape": "tape test/unit/*.js",
@@ -43,12 +44,11 @@
4344
"dependencies": {
4445
"babel-cli": "^6.14.0",
4546
"babel-preset-es2015": "^6.14.0",
46-
"shorthash": "0.0.2",
47-
"solid-namespace": "0.0.1"
47+
"solid-namespace": "0.1.0"
4848
},
4949
"devDependencies": {
50-
"rdflib": "^0.10.0",
51-
"solid-web-client": "0.0.5",
50+
"rdflib": "^0.12.1",
51+
"solid-web-client": "0.0.8",
5252
"standard": "^5.4.1",
5353
"tape": "^4.4.0"
5454
},

src/authorization.js

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
* @module authorization
66
*/
77

8-
var hash = require('shorthash')
98
var vocab = require('solid-namespace')
109

1110
/**
@@ -24,12 +23,6 @@ function modes () {
2423
return acl
2524
}
2625

27-
/**
28-
* Inherited authorization (acl:defaultForNew)
29-
* @type {Boolean}
30-
*/
31-
var INHERIT = true
32-
3326
/**
3427
* Models an individual authorization object, for a single resource and for
3528
* a single webId (either agent or agentClass). See the comments at the top
@@ -54,6 +47,15 @@ class Authorization {
5447
* @type {Object}
5548
*/
5649
this.accessModes = {}
50+
/**
51+
* Type of authorization, either for a specific resource ('accessTo'),
52+
* or to be inherited by all downstream resources ('default')
53+
* @property accessType
54+
* @type {String} Either 'accessTo' or 'default'
55+
*/
56+
this.accessType = inherited
57+
? Authorization.DEFAULT
58+
: Authorization.ACCESS_TO
5759
/**
5860
* URL of an agent's WebID (`acl:agent`). Inside an authorization, mutually
5961
* exclusive with the `group` property. Set via `setAgent()`.
@@ -96,6 +98,14 @@ class Authorization {
9698
* @type {String}
9799
*/
98100
this.resourceUrl = resourceUrl
101+
/**
102+
* Should this authorization be serialized? (When writing back to an ACL
103+
* resource, for example.) Used for implied (rather than explicit)
104+
* authorization, such as ones that are derived from acl:Control statements.
105+
* @property virtual
106+
* @type {Boolean}
107+
*/
108+
this.virtual = false
99109
}
100110

101111
/**
@@ -105,7 +115,7 @@ class Authorization {
105115
*/
106116
addMailTo (agent) {
107117
if (typeof agent !== 'string') {
108-
agent = agent.object.uri
118+
agent = agent.object.value
109119
}
110120
if (agent.startsWith('mailto:')) {
111121
agent = agent.split(':')[ 1 ]
@@ -122,15 +132,14 @@ class Authorization {
122132
* @return {Authorization} Returns self, chainable.
123133
*/
124134
addMode (accessMode) {
125-
var self = this
126135
if (Array.isArray(accessMode)) {
127-
accessMode.forEach((ea) => {
128-
self.addModeSingle(ea)
136+
accessMode.forEach(ea => {
137+
this.addModeSingle(ea)
129138
})
130139
} else {
131-
self.addModeSingle(accessMode)
140+
this.addModeSingle(accessMode)
132141
}
133-
return self
142+
return this
134143
}
135144

136145
/**
@@ -142,7 +151,7 @@ class Authorization {
142151
*/
143152
addModeSingle (accessMode) {
144153
if (typeof accessMode !== 'string') {
145-
accessMode = accessMode.object.uri
154+
accessMode = accessMode.object.value
146155
}
147156
this.accessModes[ accessMode ] = true
148157
return this
@@ -157,15 +166,14 @@ class Authorization {
157166
* @return {Authorization} Returns self, chainable.
158167
*/
159168
addOrigin (origin) {
160-
var self = this
161169
if (Array.isArray(origin)) {
162170
origin.forEach((ea) => {
163-
self.addOriginSingle(ea)
171+
this.addOriginSingle(ea)
164172
})
165173
} else {
166-
self.addOriginSingle(origin)
174+
this.addOriginSingle(origin)
167175
}
168-
return self
176+
return this
169177
}
170178

171179
/**
@@ -177,7 +185,7 @@ class Authorization {
177185
*/
178186
addOriginSingle (origin) {
179187
if (typeof origin !== 'string') {
180-
origin = origin.object.uri
188+
origin = origin.object.value
181189
}
182190
this.originsAllowed[ origin ] = true
183191
return this
@@ -258,6 +266,16 @@ class Authorization {
258266
return this.accessModes[ Authorization.acl.CONTROL ]
259267
}
260268

269+
/**
270+
* Returns a deep copy of this authorization.
271+
* @return {Authorization}
272+
*/
273+
clone () {
274+
let auth = new Authorization()
275+
Object.assign(auth, JSON.parse(JSON.stringify(this)))
276+
return auth
277+
}
278+
261279
/**
262280
* Compares this authorization with another one.
263281
* Authorizations are equal iff they:
@@ -303,7 +321,8 @@ class Authorization {
303321
if (!this.webId || !this.resourceUrl) {
304322
throw new Error('Cannot call hashFragment() on an incomplete authorization')
305323
}
306-
var hashFragment = hashFragmentFor(this.webId(), this.resourceUrl)
324+
var hashFragment = hashFragmentFor(this.webId(), this.resourceUrl,
325+
this.accessType)
307326
return hashFragment
308327
}
309328

@@ -399,6 +418,10 @@ class Authorization {
399418
if (!this.webId() || !this.resourceUrl) {
400419
return [] // This Authorization is invalid, return empty array
401420
}
421+
// Virtual / implied authorizations are not serialized
422+
if (this.virtual) {
423+
return []
424+
}
402425
var statement
403426
var fragment = rdf.namedNode('#' + this.hashFragment())
404427
var ns = vocab(rdf)
@@ -452,15 +475,14 @@ class Authorization {
452475
* @returns {removeMode}
453476
*/
454477
removeMode (accessMode) {
455-
var self = this
456478
if (Array.isArray(accessMode)) {
457479
accessMode.forEach((ea) => {
458-
self.removeModeSingle(ea)
480+
this.removeModeSingle(ea)
459481
})
460482
} else {
461-
self.removeModeSingle(accessMode)
483+
this.removeModeSingle(accessMode)
462484
}
463-
return self
485+
return this
464486
}
465487

466488
/**
@@ -472,7 +494,7 @@ class Authorization {
472494
*/
473495
removeModeSingle (accessMode) {
474496
if (typeof accessMode !== 'string') {
475-
accessMode = accessMode.object.uri
497+
accessMode = accessMode.object.value
476498
}
477499
delete this.accessModes[ accessMode ]
478500
}
@@ -485,15 +507,14 @@ class Authorization {
485507
* @returns {removeMode}
486508
*/
487509
removeOrigin (accessMode) {
488-
var self = this
489510
if (Array.isArray(accessMode)) {
490511
accessMode.forEach((ea) => {
491-
self.removeOriginSingle(ea)
512+
this.removeOriginSingle(ea)
492513
})
493514
} else {
494-
self.removeOriginSingle(accessMode)
515+
this.removeOriginSingle(accessMode)
495516
}
496-
return self
517+
return this
497518
}
498519

499520
/**
@@ -505,7 +526,7 @@ class Authorization {
505526
*/
506527
removeOriginSingle (origin) {
507528
if (typeof origin !== 'string') {
508-
origin = origin.object.uri
529+
origin = origin.object.value
509530
}
510531
delete this.originsAllowed[ origin ]
511532
}
@@ -515,12 +536,12 @@ class Authorization {
515536
* setter method to enforce mutual exclusivity with `group` property, until
516537
* ES6 setter methods become available.
517538
* @method setAgent
518-
* @param agent {String|Statement} Agent URL (or `acl:agent` RDF triple).
539+
* @param agent {String|Quad} Agent URL (or `acl:agent` RDF triple).
519540
*/
520541
setAgent (agent) {
521542
if (typeof agent !== 'string') {
522543
// This is an RDF statement
523-
agent = agent.object.uri
544+
agent = agent.object.value
524545
}
525546
if (agent === Authorization.acl.EVERYONE) {
526547
this.setPublic()
@@ -545,7 +566,7 @@ class Authorization {
545566
setGroup (agentClass) {
546567
if (typeof agentClass !== 'string') {
547568
// This is an RDF statement
548-
agentClass = agentClass.object.uri
569+
agentClass = agentClass.object.value
549570
}
550571
if (this.agent) {
551572
throw new Error('Cannot set group, authorization already has an agent set')
@@ -571,22 +592,33 @@ class Authorization {
571592
}
572593
}
573594
// --- Standalone (non-instance) functions --
574-
575595
/**
576596
* Utility method that creates a hash fragment key for this authorization.
577597
* Used with graph serialization to RDF, and as a key to store authorizations
578598
* in a PermissionSet. Exported (mainly for use in PermissionSet).
579599
* @method hashFragmentFor
580-
* @param webId {String}
581-
* @param resourceUrl {String}
600+
* @param webId {String} Agent or group web id
601+
* @param resourceUrl {String} Resource or container URL for this authorization
602+
* @param [authType='accessTo'] {String} Either 'accessTo' or 'default'
582603
* @return {String}
583604
*/
584-
function hashFragmentFor (webId, resourceUrl) {
585-
var hashKey = webId + '-' + resourceUrl
586-
return hash.unique(hashKey)
605+
function hashFragmentFor (webId, resourceUrl,
606+
authType = Authorization.ACCESS_TO) {
607+
var hashKey = webId + '-' + resourceUrl + '-' + authType
608+
return hashKey
587609
}
588610
Authorization.acl = modes()
611+
Authorization.ALL_MODES = [
612+
Authorization.acl.READ,
613+
Authorization.acl.WRITE,
614+
Authorization.acl.CONTROL
615+
]
589616
Authorization.hashFragmentFor = hashFragmentFor
590-
Authorization.INHERIT = INHERIT
617+
618+
// Exported constants, for convenience / readability
619+
Authorization.INHERIT = true
620+
Authorization.NOT_INHERIT = !Authorization.INHERIT
621+
Authorization.ACCESS_TO = 'accessTo'
622+
Authorization.DEFAULT = 'default'
591623

592624
module.exports = Authorization

0 commit comments

Comments
 (0)