authsome
Advanced tools
Comparing version 0.0.7 to 0.0.8
@@ -28,4 +28,10 @@ 'use strict'; | ||
class Authsome { | ||
constructor(config, context) { | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var Authsome = function () { | ||
function Authsome(config, context) { | ||
_classCallCheck(this, Authsome); | ||
if (config) { | ||
@@ -44,13 +50,18 @@ this.mode = config.mode; | ||
can(user, operation, object) { | ||
if (this.mode === 'freefornone') { | ||
return Promise.resolve(false); | ||
} else { | ||
let result = this.mode(user, operation, object, this.context); | ||
let isPromise = typeof result.then === 'function'; | ||
return isPromise ? result : Promise.resolve(result); | ||
_createClass(Authsome, [{ | ||
key: 'can', | ||
value: function can(user, operation, object) { | ||
if (this.mode === 'freefornone') { | ||
return Promise.resolve(false); | ||
} else { | ||
var result = this.mode(user, operation, object, this.context); | ||
var isPromise = typeof result.then === 'function'; | ||
return isPromise ? result : Promise.resolve(result); | ||
} | ||
} | ||
} | ||
} | ||
}]); | ||
return Authsome; | ||
}(); | ||
module.exports = Authsome; |
@@ -0,1 +1,121 @@ | ||
'use strict'; | ||
var blog = function () { | ||
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(userId, operation, object, context) { | ||
var user, collection, fragment; | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
if (userId) { | ||
_context.next = 2; | ||
break; | ||
} | ||
return _context.abrupt('return', unauthenticatedUser(operation, object)); | ||
case 2: | ||
_context.next = 4; | ||
return context.models.User.find(userId); | ||
case 4: | ||
user = _context.sent; | ||
if (!(user && user.admin === true)) { | ||
_context.next = 7; | ||
break; | ||
} | ||
return _context.abrupt('return', true); | ||
case 7: | ||
if (!(object.type === 'collection')) { | ||
_context.next = 15; | ||
break; | ||
} | ||
collection = object; | ||
if (!isOwner(user, collection)) { | ||
_context.next = 11; | ||
break; | ||
} | ||
return _context.abrupt('return', true); | ||
case 11: | ||
if (!teamPermissions(user, operation, collection)) { | ||
_context.next = 13; | ||
break; | ||
} | ||
return _context.abrupt('return', true); | ||
case 13: | ||
_context.next = 27; | ||
break; | ||
case 15: | ||
if (!(object.type === 'fragment')) { | ||
_context.next = 25; | ||
break; | ||
} | ||
fragment = object; | ||
if (!isOwner(user, fragment)) { | ||
_context.next = 19; | ||
break; | ||
} | ||
return _context.abrupt('return', true); | ||
case 19: | ||
if (!teamPermissions(user, operation, fragment)) { | ||
_context.next = 21; | ||
break; | ||
} | ||
return _context.abrupt('return', true); | ||
case 21: | ||
if (!(Array.isArray(fragment.parents) && teamPermissions(user, operation, fragment.parents[0]))) { | ||
_context.next = 23; | ||
break; | ||
} | ||
return _context.abrupt('return', true); | ||
case 23: | ||
_context.next = 27; | ||
break; | ||
case 25: | ||
if (!(object.type === 'user')) { | ||
_context.next = 27; | ||
break; | ||
} | ||
return _context.abrupt('return', user.id === object.id); | ||
case 27: | ||
return _context.abrupt('return', unauthenticatedUser(operation, object)); | ||
case 28: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee, this); | ||
})); | ||
return function blog(_x, _x2, _x3, _x4) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}(); | ||
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } | ||
var pick = require('lodash/pick'); | ||
function isPublished(fragment) { | ||
@@ -10,7 +130,3 @@ return fragment.published; | ||
for (const ownerId of object.owners) { | ||
if (ownerId === user.id) { | ||
return true; | ||
} | ||
} | ||
return object.owners.includes(user.id); | ||
} | ||
@@ -23,25 +139,14 @@ | ||
for (const team of user.teams) { | ||
if (team.teamType.permissions === 'POST' && team.object.id === object.id && operation === 'POST') { | ||
return true; | ||
} else if (team.teamType.permissions === 'PATCH' && team.object.id === object.id && operation === 'PATCH') { | ||
return true; | ||
} | ||
} | ||
return false; | ||
return user.teams.some(function (team) { | ||
return ['POST', 'PATCH'].includes(operation) && operation === team.teamType.permissions && team.object.id === object.id; | ||
}); | ||
} | ||
function unauthenticatedUser(operation, object) { | ||
// Public/unauthenticated users can GET /collections, filtered by 'published' | ||
if (operation === 'GET' && object && object.path === '/collections') { | ||
return { | ||
filter: collection => collection.published | ||
}; | ||
} | ||
// Public/unauthenticated users can GET /collections/:id/fragments, filtered by 'published' | ||
if (operation === 'GET' && object && object.path === '/collections/:id/fragments') { | ||
return { | ||
filter: fragment => fragment.published | ||
filter: function filter(fragments) { | ||
return fragments.filter(isPublished); | ||
} | ||
}; | ||
@@ -52,15 +157,15 @@ } | ||
if (operation === 'GET' && object && object.type === 'collection') { | ||
if (object.published) { | ||
return { | ||
filter: (_, key) => ['id', 'title', 'owners'].includes(key) | ||
}; | ||
} | ||
return { | ||
filter: function filter(collection) { | ||
return pick(collection, ['id', 'title', 'owners']); | ||
} | ||
}; | ||
} | ||
if (operation === 'GET' && object && object.type === 'fragment') { | ||
if (object.published) { | ||
return { | ||
filter: (_, key) => ['id', 'title', 'source', 'presentation', 'owners'].includes(key) | ||
}; | ||
} | ||
if (operation === 'GET' && object && object.type === 'fragment' && object.published) { | ||
return { | ||
filter: function filter(fragment) { | ||
return pick(fragment, ['id', 'title', 'source', 'presentation', 'owners']); | ||
} | ||
}; | ||
} | ||
@@ -71,46 +176,2 @@ | ||
var blog = function (user, operation, object, context) { | ||
// Admins can do anything | ||
if (user && user.admin === true) return true; | ||
if (!user) { | ||
return unauthenticatedUser(operation, object); | ||
} | ||
let collection; | ||
if (object.type === 'collection') { | ||
collection = object; | ||
if (isOwner(user, collection)) { | ||
return true; | ||
} | ||
if (teamPermissions(user, operation, collection)) { | ||
return true; | ||
} | ||
} else if (object.type === 'fragment') { | ||
let fragment = object; | ||
if (isPublished(fragment) && operation === 'GET') { | ||
return true; | ||
} | ||
if (isOwner(user, fragment)) { | ||
return true; | ||
} | ||
if (teamPermissions(user, operation, fragment)) { | ||
return true; | ||
} | ||
if (Array.isArray(fragment.parents)) { | ||
collection = fragment.parents[0]; | ||
return teamPermissions(user, operation, collection); | ||
} | ||
} else if (object.type === 'user') { | ||
return user.id === object.id; | ||
} | ||
return false; | ||
}; | ||
module.exports = blog; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
function isAllowed(operation, permission) { | ||
@@ -31,13 +33,55 @@ if ((operation === 'read' || operation === 'update' || operation === 'delete') && permission === 'delete') { | ||
for (const objectOwnerId of object.owners) { | ||
if (objectOwnerId === user.id) { | ||
return true; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = object.owners[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var objectOwnerId = _step.value; | ||
if (objectOwnerId === user.id) { | ||
return true; | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
if (Array.isArray(object.parents)) { | ||
for (const parent of object.parents) { | ||
if (parent.owners.includes(user)) { | ||
return true; | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator2 = object.parents[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var parent = _step2.value; | ||
if (parent.owners.includes(user)) { | ||
return true; | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
@@ -48,22 +92,64 @@ } | ||
for (const team of user.teams) { | ||
if (team.teamType.active) { | ||
if (isAllowed(operation, team.teamType.permissions) && team.object === object && team.teamType.active(object)) { | ||
return true; | ||
var _iteratorNormalCompletion3 = true; | ||
var _didIteratorError3 = false; | ||
var _iteratorError3 = undefined; | ||
try { | ||
for (var _iterator3 = user.teams[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { | ||
var team = _step3.value; | ||
if (team.teamType.active) { | ||
if (isAllowed(operation, team.teamType.permissions) && team.object === object && team.teamType.active(object)) { | ||
return true; | ||
} | ||
} else { | ||
if (isAllowed(operation, team.teamType.permissions) && team.object === object) { | ||
return true; | ||
} | ||
} | ||
} else { | ||
if (isAllowed(operation, team.teamType.permissions) && team.object === object) { | ||
return true; | ||
} | ||
// Users with permissions for parents of object | ||
// This is only applicable in certain states | ||
} catch (err) { | ||
_didIteratorError3 = true; | ||
_iteratorError3 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion3 && _iterator3.return) { | ||
_iterator3.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError3) { | ||
throw _iteratorError3; | ||
} | ||
} | ||
} | ||
// Users with permissions for parents of object | ||
// This is only applicable in certain states | ||
if ((object.state === 'submitted' || object.state === undefined) && Array.isArray(object.parents)) { | ||
var _iteratorNormalCompletion4 = true; | ||
var _didIteratorError4 = false; | ||
var _iteratorError4 = undefined; | ||
if ((object.state === 'submitted' || object.state === undefined) && Array.isArray(object.parents)) { | ||
for (const parent of object.parents) { | ||
if (can(user, operation, parent)) { | ||
return true; | ||
try { | ||
for (var _iterator4 = object.parents[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { | ||
var _parent = _step4.value; | ||
if (can(user, operation, _parent)) { | ||
return true; | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError4 = true; | ||
_iteratorError4 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion4 && _iterator4.return) { | ||
_iterator4.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError4) { | ||
throw _iteratorError4; | ||
} | ||
} | ||
} | ||
@@ -70,0 +156,0 @@ } |
@@ -1,12 +0,35 @@ | ||
var noon = function (user, operation, object) { | ||
let fragment = object; | ||
let collection = fragment.parents[0]; | ||
'use strict'; | ||
var noon = function noon(user, operation, object) { | ||
var fragment = object; | ||
var collection = fragment.parents[0]; | ||
if (user.admin === true) return true; | ||
if (operation === 'update' || operation === 'delete') { | ||
for (const fragmentOwnerId of fragment.owners) { | ||
if (fragmentOwnerId === user.id) { | ||
return true; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = fragment.owners[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var fragmentOwnerId = _step.value; | ||
if (fragmentOwnerId === user.id) { | ||
return true; | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
@@ -16,28 +39,71 @@ } | ||
if (operation === 'create') { | ||
for (const collectionOwnerId of collection.owners) { | ||
if (collectionOwnerId === user.id) { | ||
return true; | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator2 = collection.owners[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var collectionOwnerId = _step2.value; | ||
if (collectionOwnerId === user.id) { | ||
return true; | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
} | ||
for (const team of user.teams) { | ||
if (team.teamType.active()) { | ||
if (team.teamType.permissions === 'all' && team.object === collection && operation === 'create') { | ||
return true; | ||
} | ||
var _iteratorNormalCompletion3 = true; | ||
var _didIteratorError3 = false; | ||
var _iteratorError3 = undefined; | ||
if (team.teamType.permissions === 'all' && team.object === fragment && (operation === 'update' || operation === 'delete')) { | ||
return true; | ||
} | ||
try { | ||
for (var _iterator3 = user.teams[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { | ||
var team = _step3.value; | ||
if (team.teamType.permissions === 'create' && team.object === collection && operation === 'create') { | ||
return true; | ||
} | ||
if (team.teamType.active()) { | ||
if (team.teamType.permissions === 'all' && team.object === collection && operation === 'create') { | ||
return true; | ||
} | ||
if (team.teamType.permissions === 'update' && team.object === fragment && operation === 'update') { | ||
return true; | ||
if (team.teamType.permissions === 'all' && team.object === fragment && (operation === 'update' || operation === 'delete')) { | ||
return true; | ||
} | ||
if (team.teamType.permissions === 'create' && team.object === collection && operation === 'create') { | ||
return true; | ||
} | ||
if (team.teamType.permissions === 'update' && team.object === fragment && operation === 'update') { | ||
return true; | ||
} | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError3 = true; | ||
_iteratorError3 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion3 && _iterator3.return) { | ||
_iterator3.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError3) { | ||
throw _iteratorError3; | ||
} | ||
} | ||
} | ||
return false; | ||
@@ -44,0 +110,0 @@ }; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
// WARNING: Used purely for testing reasons | ||
@@ -6,3 +8,3 @@ // - Everything is allowed for owners of objects or the objects' parents | ||
// - User with id user_3 gets filteret results | ||
var test = function (user, operation, object, context) { | ||
var test = function test(user, operation, object, context) { | ||
if (!user) { | ||
@@ -23,3 +25,5 @@ if (operation === 'GET' && object.public) { | ||
permission: 'filter', | ||
filter: object => object.owners.includes('user_3') | ||
filter: function filter(object) { | ||
return object.owners.includes('user_3'); | ||
} | ||
}; | ||
@@ -29,3 +33,5 @@ } else if (object && object.type === 'collection') { | ||
permission: 'filter', | ||
filter: (value, key) => key === 'id' | ||
filter: function filter(value, key) { | ||
return key === 'id'; | ||
} | ||
}; | ||
@@ -44,3 +50,3 @@ } | ||
return context.models.collection.find(object.parents[0]).then(collection => { | ||
return context.models.collection.find(object.parents[0]).then(function (collection) { | ||
if (collection.owners.includes(user.id)) { | ||
@@ -47,0 +53,0 @@ return true; |
{ | ||
"name": "authsome", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "Flexible team-based authorization", | ||
@@ -23,4 +23,4 @@ "main": "dist/index.js", | ||
"babel-core": "^6.10.4", | ||
"babel-plugin-array-includes": "^2.0.3", | ||
"babel-preset-es2015": "^6.9.0", | ||
"babel-preset-env": "^1.6.0", | ||
"babel-preset-stage-3": "^6.24.1", | ||
"eslint": "^3.2.2", | ||
@@ -31,3 +31,3 @@ "eslint-config-standard": "^5.3.1", | ||
"expect.js": "^0.3.1", | ||
"jest": "^20.0.4", | ||
"jest": "^21.2.1", | ||
"lodash": "^4.17.4", | ||
@@ -34,0 +34,0 @@ "rimraf": "^2.6.2", |
@@ -0,1 +1,3 @@ | ||
const pick = require('lodash/pick') | ||
function isPublished (fragment) { | ||
@@ -10,7 +12,3 @@ return fragment.published | ||
for (const ownerId of object.owners) { | ||
if (ownerId === user.id) { | ||
return true | ||
} | ||
} | ||
return object.owners.includes(user.id) | ||
} | ||
@@ -23,29 +21,14 @@ | ||
for (const team of user.teams) { | ||
if (team.teamType.permissions === 'POST' && | ||
team.object.id === object.id && | ||
operation === 'POST') { | ||
return true | ||
} else if (team.teamType.permissions === 'PATCH' && | ||
team.object.id === object.id && | ||
operation === 'PATCH') { | ||
return true | ||
} | ||
} | ||
return false | ||
return user.teams.some(team => { | ||
return ['POST', 'PATCH'].includes(operation) && | ||
operation === team.teamType.permissions && | ||
team.object.id === object.id | ||
}) | ||
} | ||
function unauthenticatedUser (operation, object) { | ||
// Public/unauthenticated users can GET /collections, filtered by 'published' | ||
if (operation === 'GET' && object && object.path === '/collections') { | ||
return { | ||
filter: (collection) => collection.published | ||
} | ||
} | ||
// Public/unauthenticated users can GET /collections/:id/fragments, filtered by 'published' | ||
if (operation === 'GET' && object && object.path === '/collections/:id/fragments') { | ||
return { | ||
filter: (fragment) => fragment.published | ||
filter: fragments => fragments.filter(isPublished) | ||
} | ||
@@ -56,14 +39,10 @@ } | ||
if (operation === 'GET' && object && object.type === 'collection') { | ||
if (object.published) { | ||
return { | ||
filter: (_, key) => ['id', 'title', 'owners'].includes(key) | ||
} | ||
return { | ||
filter: collection => pick(collection, ['id', 'title', 'owners']) | ||
} | ||
} | ||
if (operation === 'GET' && object && object.type === 'fragment') { | ||
if (object.published) { | ||
return { | ||
filter: (_, key) => ['id', 'title', 'source', 'presentation', 'owners'].includes(key) | ||
} | ||
if (operation === 'GET' && object && object.type === 'fragment' && object.published) { | ||
return { | ||
filter: fragment => pick(fragment, ['id', 'title', 'source', 'presentation', 'owners']) | ||
} | ||
@@ -75,14 +54,14 @@ } | ||
var blog = function (user, operation, object, context) { | ||
// Admins can do anything | ||
if (user && user.admin === true) return true | ||
if (!user) { | ||
async function blog (userId, operation, object, context) { | ||
if (!userId) { | ||
return unauthenticatedUser(operation, object) | ||
} | ||
let collection | ||
const user = await context.models.User.find(userId) | ||
// Admins can do anything | ||
if (user && user.admin === true) return true | ||
if (object.type === 'collection') { | ||
collection = object | ||
const collection = object | ||
if (isOwner(user, collection)) { | ||
@@ -95,8 +74,4 @@ return true | ||
} else if (object.type === 'fragment') { | ||
let fragment = object | ||
const fragment = object | ||
if (isPublished(fragment) && operation === 'GET') { | ||
return true | ||
} | ||
if (isOwner(user, fragment)) { | ||
@@ -110,5 +85,4 @@ return true | ||
if (Array.isArray(fragment.parents)) { | ||
collection = fragment.parents[0] | ||
return teamPermissions(user, operation, collection) | ||
if (Array.isArray(fragment.parents) && teamPermissions(user, operation, fragment.parents[0])) { | ||
return true | ||
} | ||
@@ -119,5 +93,6 @@ } else if (object.type === 'user') { | ||
return false | ||
// ensure a logged in user can do anything a non-logged in user can | ||
return unauthenticatedUser(operation, object) | ||
} | ||
module.exports = blog |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
152024
15
747