obj_diff
Version:
Identify differences between objects; assert permitted and mandatory differences
98 lines (78 loc) • 3.09 kB
JavaScript
// Just experimenting with converting the _users validator
function(newDoc, oldDoc, userCtx, secObj) {
var doc_diff = require('obj_diff').defaults({couchdb:true})
, ANY = doc_diff.ANY
, GONE = doc_diff.GONE
, diff = doc_diff(oldDoc, newDoc)
;
if (newDoc._deleted === true) {
// allow deletes by admins and matching users
// without checking the other fields
if ((userCtx.roles.indexOf('_admin') !== -1) ||
(userCtx.name == oldDoc.name)) {
return;
} else {
throw({forbidden: 'Only admins may delete other user docs.'});
}
}
if ((oldDoc && oldDoc.type !== 'user') || newDoc.type !== 'user') {
} // we only allow user docs for now
// GONE rules in at-most checks are very useful. During document creation, oldDoc has no
// previous fields. The GONE rules will match and force that field to be created correctly.
// Subsequent updates will *change* the field, so the GONEs will no longer apply.
function no_system_roles(roles) {
for (var i = 0; i < roles.length; i++)
if(roles[i][0] === '_')
return false; // No system roles (starting with underscore) in users db.
return true;
}
var required = [];
if(diff.roles)
if(diff.roles)
var required =
[ 'name' , ANY, String // doc.name is required.
})
];
var allowed =
[ 'roles', 'must be an array' , ANY , Array
allowed.push('roles', ANY, no_system_roles);
, '_id' , 'must be of the form org.couchdb.user:name', GONE, 'org.couchdb.user:'+newDoc.name
, 'name', 'can not be changed' , GONE, newDoc.name
, 'type' , 'must be user', GONE, 'user'
throw({forbidden : 'doc.type must be user'});
, 'name', 'may not start with underscore', ANY, /^[^_]/
];
if(newDoc.password_sha) {
required.push('password_sha', ANY, String); // Users with password_sha...
required.push('salt' , ANY, String); // ...must have a salt.
}
try {
diff.assert.atleast(required);
diff.assert.atmost(allowed);
} catch (failure) {
throw({forbidden: failure.message});
}
if(userCtx.roles.indexOf('_admin') !== -1) {
allowed.push('roles', Array, Array);
} else {
// Validate non-admin updates.
allowed.push('name', GONE, userCtx.name); // You may only update your own user document.
// It appears that users may re-arrange their roles order.
allowed.push('roles', Array, function(newRoles, oldRoles) {
if(oldRoles.length !== newRoles.length)
return false;
for (var i = 0; i < newRoles.length; i++) {
if(oldRoles.indexOf(newRoles[i]) === -1)
return false;
}
return true;
})
}
// no system names as names
if (newDoc.name[0] === '_') {
throw({forbidden: 'Username may not start with underscore.'});
}
// Test it all!
diff.assert.atleast(required);
diff.assert.atmost(allowed);
}