solid-server 5.8.2 → 5.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +1 -1
- package/default-templates/new-account/.well-known/.acl +2 -2
- package/lib/handlers/delete.js +0 -3
- package/lib/handlers/get.js +6 -4
- package/lib/handlers/notify.js +30 -12
- package/lib/handlers/patch.js +0 -4
- package/lib/handlers/post.js +0 -5
- package/lib/handlers/put.js +0 -3
- package/lib/rdf-notification-template.js +22 -10
- package/package.json +3 -3
package/.github/workflows/ci.yml
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
a acl:Authorization;
|
|
8
8
|
acl:agent <{{webId}}>;
|
|
9
9
|
acl:accessTo <./>;
|
|
10
|
-
acl:
|
|
10
|
+
acl:default <./>;
|
|
11
11
|
acl:mode acl:Read, acl:Write, acl:Control.
|
|
12
12
|
|
|
13
13
|
# The public has read permissions
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
a acl:Authorization;
|
|
16
16
|
acl:agentClass foaf:Agent;
|
|
17
17
|
acl:accessTo <./>;
|
|
18
|
-
acl:
|
|
18
|
+
acl:default <./>;
|
|
19
19
|
acl:mode acl:Read.
|
package/lib/handlers/delete.js
CHANGED
|
@@ -6,12 +6,9 @@ async function handler (req, res, next) {
|
|
|
6
6
|
debug('DELETE -- Request on' + req.originalUrl)
|
|
7
7
|
|
|
8
8
|
const ldp = req.app.locals.ldp
|
|
9
|
-
const prep = req.app.locals.prep
|
|
10
9
|
try {
|
|
11
10
|
await ldp.delete(req)
|
|
12
11
|
debug('DELETE -- Ok.')
|
|
13
|
-
// Add event-id for notifications
|
|
14
|
-
prep && res.setHeader('Event-ID', res.setEventID())
|
|
15
12
|
res.sendStatus(200)
|
|
16
13
|
next()
|
|
17
14
|
} catch (err) {
|
package/lib/handlers/get.js
CHANGED
|
@@ -101,7 +101,7 @@ async function handler (req, res, next) {
|
|
|
101
101
|
RDFs.includes(contentType) && !isHtmlResource && !ldp.suppressDataBrowser)
|
|
102
102
|
|
|
103
103
|
if (useDataBrowser) {
|
|
104
|
-
res.
|
|
104
|
+
res.setHeader('Content-Type', 'text/html')
|
|
105
105
|
const defaultDataBrowser = require.resolve('mashlib/dist/databrowser.html')
|
|
106
106
|
const dataBrowserPath = ldp.dataBrowserPath === 'default' ? defaultDataBrowser : ldp.dataBrowserPath
|
|
107
107
|
debug(' sending data browser file: ' + dataBrowserPath)
|
|
@@ -118,6 +118,7 @@ async function handler (req, res, next) {
|
|
|
118
118
|
let headers = {
|
|
119
119
|
'Content-Type': contentType
|
|
120
120
|
}
|
|
121
|
+
|
|
121
122
|
if (contentRange) {
|
|
122
123
|
headers = {
|
|
123
124
|
...headers,
|
|
@@ -125,16 +126,17 @@ async function handler (req, res, next) {
|
|
|
125
126
|
'Accept-Ranges': 'bytes',
|
|
126
127
|
'Content-Length': chunksize
|
|
127
128
|
}
|
|
128
|
-
res.
|
|
129
|
+
res.status(206)
|
|
129
130
|
}
|
|
130
131
|
|
|
131
|
-
if (prep
|
|
132
|
+
if (prep && isRdf(contentType) && !res.sendEvents({
|
|
132
133
|
config: { prep: prepConfig },
|
|
133
134
|
body: stream,
|
|
134
135
|
isBodyStream: true,
|
|
135
136
|
headers
|
|
136
137
|
})) return
|
|
137
|
-
|
|
138
|
+
|
|
139
|
+
res.writeHead(res.statusCode, headers) // res.set sneds 'charset'
|
|
138
140
|
return stream.pipe(res)
|
|
139
141
|
}
|
|
140
142
|
|
package/lib/handlers/notify.js
CHANGED
|
@@ -38,18 +38,32 @@ function getParentActivity (method, status) {
|
|
|
38
38
|
return 'Update'
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
function filterMillseconds (isoDate) {
|
|
42
|
+
return `${isoDate.substring(0, 19)}${isoDate.substring(23)}`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getDate (date) {
|
|
46
|
+
if (date) {
|
|
47
|
+
const eventDate = new Date(date)
|
|
48
|
+
if (!isNaN(eventDate.valueOf())) {
|
|
49
|
+
return filterMillseconds(eventDate.toISOString())
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const now = new Date()
|
|
53
|
+
return filterMillseconds(now.toISOString())
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
function handler (req, res, next) {
|
|
42
57
|
const { trigger, defaultNotification } = res.events.prep
|
|
43
58
|
|
|
44
59
|
const { method, path } = req
|
|
45
60
|
const { statusCode } = res
|
|
46
|
-
const eventID = res.
|
|
61
|
+
const eventID = res.setEventID()
|
|
47
62
|
const fullUrl = new URL(path, `${req.protocol}://${req.hostname}/`)
|
|
48
63
|
|
|
49
64
|
// Date is a hack since node does not seem to provide access to send date.
|
|
50
65
|
// Date needs to be shared with parent notification
|
|
51
|
-
const eventDate = res._header.match(/^Date: (.*?)$/m)?.[1]
|
|
52
|
-
new Date().toUTCString()
|
|
66
|
+
const eventDate = getDate(res._header.match(/^Date: (.*?)$/m)?.[1])
|
|
53
67
|
|
|
54
68
|
// If the resource itself newly created,
|
|
55
69
|
// it could not have been subscribed for notifications already
|
|
@@ -61,18 +75,19 @@ function handler (req, res, next) {
|
|
|
61
75
|
) {
|
|
62
76
|
const mediaType = negotiatedFields['content-type']
|
|
63
77
|
const activity = getActivity(method, path)
|
|
64
|
-
const
|
|
78
|
+
const object = activity === 'Add'
|
|
65
79
|
? res.getHeader('location')
|
|
80
|
+
: String(fullUrl)
|
|
81
|
+
const target = activity === 'Add'
|
|
82
|
+
? String(fullUrl)
|
|
66
83
|
: undefined
|
|
67
84
|
if (ALLOWED_RDF_MIME_TYPES.includes(mediaType?.[0])) {
|
|
68
85
|
return `${headerTemplate(negotiatedFields)}\r\n${solidRDFTemplate({
|
|
69
86
|
activity,
|
|
70
87
|
eventID,
|
|
71
|
-
object
|
|
88
|
+
object,
|
|
72
89
|
target,
|
|
73
90
|
date: eventDate,
|
|
74
|
-
// We use eTag as a proxy for state for now
|
|
75
|
-
state: res.getHeader('ETag'),
|
|
76
91
|
mediaType
|
|
77
92
|
})}`
|
|
78
93
|
} else {
|
|
@@ -93,7 +108,10 @@ function handler (req, res, next) {
|
|
|
93
108
|
// POST in Solid creates a child resource
|
|
94
109
|
const parent = getParent(path)
|
|
95
110
|
if (parent && method !== 'POST') {
|
|
96
|
-
|
|
111
|
+
res.setEventID({
|
|
112
|
+
path: parent,
|
|
113
|
+
id: eventID
|
|
114
|
+
})
|
|
97
115
|
const parentUrl = new URL(parent, fullUrl)
|
|
98
116
|
try {
|
|
99
117
|
trigger({
|
|
@@ -103,15 +121,15 @@ function handler (req, res, next) {
|
|
|
103
121
|
) {
|
|
104
122
|
const mediaType = negotiatedFields['content-type']
|
|
105
123
|
const activity = getParentActivity(method, statusCode)
|
|
106
|
-
const
|
|
124
|
+
const object = activity === 'Update' ? String(parentUrl) : String(fullUrl)
|
|
125
|
+
const target = activity === 'Update' ? undefined : String(parentUrl)
|
|
107
126
|
if (ALLOWED_RDF_MIME_TYPES.includes(mediaType?.[0])) {
|
|
108
127
|
return `${headerTemplate(negotiatedFields)}\r\n${solidRDFTemplate({
|
|
109
128
|
activity,
|
|
110
|
-
eventID
|
|
129
|
+
eventID,
|
|
111
130
|
date: eventDate,
|
|
112
|
-
object
|
|
131
|
+
object,
|
|
113
132
|
target,
|
|
114
|
-
eTag: undefined,
|
|
115
133
|
mediaType
|
|
116
134
|
})}`
|
|
117
135
|
}
|
package/lib/handlers/patch.js
CHANGED
|
@@ -39,7 +39,6 @@ function contentForNew (contentType) {
|
|
|
39
39
|
// Handles a PATCH request
|
|
40
40
|
async function patchHandler (req, res, next) {
|
|
41
41
|
debug(`PATCH -- ${req.originalUrl}`)
|
|
42
|
-
const prep = req.app.locals.prep
|
|
43
42
|
try {
|
|
44
43
|
// Obtain details of the target resource
|
|
45
44
|
const ldp = req.app.locals.ldp
|
|
@@ -91,9 +90,6 @@ async function patchHandler (req, res, next) {
|
|
|
91
90
|
await applyPatch(patchObject, graph, url)
|
|
92
91
|
return writeGraph(graph, resource, ldp.resourceMapper.resolveFilePath(req.hostname), ldp.serverUri)
|
|
93
92
|
})
|
|
94
|
-
|
|
95
|
-
// Add event-id for notifications
|
|
96
|
-
prep && res.setHeader('Event-ID', res.setEventID())
|
|
97
93
|
// Send the status and result to the client
|
|
98
94
|
res.status(resourceExists ? 200 : 201)
|
|
99
95
|
res.send(result)
|
package/lib/handlers/post.js
CHANGED
|
@@ -11,7 +11,6 @@ const getContentType = require('../utils').getContentType
|
|
|
11
11
|
|
|
12
12
|
async function handler (req, res, next) {
|
|
13
13
|
const ldp = req.app.locals.ldp
|
|
14
|
-
const prep = req.app.locals.prep
|
|
15
14
|
const contentType = getContentType(req.headers)
|
|
16
15
|
debug('content-type is ', contentType)
|
|
17
16
|
// Handle SPARQL(-update?) query
|
|
@@ -73,8 +72,6 @@ async function handler (req, res, next) {
|
|
|
73
72
|
// Handled by backpressure of streams!
|
|
74
73
|
busboy.on('finish', function () {
|
|
75
74
|
debug('Done storing files')
|
|
76
|
-
// Add event-id for notifications
|
|
77
|
-
prep && res.setHeader('Event-ID', res.setEventID())
|
|
78
75
|
res.sendStatus(200)
|
|
79
76
|
next()
|
|
80
77
|
})
|
|
@@ -94,8 +91,6 @@ async function handler (req, res, next) {
|
|
|
94
91
|
debug('File stored in ' + resourcePath)
|
|
95
92
|
header.addLinks(res, links)
|
|
96
93
|
res.set('Location', resourcePath)
|
|
97
|
-
// Add event-id for notifications
|
|
98
|
-
prep && res.setHeader('Event-ID', res.setEventID())
|
|
99
94
|
res.sendStatus(201)
|
|
100
95
|
next()
|
|
101
96
|
},
|
package/lib/handlers/put.js
CHANGED
|
@@ -59,7 +59,6 @@ async function checkPermission (request, resourceExists) {
|
|
|
59
59
|
// TODO could be renamed as putResource (it now covers container and non-container)
|
|
60
60
|
async function putStream (req, res, next, stream = req) {
|
|
61
61
|
const ldp = req.app.locals.ldp
|
|
62
|
-
const prep = req.app.locals.prep
|
|
63
62
|
// try {
|
|
64
63
|
// Obtain details of the target resource
|
|
65
64
|
let resourceExists = true
|
|
@@ -78,8 +77,6 @@ async function putStream (req, res, next, stream = req) {
|
|
|
78
77
|
// Fails with Append on existing resource
|
|
79
78
|
if (!req.originalUrl.endsWith('.acl')) await checkPermission(req, resourceExists)
|
|
80
79
|
await ldp.put(req, stream, getContentType(req.headers))
|
|
81
|
-
// Add event-id for notifications
|
|
82
|
-
prep && res.setHeader('Event-ID', res.setEventID())
|
|
83
80
|
res.sendStatus(resourceExists ? 204 : 201)
|
|
84
81
|
return next()
|
|
85
82
|
} catch (err) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
const uuid = require('uuid')
|
|
2
|
+
|
|
1
3
|
const CONTEXT_ACTIVITYSTREAMS = 'https://www.w3.org/ns/activitystreams'
|
|
2
4
|
const CONTEXT_NOTIFICATION = 'https://www.w3.org/ns/solid/notification/v1'
|
|
3
5
|
const CONTEXT_XML_SCHEMA = 'http://www.w3.org/2001/XMLSchema'
|
|
4
6
|
|
|
5
7
|
function generateJSONNotification ({
|
|
6
8
|
activity: type,
|
|
7
|
-
|
|
9
|
+
eventID,
|
|
8
10
|
date: published,
|
|
9
11
|
object,
|
|
10
12
|
target,
|
|
@@ -13,30 +15,40 @@ function generateJSONNotification ({
|
|
|
13
15
|
return {
|
|
14
16
|
published,
|
|
15
17
|
type,
|
|
16
|
-
id
|
|
18
|
+
id: `urn:uuid:${uuid.v4()}`,
|
|
19
|
+
...(eventID) && { state: eventID },
|
|
17
20
|
object,
|
|
18
21
|
...(type === 'Add') && { target },
|
|
19
|
-
...(type === 'Remove') && { origin: target }
|
|
20
|
-
...(state) && { state }
|
|
22
|
+
...(type === 'Remove') && { origin: target }
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
function generateTurtleNotification ({
|
|
25
27
|
activity,
|
|
26
|
-
|
|
28
|
+
eventID,
|
|
27
29
|
date,
|
|
28
30
|
object,
|
|
29
|
-
target
|
|
30
|
-
state = undefined
|
|
31
|
+
target
|
|
31
32
|
}) {
|
|
32
|
-
|
|
33
|
+
let targetLine = ''
|
|
34
|
+
let stateLine = ''
|
|
35
|
+
|
|
36
|
+
if (activity === 'Add') {
|
|
37
|
+
targetLine = `\n as:target <${target}> ;`
|
|
38
|
+
}
|
|
39
|
+
if (activity === 'Remove') {
|
|
40
|
+
targetLine = `\n as:origin <${target}> ;`
|
|
41
|
+
}
|
|
42
|
+
if (eventID) {
|
|
43
|
+
stateLine = `\n notify:state "${eventID}" ;`
|
|
44
|
+
}
|
|
33
45
|
|
|
34
46
|
return `@prefix as: <${CONTEXT_ACTIVITYSTREAMS}#> .
|
|
35
47
|
@prefix notify: <${CONTEXT_NOTIFICATION}#> .
|
|
36
48
|
@prefix xsd: <${CONTEXT_XML_SCHEMA}#> .
|
|
37
49
|
|
|
38
|
-
|
|
39
|
-
as:object
|
|
50
|
+
<urn:uuid:${uuid.v4()}> a as:${activity} ;
|
|
51
|
+
as:object <${object}> ;${targetLine}${stateLine}
|
|
40
52
|
as:published "${date}"^^xsd:dateTime .`.replaceAll('\n', '\r\n')
|
|
41
53
|
}
|
|
42
54
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solid-server",
|
|
3
3
|
"description": "Solid server on top of the file-system",
|
|
4
|
-
"version": "5.8.
|
|
4
|
+
"version": "5.8.4",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Tim Berners-Lee",
|
|
7
7
|
"email": "timbl@w3.org"
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"express-accept-events": "^0.3.0",
|
|
78
78
|
"express-handlebars": "^5.3.5",
|
|
79
79
|
"express-negotiate-events": "^0.3.0",
|
|
80
|
-
"express-prep": "^0.6.
|
|
80
|
+
"express-prep": "^0.6.4",
|
|
81
81
|
"express-session": "^1.18.0",
|
|
82
82
|
"extend": "^3.0.2",
|
|
83
83
|
"from2": "^2.3.0",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"ip-range-check": "0.2.0",
|
|
93
93
|
"is-ip": "^3.1.0",
|
|
94
94
|
"li": "^1.3.0",
|
|
95
|
-
"mashlib": "^1.
|
|
95
|
+
"mashlib": "^1.10.2",
|
|
96
96
|
"mime-types": "^2.1.35",
|
|
97
97
|
"negotiator": "^0.6.3",
|
|
98
98
|
"node-fetch": "^2.7.0",
|