expressa 2.0.4 → 2.0.6

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.
@@ -14,13 +14,11 @@ async function validateDocumentOwner(req, doc) {
14
14
  if (!doc.meta.owner_collection) {
15
15
  throw new util.ApiError(417, 'no owner_collection for owner found')
16
16
  }
17
- if (doc._id !== doc.meta.owner) {
17
+ if (!(doc._id === doc.meta.owner && req.params.collection === doc.meta.owner_collection)) {
18
18
  const count = await req.db[doc.meta.owner_collection].count({ _id: doc.meta.owner }, undefined, 1)
19
19
  if (!count) {
20
20
  throw new util.ApiError(417, 'invalid owner')
21
21
  }
22
- } else if (req.params.collection !== doc.meta.owner_collection) {
23
- throw new util.ApiError(417, 'invalid owner collection')
24
22
  }
25
23
  }
26
24
 
@@ -167,22 +165,37 @@ exports.getById = async function (req) {
167
165
  exports.replaceById = async function (req) {
168
166
  assertValidCollection(req)
169
167
  req.customResponseData = req.customResponseData || {}
168
+ const data = req.body
170
169
  let oldDoc = {}
171
170
  try {
172
171
  oldDoc = await req.db[req.params.collection].get(req.params.id)
173
172
  } catch (error) {
174
173
  // happens when new documents are created via a PUT
175
- // todo: use setDocumentOwner
176
- oldDoc = { meta: { owner: req.user._id } }
174
+ oldDoc = { meta: { owner: req.user._id, owner_collection: 'users' } }
175
+ data._id = req.params.id.trim()
176
+ await setDocumentOwner(req, data)
177
+ }
178
+ if (data._id) {
179
+ data._id = data._id.trim()
180
+ } else {
181
+ data._id = req.params.id.trim()
177
182
  }
178
- const data = req.body
179
- data._id = req.params.id
180
183
  data.meta = data.meta || {}
181
184
  data.meta.created = (oldDoc.meta || {}).created
182
- data.meta.owner = (oldDoc.meta || {}).owner
185
+ if (data.meta.owner !== oldDoc.meta.owner || data.meta.owner_collection !== oldDoc.meta.owner_ollection) {
186
+ if (req.hasPermission(`${req.params.collection}: modify owner`)) {
187
+ if (oldDoc.meta.owner) {
188
+ await validateDocumentOwner(req, data)
189
+ }
190
+ } else {
191
+ debug('attempting to change document owner.')
192
+ data.meta.owner = oldDoc.meta.owner
193
+ data.meta.owner_collection = oldDoc.meta.owner_collection
194
+ }
195
+ }
183
196
  await util.notify('put', req, req.params.collection, data)
184
- await req.db[req.params.collection].update(req.params.id, req.body)
185
- await util.notify('changed', req, req.params.collection, req.body)
197
+ await req.db[req.params.collection].update(req.params.id, data)
198
+ await util.notify('changed', req, req.params.collection, data)
186
199
  return {
187
200
  status: 'OK',
188
201
  id: data._id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expressa",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "API framework using JSON schemas",
5
5
  "main": "index.js",
6
6
  "repository": "https://github.com/thomas4019/expressa",
package/test/testutils.js CHANGED
@@ -85,3 +85,4 @@ exports.clone = util.clone
85
85
  exports.sleep = function sleep(ms) {
86
86
  return new Promise(resolve => setTimeout(resolve, ms))
87
87
  }
88
+ exports.generateDocumentId = util.generateDocumentId
package/test/users.js CHANGED
@@ -232,6 +232,50 @@ describe('user functionality', function () {
232
232
  expect(res2.body.meta.owner).to.equal(user._id)
233
233
  })
234
234
 
235
+ it('cannot change owner with a PUT by default', async function () {
236
+ const token = await testutils.getUserWithPermissions(api, ['users: view', 'users: edit', 'users: view hashed passwords'])
237
+
238
+ const res = await request(app)
239
+ .get(`/users/me`)
240
+ .set('x-access-token', token)
241
+ const newUser = JSON.parse(JSON.stringify(res.body))
242
+
243
+ res.body.meta.owner = user._id
244
+ await request(app)
245
+ .put(`/users/${newUser._id}`)
246
+ .set('x-access-token', token)
247
+ .send(res.body)
248
+ .expect(200)
249
+
250
+ const res2 = await request(app)
251
+ .get(`/users/${newUser._id}`)
252
+ .set('x-access-token', token)
253
+ expect(res2.body.meta.owner).to.not.equal(user._id)
254
+ expect(res2.body.meta.owner).to.equal(newUser._id)
255
+
256
+ })
257
+
258
+ it('can change owner with a PUT with correct permission', async function () {
259
+ const token = await testutils.getUserWithPermissions(api, ['users: view', 'users: edit', 'users: view hashed passwords', 'users: modify owner'])
260
+
261
+ const res = await request(app)
262
+ .get(`/users/me`)
263
+ .set('x-access-token', token)
264
+ const newUser = JSON.parse(JSON.stringify(res.body))
265
+
266
+ res.body.meta.owner = user._id
267
+ await request(app)
268
+ .put(`/users/${newUser._id}`)
269
+ .set('x-access-token', token)
270
+ .send(res.body) // try change owner to another user
271
+ .expect(200)
272
+
273
+ const res2 = await request(app)
274
+ .get(`/users/${newUser._id}`)
275
+ .set('x-access-token', token)
276
+ expect(res2.body.meta.owner).to.equal(user._id)
277
+ })
278
+
235
279
  it('changing to bogus owner fails', async function () {
236
280
  const token = await testutils.getUserWithPermissions(api, ['users: view', 'users: edit', 'users: modify owner'])
237
281
 
@@ -308,4 +352,74 @@ describe('user functionality', function () {
308
352
  expect(res3.body.meta.owner).to.not.equal(newUser._id)
309
353
  expect(res3.body.meta.owner).to.equal(user._id)
310
354
  })
355
+
356
+ it('cannot set owner with a PUT on creation by default', async function () {
357
+ const token = await testutils.getUserWithPermissions(api, ['users: view', 'users: edit', 'testdoc: edit', 'testdoc: view own'])
358
+
359
+ const res = await request(app)
360
+ .get(`/users/me`)
361
+ .set('x-access-token', token)
362
+ const newUser = res.body
363
+
364
+ const doc = {
365
+ title: 'Test Title',
366
+ meta: {
367
+ owner: user._id,
368
+ owner_collection: 'users',
369
+ }
370
+ }
371
+
372
+ const docId = testutils.generateDocumentId()
373
+
374
+ const res2 = await request(app)
375
+ .put(`/testdoc/${docId}`)
376
+ .set('x-access-token', token)
377
+ .send(doc)
378
+ .expect(200) // will succeed but owner will not change
379
+
380
+ expect(res2.body.id).to.equal(docId)
381
+ doc._id = docId
382
+
383
+ const res3 = await request(app)
384
+ .get(`/testdoc/${doc._id}`)
385
+ .set('x-access-token', token)
386
+ .expect(200)
387
+ expect(res3.body.meta.owner).to.not.equal(user._id)
388
+ expect(res3.body.meta.owner).to.equal(newUser._id)
389
+ })
390
+
391
+ it('can set owner with a PUT on creation with correct permission', async function () {
392
+ const token = await testutils.getUserWithPermissions(api, ['users: view', 'users: edit', 'testdoc: edit', 'testdoc: view', 'testdoc: modify owner'])
393
+
394
+ const res = await request(app)
395
+ .get(`/users/me`)
396
+ .set('x-access-token', token)
397
+ const newUser = res.body
398
+
399
+ const doc = {
400
+ title: 'Test Title',
401
+ meta: {
402
+ owner: user._id,
403
+ owner_collection: 'users',
404
+ }
405
+ }
406
+
407
+ const docId = testutils.generateDocumentId()
408
+
409
+ const res2 = await request(app)
410
+ .put(`/testdoc/${docId}`)
411
+ .set('x-access-token', token)
412
+ .send(doc)
413
+ .expect(200) // will succeed but owner will not change
414
+
415
+ expect(res2.body.id).to.equal(docId)
416
+ doc._id = docId
417
+
418
+ const res3 = await request(app)
419
+ .get(`/testdoc/${doc._id}`)
420
+ .set('x-access-token', token)
421
+ .expect(200)
422
+ expect(res3.body.meta.owner).to.not.equal(newUser._id)
423
+ expect(res3.body.meta.owner).to.equal(user._id)
424
+ })
311
425
  })