-
Notifications
You must be signed in to change notification settings - Fork 307
Expand file tree
/
Copy pathallow.mjs
More file actions
86 lines (77 loc) · 3.03 KB
/
allow.mjs
File metadata and controls
86 lines (77 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import ACL from '../acl-checker.mjs'
import { verifyNostrAuth } from '../api/authn/webid-nostr.mjs'
// import debug from '../debug.mjs'
export default function allow (mode) {
return async function allowHandler (req, res, next) {
const ldp = req.app.locals.ldp || {}
if (!ldp.webid) {
return next()
}
// Set up URL to filesystem mapping
const rootUrl = ldp.resourceMapper.resolveUrl(req.hostname)
// Determine the actual path of the request
// (This is used as an ugly hack to check the ACL status of other resources.)
let resourcePath = res && res.locals && res.locals.path
? res.locals.path
: req.path
// Check whether the resource exists
let stat
try {
const ret = await ldp.exists(req.hostname, resourcePath)
stat = ret.stream
} catch (err) {
stat = null
}
// Ensure directories always end in a slash
if (!resourcePath.endsWith('/') && stat && stat.isDirectory()) {
resourcePath += '/'
}
const trustedOrigins = [ldp.resourceMapper.resolveUrl(req.hostname)].concat(ldp.trustedOrigins)
if (ldp.multiuser) {
trustedOrigins.push(ldp.serverUri)
}
// Obtain and store the ACL of the requested resource
const resourceUrl = rootUrl + resourcePath
// Ensure the user has the required permission
let userId = req.session?.userId
if (!userId) {
userId = await verifyNostrAuth(req)
if (userId) {
res.set('User', userId)
}
}
try {
req.acl = ACL.createFromLDPAndRequest(resourceUrl, ldp, req)
// if (resourceUrl.endsWith('.acl')) mode = 'Control'
const isAllowed = await req.acl.can(userId, mode, req.method, stat)
if (isAllowed) {
return next()
}
} catch (error) { next(error) }
if (mode === 'Read' && (resourcePath === '' || resourcePath === '/')) {
// This is a hack to make NSS check the ACL for representation that is served for root (if any)
// See https://github.com/solid/node-solid-server/issues/1063 for more info
const representationUrl = `${rootUrl}/index.html`
let representationPath
try {
representationPath = await ldp.resourceMapper.mapUrlToFile({ url: representationUrl })
} catch (err) {
}
// We ONLY want to do this when the HTML representation exists
if (representationPath) {
req.acl = ACL.createFromLDPAndRequest(representationUrl, ldp, req)
const representationIsAllowed = await req.acl.can(userId, mode)
if (representationIsAllowed) {
return next()
}
}
}
// check if user is owner. Check isOwner from /.meta
try {
if (resourceUrl.endsWith('.acl') && (await ldp.isOwner(userId, req.hostname))) return next()
} catch (err) {}
const error = req.authError || await req.acl.getError(userId, mode)
// debug.handlers(`ALLOW -- ${mode} access denied to ${userId || '(none)'}: ${error.status} - ${error.message}`)
next(error)
}
}