Last active
August 29, 2015 13:56
-
-
Save isaacs/8926985 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"_id": "_design/_auth", | |
"language": "javascript", | |
"lists": { | |
"index": "function (head,req) {\n var row\n , out = {}\n , id, data\n while (row = getRow()) {\n id = row.id.replace(/^org\\.couchdb\\.user:/, '')\n data = row.value\n delete data._id\n delete data._rev\n delete data.salt\n delete data.password_sha\n delete data.type\n delete data.roles\n delete data._deleted_conflicts\n out[id] = data\n }\n send(toJSON(out))\n }", | |
"email": "function (head, req) {\n var row\n , data\n , id\n , email = req.query.email || undefined\n , out = []\n while (row = getRow()) {\n id = row.id.replace(/^org\\.couchdb\\.user:/, '')\n data = row.value\n var dm = data.email || undefined\n if (data.email !== email) continue\n out.push(row.value.name)\n }\n send(toJSON(out))\n }" | |
}, | |
"validate_doc_update": "function (newDoc, oldDoc, userCtx, secObj) {\n if (newDoc._deleted === true) {\n // allow deletes by admins\n if ((userCtx.roles.indexOf('_admin') !== -1)) {\n return;\n } else {\n throw({forbidden: 'Only admins may delete user docs.'});\n }\n }\n\n if ((oldDoc && oldDoc.type !== 'user') || newDoc.type !== 'user') {\n throw({forbidden : 'doc.type must be user'});\n } // we only allow user docs for now\n\n if (!newDoc.name) {\n throw({forbidden: 'doc.name is required'});\n }\n\n if (newDoc.roles && !isArray(newDoc.roles)) {\n throw({forbidden: 'doc.roles must be an array'});\n }\n\n if (newDoc._id !== ('org.couchdb.user:' + newDoc.name)) {\n throw({\n forbidden: 'Doc ID must be of the form org.couchdb.user:name'\n });\n }\n\n if (newDoc.name !== newDoc.name.toLowerCase()) {\n throw({\n forbidden: 'Name must be lower-case'\n })\n }\n\n if (newDoc.name !== encodeURIComponent(newDoc.name)) {\n throw({\n forbidden: 'Name cannot contain non-url-safe characters'\n })\n }\n\n if (newDoc.name.charAt(0) === '.') {\n throw({\n forbidden: 'Name cannot start with .'\n })\n }\n\n if (!(newDoc.email && newDoc.email.match(/^.+@.+\\..+$/))) {\n throw({forbidden: 'Email must be an email address'})\n }\n\n if (oldDoc) { // validate all updates\n if (oldDoc.name !== newDoc.name) {\n throw({forbidden: 'Usernames can not be changed.'});\n }\n }\n\n if (newDoc.password_sha && !newDoc.salt) {\n throw({\n forbidden: 'Users with password_sha must have a salt.'\n });\n }\n\n var is_server_or_database_admin = function(userCtx, secObj) {\n // see if the user is a server admin\n if(userCtx.roles.indexOf('_admin') !== -1) {\n return true; // a server admin\n }\n\n // see if the user a database admin specified by name\n if(secObj && secObj.admins && secObj.admins.names) {\n if(secObj.admins.names.indexOf(userCtx.name) !== -1) {\n return true; // database admin\n }\n }\n\n // see if the user a database admin specified by role\n if(secObj && secObj.admins && secObj.admins.roles) {\n var db_roles = secObj.admins.roles;\n for(var idx = 0; idx < userCtx.roles.length; idx++) {\n var user_role = userCtx.roles[idx];\n if(db_roles.indexOf(user_role) !== -1) {\n return true; // role matches!\n }\n }\n }\n\n return false; // default to no admin\n }\n\n if (newDoc.name.length > 50) {\n throw({\n forbidden: 'Username is too long. Pick a shorter one.'\n })\n }\n\n if (!is_server_or_database_admin(userCtx, secObj)) {\n if (oldDoc) { // validate non-admin updates\n if (userCtx.name !== newDoc.name) {\n throw({\n forbidden: 'You may only update your own user document.'\n });\n }\n if (oldDoc.email !== newDoc.email) {\n throw({\n forbidden: 'You may not change your email address\\n' +\n 'Please visit https://npmjs.org/email-edit to do so.'\n })\n }\n // validate role updates\n var oldRoles = oldDoc.roles.sort();\n var newRoles = newDoc.roles.sort();\n\n if (oldRoles.length !== newRoles.length) {\n throw({forbidden: 'Only _admin may edit roles'});\n }\n\n for (var i = 0; i < oldRoles.length; i++) {\n if (oldRoles[i] !== newRoles[i]) {\n throw({forbidden: 'Only _admin may edit roles'});\n }\n }\n } else if (newDoc.roles.length > 0) {\n throw({forbidden: 'Only _admin may set roles'});\n }\n }\n\n // no system roles in users db\n for (var i = 0; i < newDoc.roles.length; i++) {\n if (newDoc.roles[i][0] === '_') {\n throw({\n forbidden: 'No system roles (starting with underscore) in users db.'\n });\n }\n }\n\n // no system names as names\n if (newDoc.name[0] === '_') {\n throw({forbidden: 'Username may not start with underscore.'});\n }\n\n var badUserNameChars = [':'];\n\n for (var i = 0; i < badUserNameChars.length; i++) {\n if (newDoc.name.indexOf(badUserNameChars[i]) >= 0) {\n throw({forbidden: 'Character `' + badUserNameChars[i] +\n '` is not allowed in usernames.'});\n }\n }\n}", | |
"views": { | |
"listAll": { | |
"map": "function (doc) { return emit(doc._id, doc) }" | |
}, | |
"invalidUser": { | |
"map": "function (doc) {\n var errors = []\n if (doc.type !== 'user') {\n errors.push('doc.type must be user')\n }\n\n if (!doc.name) {\n errors.push('doc.name is required')\n }\n\n if (doc.roles && !isArray(doc.roles)) {\n errors.push('doc.roles must be an array')\n }\n\n if (doc._id !== ('org.couchdb.user:' + doc.name)) {\n errors.push('Doc ID must be of the form org.couchdb.user:name')\n }\n\n if (doc.name !== doc.name.toLowerCase()) {\n errors.push('Name must be lower-case')\n }\n\n if (doc.name !== encodeURIComponent(doc.name)) {\n errors.push('Name cannot contain non-url-safe characters')\n }\n\n if (doc.name.charAt(0) === '.') {\n errors.push('Name cannot start with .')\n }\n\n if (!(doc.email && doc.email.match(/^.+@.+\\..+$/))) {\n errors.push('Email must be an email address')\n }\n\n if (doc.password_sha && !doc.salt) {\n errors.push('Users with password_sha must have a salt.')\n }\n if (!errors.length) return\n emit([doc.name, doc.email], errors)\n }" | |
}, | |
"invalid": { | |
"map": "function (doc) {\n if (doc.type !== 'user') {\n return emit(['doc.type must be user', doc.email, doc.name], 1)\n }\n\n if (!doc.name) {\n return emit(['doc.name is required', doc.email, doc.name], 1)\n }\n\n if (doc.roles && !isArray(doc.roles)) {\n return emit(['doc.roles must be an array', doc.email, doc.name], 1)\n }\n\n if (doc._id !== ('org.couchdb.user:' + doc.name)) {\n return emit(['Doc ID must be of the form org.couchdb.user:name', doc.email, doc.name], 1)\n }\n\n if (doc.name !== doc.name.toLowerCase()) {\n return emit(['Name must be lower-case', doc.email, doc.name], 1)\n }\n\n if (doc.name !== encodeURIComponent(doc.name)) {\n return emit(['Name cannot contain non-url-safe characters', doc.email, doc.name], 1)\n }\n\n if (doc.name.charAt(0) === '.') {\n return emit(['Name cannot start with .', doc.email, doc.name], 1)\n }\n\n if (!(doc.email && doc.email.match(/^.+@.+\\..+$/))) {\n return emit(['Email must be an email address', doc.email, doc.name], 1)\n }\n\n if (doc.password_sha && !doc.salt) {\n return emit(['Users with password_sha must have a salt.', doc.email, doc.name], 1)\n }\n }", | |
"reduce": "_sum" | |
}, | |
"conflicts": { | |
"map": "function (doc) {\n if (doc._conflicts) {\n for (var i = 0; i < doc._conflicts.length; i++) {\n emit([doc._id, doc._conflicts[i]], 1)\n }\n }\n}", | |
"reduce": "_sum" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment