solid-server 5.7.7 → 5.7.8

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.
@@ -17,7 +17,7 @@ jobs:
17
17
 
18
18
  strategy:
19
19
  matrix:
20
- node-version: [12.x, 14.x, 16.x]
20
+ node-version: [16.x, 18.x]
21
21
  os: [ubuntu-latest]
22
22
 
23
23
  steps:
@@ -97,4 +97,4 @@ jobs:
97
97
  build-args: SOLID_SERVER_VERSION=${{ steps.tagName.outputs.version }}
98
98
  push: true
99
99
  tags: ${{ steps.meta.outputs.tags }}
100
- labels: ${{ steps.meta.outputs.labels }}
100
+ labels: ${{ steps.meta.outputs.labels }}
package/README.md CHANGED
@@ -9,6 +9,8 @@
9
9
 
10
10
  `solid-server` lets you run a Solid server on top of the file-system. You can use it as a [command-line tool](https://github.com/solid/node-solid-server/blob/master/README.md#command-line-usage) (easy) or as a [library](https://github.com/solid/node-solid-server/blob/master/README.md#library-usage) (advanced).
11
11
 
12
+ The [solid test suite](https://github.com/nodeSolidServer/node-solid-server/blob/main/test/surface/run-solid-test-suite.sh) runs as part of GitHub Actions on this repository, ensuring that this server is always (to the best of our knowledge) fully spec compliant.
13
+
12
14
  ## Solid Features supported
13
15
  - [x] [Linked Data Platform](http://www.w3.org/TR/ldp/)
14
16
  - [x] [Web Access Control](http://www.w3.org/wiki/WebAccessControl)
@@ -28,7 +28,14 @@ class ACLChecker {
28
28
  constructor (resource, options = {}) {
29
29
  this.resource = resource
30
30
  this.resourceUrl = new URL(resource)
31
- this.agentOrigin = options.strictOrigin && options.agentOrigin ? rdf.sym(options.agentOrigin) : null
31
+ this.agentOrigin = null
32
+ try {
33
+ if (options.strictOrigin && options.agentOrigin) {
34
+ this.agentOrigin = rdf.sym(options.agentOrigin)
35
+ }
36
+ } catch (e) {
37
+ // noop
38
+ }
32
39
  this.fetch = options.fetch
33
40
  this.fetchGraph = options.fetchGraph
34
41
  this.trustedOrigins = options.strictOrigin && options.trustedOrigins ? options.trustedOrigins.map(trustedOrigin => rdf.sym(trustedOrigin)) : null
@@ -72,9 +72,10 @@ function allow (mode) {
72
72
  }
73
73
  }
74
74
 
75
- // check user is owner. Find owner from /.meta
76
- if (resourceUrl.endsWith('.acl') && userId === await ldp.getOwner(req.hostname)) return next()
77
-
75
+ // check if user is owner. Check isOwner from /.meta
76
+ try {
77
+ if (resourceUrl.endsWith('.acl') && (await ldp.isOwner(userId, req.hostname))) return next()
78
+ } catch (err) {}
78
79
  const error = req.authError || await req.acl.getError(userId, mode)
79
80
  debug(`${mode} access denied to ${userId || '(none)'}: ${error.status} - ${error.message}`)
80
81
  next(error)
@@ -143,8 +143,6 @@ async function checkPermission (request, patchObject, resourceExists) {
143
143
  // Now that we know the details of the patch,
144
144
  // we might need to perform additional checks.
145
145
  let modes = []
146
- // acl:default Write is required for create
147
- if (!resourceExists) modes = ['Write']
148
146
  const { acl, session: { userId } } = request
149
147
  // Read access is required for DELETE and WHERE.
150
148
  // If we would allows users without read access,
@@ -164,7 +162,7 @@ async function checkPermission (request, patchObject, resourceExists) {
164
162
  if (!allAllowed) {
165
163
  // check owner with Control
166
164
  const ldp = request.app.locals.ldp
167
- if (request.path.endsWith('.acl') && userId === await ldp.getOwner(request.hostname)) return Promise.resolve(patchObject)
165
+ if (request.path.endsWith('.acl') && await ldp.isOwner(userId, request.hostname)) return Promise.resolve(patchObject)
168
166
 
169
167
  const errors = await Promise.all(modes.map(mode => acl.getError(userId, mode)))
170
168
  const error = errors.filter(error => !!error)
package/lib/header.js CHANGED
@@ -128,7 +128,7 @@ async function addPermissions (req, res, next) {
128
128
  getPermissionsFor(acl, null, req),
129
129
  getPermissionsFor(acl, session.userId, req)
130
130
  ])
131
- if (resource.endsWith('.acl') && userPerms === '' && session.userId === await ldp.getOwner(req.hostname)) userPerms = 'control'
131
+ if (resource.endsWith('.acl') && userPerms === '' && await ldp.isOwner(session.userId, req.hostname)) userPerms = 'control'
132
132
  debug.ACL(`Permissions on ${resource} for ${session.userId || '(none)'}: ${userPerms}`)
133
133
  debug.ACL(`Permissions on ${resource} for public: ${publicPerms}`)
134
134
  res.set('WAC-Allow', `user="${userPerms}",public="${publicPerms}"`)
package/lib/ldp.js CHANGED
@@ -243,7 +243,14 @@ class LDP {
243
243
  'PUT request requires a content-type via the Content-Type header')
244
244
  }
245
245
 
246
+ // reject resource with percent-encoded $ extension
247
+ const dollarExtensionRegex = /%(?:24)\.[^%(?:24)]*$/ // /\$\.[^$]*$/
248
+ if ((url.url || url).match(dollarExtensionRegex)) {
249
+ throw error(400, 'Resource with a $.ext is not allowed by the server')
250
+ }
251
+
246
252
  // check if a folder or file with same name exists
253
+ // const urlItem = url.url || url
247
254
  await this.checkItemName(url)
248
255
 
249
256
  // First check if we are above quota
@@ -350,17 +357,27 @@ class LDP {
350
357
 
351
358
  async checkItemName (url) {
352
359
  let testName
353
- const itemUrl = (url.url || url)
360
+ const { hostname, pathname } = this.resourceMapper._parseUrl(url) // (url.url || url)
361
+ let itemUrl = this.resourceMapper.resolveUrl(hostname, pathname)
354
362
  const container = itemUrl.endsWith('/')
355
363
  try {
356
364
  const testUrl = container ? itemUrl.slice(0, -1) : itemUrl + '/'
357
365
  const { path: testPath } = await this.resourceMapper.mapUrlToFile({ url: testUrl })
358
- // testName = fs.lstatSync(testPath).isDirectory()
359
366
  testName = container ? fs.lstatSync(testPath).isFile() : fs.lstatSync(testPath).isDirectory()
360
- } catch (err) { testName = false }
361
-
367
+ } catch (err) {
368
+ testName = false
369
+
370
+ // item does not exist, check one level up the tree
371
+ if (itemUrl.endsWith('/')) itemUrl = itemUrl.substring(0, itemUrl.length - 1)
372
+ itemUrl = itemUrl.substring(0, itemUrl.lastIndexOf('/') + 1)
373
+ const { pathname } = this.resourceMapper._parseUrl(itemUrl) // (url.url || url)
374
+ // check not at root
375
+ if (pathname !== '/') {
376
+ await this.checkItemName(itemUrl)
377
+ }
378
+ }
362
379
  if (testName) {
363
- throw error(200, 'Container and resource cannot have the same name in URI')
380
+ throw error(404, 'Container and resource cannot have the same name in URI')
364
381
  }
365
382
  }
366
383
 
@@ -437,7 +454,7 @@ class LDP {
437
454
  // this is a hack to replace solid:owner, using solid:account in /.meta to avoid NSS migration
438
455
  // this /.meta has no functionality in actual NSS
439
456
  // comment https://github.com/solid/node-solid-server/pull/1604#discussion_r652903546
440
- async getOwner (hostname) {
457
+ async isOwner (webId, hostname) {
441
458
  // const ldp = req.app.locals.ldp
442
459
  const rootUrl = this.resourceMapper.resolveUrl(hostname)
443
460
  let graph
@@ -445,8 +462,8 @@ class LDP {
445
462
  // TODO check for permission ?? Owner is a MUST
446
463
  graph = await this.getGraph(rootUrl + '/.meta')
447
464
  const SOLID = $rdf.Namespace('http://www.w3.org/ns/solid/terms#')
448
- const owner = await graph.any(null, SOLID('account'), $rdf.sym(rootUrl + '/'))
449
- return owner.uri
465
+ const owner = await graph.statementsMatching($rdf.sym(webId), SOLID('account'), $rdf.sym(rootUrl + '/'))
466
+ return owner.length
450
467
  } catch (error) {
451
468
  throw new Error(`Failed to get owner from ${rootUrl}/.meta, got ` + error)
452
469
  }
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.7",
4
+ "version": "5.7.8",
5
5
  "author": {
6
6
  "name": "Tim Berners-Lee",
7
7
  "email": "timbl@w3.org"
@@ -69,7 +69,7 @@
69
69
  "cached-path-relative": "^1.1.0",
70
70
  "camelize": "^1.0.1",
71
71
  "cheerio": "^1.0.0-rc.12",
72
- "colorette": "^2.0.19",
72
+ "colorette": "^2.0.20",
73
73
  "commander": "^8.3.0",
74
74
  "cors": "^2.8.5",
75
75
  "debug": "^4.3.4",
@@ -82,27 +82,27 @@
82
82
  "get-folder-size": "^2.0.1",
83
83
  "glob": "^7.2.3",
84
84
  "global-tunnel-ng": "^2.7.1",
85
- "handlebars": "^4.7.7",
85
+ "handlebars": "^4.7.8",
86
86
  "http-proxy-middleware": "^2.0.6",
87
- "inquirer": "^8.2.5",
87
+ "inquirer": "^8.2.6",
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.8",
92
+ "mashlib": "^1.8.9",
93
93
  "mime-types": "^2.1.35",
94
94
  "negotiator": "^0.6.3",
95
- "node-fetch": "^2.6.9",
95
+ "node-fetch": "^2.7.0",
96
96
  "node-forge": "^1.3.1",
97
97
  "node-mailer": "^0.1.1",
98
- "nodemailer": "^6.9.1",
98
+ "nodemailer": "^6.9.7",
99
99
  "oidc-op-express": "^0.0.3",
100
100
  "owasp-password-strength-test": "^1.3.0",
101
101
  "recursive-readdir": "^2.2.3",
102
102
  "request": "^2.88.2",
103
103
  "rimraf": "^3.0.2",
104
104
  "solid-auth-client": "^2.5.6",
105
- "solid-namespace": "^0.5.2",
105
+ "solid-namespace": "^0.5.3",
106
106
  "solid-ws": "^0.4.3",
107
107
  "text-encoder-lite": "^2.0.0",
108
108
  "the-big-username-blacklist": "^1.5.2",
@@ -110,26 +110,26 @@
110
110
  "urijs": "^1.19.11",
111
111
  "uuid": "^8.3.2",
112
112
  "valid-url": "^1.0.9",
113
- "validator": "^13.9.0",
113
+ "validator": "^13.11.0",
114
114
  "vhost": "^3.0.2"
115
115
  },
116
116
  "devDependencies": {
117
- "@solid/solid-auth-oidc": "^0.3.0",
118
- "chai": "^4.3.7",
117
+ "@solid/solid-auth-oidc": "0.3.0",
118
+ "chai": "^4.3.10",
119
119
  "chai-as-promised": "7.1.1",
120
120
  "cross-env": "7.0.3",
121
121
  "dirty-chai": "2.0.1",
122
122
  "eslint": "^7.32.0",
123
123
  "localstorage-memory": "1.0.3",
124
124
  "mocha": "^9.2.2",
125
- "nock": "^13.3.0",
126
- "node-mocks-http": "^1.12.2",
125
+ "nock": "^13.4.0",
126
+ "node-mocks-http": "^1.14.0",
127
127
  "nyc": "15.1.0",
128
128
  "pre-commit": "1.2.2",
129
129
  "randombytes": "2.1.0",
130
130
  "sinon": "12.0.1",
131
131
  "sinon-chai": "3.7.0",
132
- "snyk": "^1.1119.0",
132
+ "snyk": "^1.1264.0",
133
133
  "standard": "16.0.4",
134
134
  "supertest": "^6.3.3",
135
135
  "turtle-validator": "1.1.1",