solid-server 5.7.2 → 5.7.3

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/index.html CHANGED
@@ -38,7 +38,7 @@
38
38
  <dt>Name</dt>
39
39
  <dd>localhost</dd>
40
40
  <dt>Details</dt>
41
- <dd>Running on <a href="https://github.com/solid/node-solid-server/releases/tag/v5.6.6">Solid 5.6.6</a></dd>
41
+ <dd>Running on <a href="https://github.com/solid/node-solid-server/releases/tag/v5.7.3">Solid 5.7.3</a></dd>
42
42
  </dl>
43
43
  </section>
44
44
  </div>
@@ -18,8 +18,24 @@ const PATCH_PARSERS = {
18
18
  'text/n3': require('./patch/n3-patch-parser.js')
19
19
  }
20
20
 
21
+ // use media-type as contentType for new RDF resource
21
22
  const DEFAULT_FOR_NEW_CONTENT_TYPE = 'text/turtle'
22
23
 
24
+ function contentTypeForNew (req) {
25
+ let contentTypeForNew = DEFAULT_FOR_NEW_CONTENT_TYPE
26
+ if (req.path.endsWith('.jsonld')) contentTypeForNew = 'application/ld+json'
27
+ else if (req.path.endsWith('.n3')) contentTypeForNew = 'text/n3'
28
+ else if (req.path.endsWith('.rdf')) contentTypeForNew = 'application/rdf+xml'
29
+ return contentTypeForNew
30
+ }
31
+
32
+ function contentForNew (contentType) {
33
+ let contentForNew = ''
34
+ if (contentType.includes('ld+json')) contentForNew = JSON.stringify('{}')
35
+ else if (contentType.includes('rdf+xml')) contentForNew = '<rdf:RDF\n xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n\n</rdf:RDF>'
36
+ return contentForNew
37
+ }
38
+
23
39
  // Handles a PATCH request
24
40
  async function patchHandler (req, res, next) {
25
41
  debug(`PATCH -- ${req.originalUrl}`)
@@ -33,9 +49,9 @@ async function patchHandler (req, res, next) {
33
49
  // First check if the file already exists
34
50
  ({ path, contentType } = await ldp.resourceMapper.mapUrlToFile({ url: req }))
35
51
  } catch (err) {
36
- // If the file doesn't exist, request one to be created with the default content type
52
+ // If the file doesn't exist, request to create one with the file media type as contentType
37
53
  ({ path, contentType } = await ldp.resourceMapper.mapUrlToFile(
38
- { url: req, createIfNotExists: true, contentType: DEFAULT_FOR_NEW_CONTENT_TYPE }))
54
+ { url: req, createIfNotExists: true, contentType: contentTypeForNew(req) }))
39
55
  // check if a folder with same name exists
40
56
  await ldp.checkItemName(req)
41
57
  resourceExists = false
@@ -93,13 +109,14 @@ function readGraph (resource) {
93
109
  // If the file does not exist, assume empty contents
94
110
  // (it will be created after a successful patch)
95
111
  if (err.code === 'ENOENT') {
96
- fileContents = ''
112
+ fileContents = contentForNew(resource.contentType)
97
113
  // Fail on all other errors
98
114
  } else {
99
115
  return reject(error(500, `Original file read error: ${err}`))
100
116
  }
101
117
  }
102
118
  debug('PATCH -- Read target file (%d bytes)', fileContents.length)
119
+ fileContents = resource.contentType.includes('json') ? JSON.parse(fileContents) : fileContents
103
120
  resolve(fileContents)
104
121
  })
105
122
  )
@@ -177,23 +194,34 @@ function writeGraph (graph, resource, root, serverUri) {
177
194
  debug('PATCH -- Writing patched file')
178
195
  return new Promise((resolve, reject) => {
179
196
  const resourceSym = graph.sym(resource.url)
180
- const serialized = $rdf.serialize(resourceSym, graph, resource.url, resource.contentType)
181
-
182
- // First check if we are above quota
183
- overQuota(root, serverUri).then((isOverQuota) => {
184
- if (isOverQuota) {
185
- return reject(error(413,
186
- 'User has exceeded their storage quota'))
187
- }
188
197
 
189
- fs.writeFile(resource.path, serialized, { encoding: 'utf8' }, function (err) {
190
- if (err) {
191
- return reject(error(500, `Failed to write file after patch: ${err}`))
198
+ function doWrite (serialized) {
199
+ // First check if we are above quota
200
+ overQuota(root, serverUri).then((isOverQuota) => {
201
+ if (isOverQuota) {
202
+ return reject(error(413,
203
+ 'User has exceeded their storage quota'))
192
204
  }
193
- debug('PATCH -- applied successfully')
194
- resolve('Patch applied successfully.\n')
205
+
206
+ fs.writeFile(resource.path, serialized, { encoding: 'utf8' }, function (err) {
207
+ if (err) {
208
+ return reject(error(500, `Failed to write file after patch: ${err}`))
209
+ }
210
+ debug('PATCH -- applied successfully')
211
+ resolve('Patch applied successfully.\n')
212
+ })
213
+ }).catch(() => reject(error(500, 'Error finding user quota')))
214
+ }
215
+
216
+ if (resource.contentType === 'application/ld+json') {
217
+ $rdf.serialize(resourceSym, graph, resource.url, resource.contentType, function (err, result) {
218
+ if (err) return reject(error(500, `Failed to serialize after patch: ${err}`))
219
+ doWrite(result)
195
220
  })
196
- }).catch(() => reject(error(500, 'Error finding user quota')))
221
+ } else {
222
+ const serialized = $rdf.serialize(resourceSym, graph, resource.url, resource.contentType)
223
+ doWrite(serialized)
224
+ }
197
225
  })
198
226
  }
199
227
 
@@ -82,9 +82,7 @@ class ResourceMapper {
82
82
 
83
83
  // Determine the URL by chopping off everything after the dollar sign
84
84
  const pathname = this._removeDollarExtension(path)
85
- const url = `${this.resolveUrl(hostname)}${
86
- pathname.split('/').map((component) => encodeURIComponent(component)).join('/')
87
- }`
85
+ const url = `${this.resolveUrl(hostname)}${this._encodePath(pathname)}`
88
86
  return { url, contentType: this._getContentTypeFromExtension(path) }
89
87
  }
90
88
 
@@ -95,7 +93,7 @@ class ResourceMapper {
95
93
  contentType = contentType ? contentType.replace(/\s*;.*/, '') : ''
96
94
  // Parse the URL and find the base file path
97
95
  const { pathname, hostname } = this._parseUrl(url)
98
- const filePath = this.resolveFilePath(hostname, decodeURIComponent(pathname))
96
+ const filePath = this.resolveFilePath(hostname, this._decodePath(pathname))
99
97
  if (filePath.indexOf('/..') >= 0) {
100
98
  throw new Error('Disallowed /.. segment in URL')
101
99
  }
@@ -149,6 +147,31 @@ class ResourceMapper {
149
147
  return { path, contentType: contentType || this._defaultContentType }
150
148
  }
151
149
 
150
+ // encode/decode path except slash (/), %encodedSlash (%2F|%2f), or ntimes%encodedSlash (%2525...2F|%2525...2f)
151
+ // see https://github.com/solid/node-solid-server/issues/1666
152
+ _exceptSlash () { return /(\/|%(?:25)*(?:2f))/gi }
153
+
154
+ _encodePath (pathname) {
155
+ return pathname.split(this._exceptSlash())
156
+ .map((el, i) => i % 2 === 0 ? encodeURIComponent(el) : el)
157
+ .join('')
158
+ /* pathArray.forEach((el, i) => {
159
+ if (i % 2 === 0) pathArray[i] = encodeURIComponent(el)
160
+ }) */
161
+ // return pathArray.join('')
162
+ }
163
+
164
+ _decodePath (pathname) {
165
+ return pathname.split(this._exceptSlash())
166
+ .map((el, i) => i % 2 === 0 ? decodeURIComponent(el) : el)
167
+ .join('')
168
+ /* const pathArray = pathname.split(this._exceptSlash())
169
+ pathArray.forEach((el, i) => {
170
+ if (i % 2 === 0) pathArray[i] = decodeURIComponent(el)
171
+ })
172
+ return pathArray.join('') */
173
+ }
174
+
152
175
  // Parses a URL into hostname and pathname
153
176
  _parseUrl (url) {
154
177
  // URL specified as string
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.7.2",
4
+ "version": "5.7.3",
5
5
  "author": {
6
6
  "name": "Tim Berners-Lee",
7
7
  "email": "timbl@w3.org"
@@ -59,46 +59,46 @@
59
59
  "homepage": "https://github.com/solid/node-solid-server",
60
60
  "bugs": "https://github.com/solid/node-solid-server/issues",
61
61
  "dependencies": {
62
- "@fastify/busboy": "^1.0.0",
62
+ "@fastify/busboy": "^1.1.0",
63
63
  "@solid/acl-check": "^0.4.5",
64
- "@solid/oidc-auth-manager": "^0.24.2",
64
+ "@solid/oidc-auth-manager": "^0.24.3",
65
65
  "@solid/oidc-op": "^0.11.6",
66
- "async-lock": "^1.3.1",
66
+ "async-lock": "^1.3.2",
67
67
  "body-parser": "^1.20.0",
68
68
  "bootstrap": "^3.4.1",
69
69
  "cached-path-relative": "^1.1.0",
70
70
  "camelize": "^1.0.0",
71
- "cheerio": "^1.0.0-rc.10",
72
- "colorette": "^2.0.16",
71
+ "cheerio": "^1.0.0-rc.12",
72
+ "colorette": "^2.0.19",
73
73
  "commander": "^8.3.0",
74
74
  "cors": "^2.8.5",
75
75
  "debug": "^4.3.4",
76
- "express": "^4.17.3",
77
- "express-handlebars": "^5.3.4",
78
- "express-session": "^1.17.2",
76
+ "express": "^4.18.1",
77
+ "express-handlebars": "^5.3.5",
78
+ "express-session": "^1.17.3",
79
79
  "extend": "^3.0.2",
80
80
  "from2": "^2.3.0",
81
- "fs-extra": "^10.0.1",
81
+ "fs-extra": "^10.1.0",
82
82
  "get-folder-size": "^2.0.1",
83
- "glob": "^7.2.0",
83
+ "glob": "^7.2.3",
84
84
  "global-tunnel-ng": "^2.7.1",
85
85
  "handlebars": "^4.7.7",
86
- "http-proxy-middleware": "^2.0.4",
87
- "inquirer": "^8.2.2",
86
+ "http-proxy-middleware": "^2.0.6",
87
+ "inquirer": "^8.2.4",
88
88
  "into-stream": "^6.0.0",
89
89
  "ip-range-check": "0.2.0",
90
90
  "is-ip": "^3.1.0",
91
91
  "li": "^1.3.0",
92
- "mashlib": "^1.8.2",
92
+ "mashlib": "^1.8.4",
93
93
  "mime-types": "^2.1.35",
94
94
  "negotiator": "^0.6.3",
95
95
  "node-fetch": "^2.6.7",
96
96
  "node-forge": "^1.3.1",
97
97
  "node-mailer": "^0.1.1",
98
- "nodemailer": "^6.7.3",
98
+ "nodemailer": "^6.7.8",
99
99
  "oidc-op-express": "^0.0.3",
100
100
  "owasp-password-strength-test": "^1.3.0",
101
- "rdflib": "^2.2.19",
101
+ "rdflib": "^2.2.20",
102
102
  "recursive-readdir": "^2.2.2",
103
103
  "request": "^2.88.2",
104
104
  "rimraf": "^3.0.2",
@@ -123,16 +123,16 @@
123
123
  "eslint": "^7.32.0",
124
124
  "localstorage-memory": "1.0.3",
125
125
  "mocha": "^9.2.2",
126
- "nock": "^13.2.4",
126
+ "nock": "^13.2.9",
127
127
  "node-mocks-http": "1.11.0",
128
128
  "nyc": "15.1.0",
129
129
  "pre-commit": "1.2.2",
130
130
  "randombytes": "2.1.0",
131
131
  "sinon": "12.0.1",
132
132
  "sinon-chai": "3.7.0",
133
- "snyk": "^1.906.0",
133
+ "snyk": "^1.997.0",
134
134
  "standard": "16.0.4",
135
- "supertest": "^6.2.2",
135
+ "supertest": "^6.2.4",
136
136
  "turtle-validator": "1.1.1",
137
137
  "whatwg-url": "11.0.0"
138
138
  },