Skip to content

Commit 39fe584

Browse files
committed
Verify read and write permissions for patches.
1 parent 6750196 commit 39fe584

File tree

4 files changed

+222
-87
lines changed

4 files changed

+222
-87
lines changed

lib/handlers/patch.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ function patchHandler (req, res, next) {
4444
return next(error(415, `Unsupported patch content type: ${patch.contentType}`))
4545
}
4646

47-
// Parse the target graph and the patch document
47+
// Parse the target graph and the patch document,
48+
// and verify permission for performing this specific patch
4849
Promise.all([
4950
readGraph(target),
5051
parsePatch(target.uri, patch.uri, patch.text)
52+
.then(patchObject => checkPermission(target, req, patchObject))
5153
])
5254
// Patch the graph and write it back to the file
5355
.then(([graph, patchObject]) => applyPatch(patchObject, graph, target))
@@ -96,6 +98,36 @@ function readGraph (resource) {
9698
})
9799
}
98100

101+
// Verifies whether the user is allowed to perform the patch on the target
102+
function checkPermission (target, request, patchObject) {
103+
// If no ACL object was passed down, assume permissions are okay.
104+
if (!request.acl) return Promise.resolve(patchObject)
105+
// At this point, we already assume append access,
106+
// as this can be checked upfront before parsing the patch.
107+
// Now that we know the details of the patch,
108+
// we might need to perform additional checks.
109+
var checks = []
110+
// Read access is required for DELETE and WHERE.
111+
// If we would allows users without read access,
112+
// they could use DELETE or WHERE to trigger 200 or 409,
113+
// and thereby guess the existence of certain triples.
114+
// DELETE additionally requires write access.
115+
if (patchObject.delete) {
116+
checks = [hasPermission('Read'), hasPermission('Write')]
117+
} else if (patchObject.where) {
118+
checks = [hasPermission('Read')]
119+
}
120+
return Promise.all(checks).then(() => patchObject)
121+
122+
// Checks whether the user has the given permission on the target
123+
function hasPermission (mode) {
124+
return new Promise((resolve, reject) =>
125+
request.acl.can(request.userId, mode, target.uri,
126+
err => err ? reject(err) : resolve())
127+
)
128+
}
129+
}
130+
99131
// Applies the patch to the RDF graph
100132
function applyPatch (patchObject, graph, target) {
101133
debug('PATCH -- Applying patch')

0 commit comments

Comments
 (0)