2016-02-07 20:25:08 -08:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
exports = module.exports = {
|
2018-04-29 11:21:01 -07:00
|
|
|
GroupsError: GroupsError,
|
2016-02-07 20:25:08 -08:00
|
|
|
|
|
|
|
|
create: create,
|
|
|
|
|
remove: remove,
|
2016-02-08 09:41:21 -08:00
|
|
|
get: get,
|
2016-02-09 15:26:34 -08:00
|
|
|
getWithMembers: getWithMembers,
|
2016-02-09 13:33:30 -08:00
|
|
|
getAll: getAll,
|
2016-06-02 21:07:33 -07:00
|
|
|
getAllWithMembers: getAllWithMembers,
|
2016-02-08 09:41:21 -08:00
|
|
|
|
|
|
|
|
getMembers: getMembers,
|
|
|
|
|
addMember: addMember,
|
2016-09-29 14:44:12 -07:00
|
|
|
setMembers: setMembers,
|
2016-02-08 10:53:01 -08:00
|
|
|
removeMember: removeMember,
|
2016-02-08 09:26:52 -08:00
|
|
|
isMember: isMember,
|
|
|
|
|
|
2016-02-08 20:38:50 -08:00
|
|
|
getGroups: getGroups,
|
2016-09-20 15:07:11 -07:00
|
|
|
setGroups: setGroups
|
2016-02-07 20:25:08 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var assert = require('assert'),
|
2016-09-20 15:07:11 -07:00
|
|
|
constants = require('./constants.js'),
|
2016-02-07 20:25:08 -08:00
|
|
|
DatabaseError = require('./databaseerror.js'),
|
2016-02-07 20:34:05 -08:00
|
|
|
groupdb = require('./groupdb.js'),
|
2016-09-30 09:18:41 -07:00
|
|
|
util = require('util'),
|
2017-08-13 17:44:31 -07:00
|
|
|
uuid = require('uuid');
|
2016-02-07 20:25:08 -08:00
|
|
|
|
|
|
|
|
// http://dustinsenos.com/articles/customErrorsInNode
|
|
|
|
|
// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
|
2018-04-29 11:21:01 -07:00
|
|
|
function GroupsError(reason, errorOrMessage) {
|
2016-02-07 20:25:08 -08:00
|
|
|
assert.strictEqual(typeof reason, 'string');
|
|
|
|
|
assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined');
|
|
|
|
|
|
|
|
|
|
Error.call(this);
|
|
|
|
|
Error.captureStackTrace(this, this.constructor);
|
|
|
|
|
|
|
|
|
|
this.name = this.constructor.name;
|
|
|
|
|
this.reason = reason;
|
|
|
|
|
if (typeof errorOrMessage === 'undefined') {
|
|
|
|
|
this.message = reason;
|
|
|
|
|
} else if (typeof errorOrMessage === 'string') {
|
|
|
|
|
this.message = errorOrMessage;
|
|
|
|
|
} else {
|
|
|
|
|
this.message = 'Internal error';
|
|
|
|
|
this.nestedError = errorOrMessage;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-29 11:21:01 -07:00
|
|
|
util.inherits(GroupsError, Error);
|
|
|
|
|
GroupsError.INTERNAL_ERROR = 'Internal Error';
|
|
|
|
|
GroupsError.ALREADY_EXISTS = 'Already Exists';
|
|
|
|
|
GroupsError.NOT_FOUND = 'Not Found';
|
|
|
|
|
GroupsError.BAD_FIELD = 'Field error';
|
|
|
|
|
GroupsError.NOT_EMPTY = 'Not Empty';
|
|
|
|
|
GroupsError.NOT_ALLOWED = 'Not Allowed';
|
2016-02-07 20:25:08 -08:00
|
|
|
|
2016-09-30 12:25:42 -07:00
|
|
|
// keep this in sync with validateUsername
|
2016-02-07 20:25:08 -08:00
|
|
|
function validateGroupname(name) {
|
|
|
|
|
assert.strictEqual(typeof name, 'string');
|
2016-09-30 12:25:42 -07:00
|
|
|
|
2018-04-29 11:21:01 -07:00
|
|
|
if (name.length < 1) return new GroupsError(GroupsError.BAD_FIELD, 'name must be atleast 1 char');
|
|
|
|
|
if (name.length >= 200) return new GroupsError(GroupsError.BAD_FIELD, 'name too long');
|
2016-02-07 20:25:08 -08:00
|
|
|
|
2018-04-29 11:21:01 -07:00
|
|
|
if (constants.RESERVED_NAMES.indexOf(name) !== -1) return new GroupsError(GroupsError.BAD_FIELD, 'name is reserved');
|
2016-02-09 12:16:30 -08:00
|
|
|
|
2016-10-01 23:52:01 -07:00
|
|
|
// +/- can be tricky in emails. also need to consider valid LDAP characters here (e.g '+' is reserved)
|
2018-04-29 11:21:01 -07:00
|
|
|
if (/[^a-zA-Z0-9.]/.test(name)) return new GroupsError(GroupsError.BAD_FIELD, 'name can only contain alphanumerals and dot');
|
2016-09-30 12:25:42 -07:00
|
|
|
|
2016-09-21 11:55:53 -07:00
|
|
|
// app emails are sent using the .app suffix
|
2018-04-29 11:21:01 -07:00
|
|
|
if (name.indexOf('.app') !== -1) return new GroupsError(GroupsError.BAD_FIELD, 'name pattern is reserved for apps');
|
2016-09-21 11:55:53 -07:00
|
|
|
|
2016-02-07 20:25:08 -08:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function create(name, callback) {
|
|
|
|
|
assert.strictEqual(typeof name, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
2016-09-30 12:33:18 -07:00
|
|
|
// we store names in lowercase
|
|
|
|
|
name = name.toLowerCase();
|
|
|
|
|
|
2016-02-07 20:25:08 -08:00
|
|
|
var error = validateGroupname(name);
|
|
|
|
|
if (error) return callback(error);
|
|
|
|
|
|
2016-09-30 09:18:41 -07:00
|
|
|
var id = 'gid-' + uuid.v4();
|
2017-02-14 09:37:07 -08:00
|
|
|
groupdb.add(id, name, function (error) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new GroupsError(GroupsError.ALREADY_EXISTS));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-07 20:25:08 -08:00
|
|
|
|
2017-02-14 09:37:07 -08:00
|
|
|
callback(null, { id: id, name: name });
|
2016-02-07 20:25:08 -08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function remove(id, callback) {
|
|
|
|
|
assert.strictEqual(typeof id, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
2016-02-13 12:24:51 +01:00
|
|
|
// never allow admin group to be deleted
|
2018-04-29 11:21:01 -07:00
|
|
|
if (id === constants.ADMIN_GROUP_ID) return callback(new GroupsError(GroupsError.NOT_ALLOWED));
|
2016-02-13 12:24:51 +01:00
|
|
|
|
2018-04-04 20:08:52 -07:00
|
|
|
groupdb.del(id, function (error) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-07 20:25:08 -08:00
|
|
|
|
2018-04-04 20:08:52 -07:00
|
|
|
callback(null);
|
2016-02-07 20:25:08 -08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function get(id, callback) {
|
|
|
|
|
assert.strictEqual(typeof id, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.get(id, function (error, result) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-07 20:25:08 -08:00
|
|
|
|
|
|
|
|
return callback(null, result);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-09 15:26:34 -08:00
|
|
|
function getWithMembers(id, callback) {
|
|
|
|
|
assert.strictEqual(typeof id, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.getWithMembers(id, function (error, result) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-09 15:26:34 -08:00
|
|
|
|
|
|
|
|
return callback(null, result);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-09 13:33:30 -08:00
|
|
|
function getAll(callback) {
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.getAll(function (error, result) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-06-02 21:07:33 -07:00
|
|
|
|
|
|
|
|
return callback(null, result);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAllWithMembers(callback) {
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.getAllWithMembers(function (error, result) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-09 13:33:30 -08:00
|
|
|
|
|
|
|
|
return callback(null, result);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-08 09:41:21 -08:00
|
|
|
function getMembers(groupId, callback) {
|
|
|
|
|
assert.strictEqual(typeof groupId, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.getMembers(groupId, function (error, result) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-08 09:41:21 -08:00
|
|
|
|
|
|
|
|
return callback(null, result);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-08 20:38:50 -08:00
|
|
|
function getGroups(userId, callback) {
|
|
|
|
|
assert.strictEqual(typeof userId, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.getGroups(userId, function (error, result) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-08 20:38:50 -08:00
|
|
|
|
|
|
|
|
return callback(null, result);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-09 15:47:02 -08:00
|
|
|
function setGroups(userId, groupIds, callback) {
|
|
|
|
|
assert.strictEqual(typeof userId, 'string');
|
|
|
|
|
assert(Array.isArray(groupIds));
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
2016-02-11 10:52:31 +01:00
|
|
|
groupdb.setGroups(userId, groupIds, function (error) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-09 15:47:02 -08:00
|
|
|
|
2016-02-11 10:52:31 +01:00
|
|
|
return callback(null);
|
2016-02-09 15:47:02 -08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-08 09:41:21 -08:00
|
|
|
function addMember(groupId, userId, callback) {
|
|
|
|
|
assert.strictEqual(typeof groupId, 'string');
|
|
|
|
|
assert.strictEqual(typeof userId, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.addMember(groupId, userId, function (error) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-08 09:41:21 -08:00
|
|
|
|
|
|
|
|
return callback(null);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-29 14:44:12 -07:00
|
|
|
function setMembers(groupId, userIds, callback) {
|
|
|
|
|
assert.strictEqual(typeof groupId, 'string');
|
|
|
|
|
assert(Array.isArray(userIds));
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.setMembers(groupId, userIds, function (error) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND, 'Invalid group or user id'));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-09-29 14:44:12 -07:00
|
|
|
|
|
|
|
|
return callback(null);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-08 09:41:21 -08:00
|
|
|
function removeMember(groupId, userId, callback) {
|
|
|
|
|
assert.strictEqual(typeof groupId, 'string');
|
|
|
|
|
assert.strictEqual(typeof userId, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.removeMember(groupId, userId, function (error) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-08 09:41:21 -08:00
|
|
|
|
|
|
|
|
return callback(null);
|
|
|
|
|
});
|
|
|
|
|
}
|
2016-02-08 10:53:01 -08:00
|
|
|
|
|
|
|
|
function isMember(groupId, userId, callback) {
|
|
|
|
|
assert.strictEqual(typeof groupId, 'string');
|
|
|
|
|
assert.strictEqual(typeof userId, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
groupdb.isMember(groupId, userId, function (error, result) {
|
2018-04-29 11:21:01 -07:00
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
|
|
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
2016-02-08 10:53:01 -08:00
|
|
|
|
|
|
|
|
return callback(null, result);
|
|
|
|
|
});
|
|
|
|
|
}
|