1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
/*jslint plusplus: true, devel: true, nomen: true, node: true, indent: 4, maxerr: 50 */
"use strict";
var Strings = require("../strings"),
util = require("../util"),
async = require("async");
/**
* Constructor for Memory rule store.
*
* This store keeps rules in memory only.
* Rules are not persisted across application reloads and therefore they have to be loaded early in the application start (initialization) phase.
*
* This is the default store for authority and it doesn’t have to be explicitly configured unless it is used in conjunction with other stores.
*
* @example
* var authority = require("authority");
*
* authority.setRules([{
* name: "allow_managers_only",
description: "Only managers can pass.",
condition: { title: "Manager" }
* }, {
* name: "allow_teenagers_only",
description: "Only users between 13 and 19 years old can pass.",
condition: { age: { $gte: 13, $lte: 19 } }
* }
* ]);
*
* @class Represents a Memory rule store.
*/
function MemoryStore() {
/**
* The name of this store. The default value is "memory". NOTE: every store is required to have a unique name within a manager.
*/
this.name = "memory";
/**
* The object that holds the references to all stored rules. NOTE: this member is not part of the Authority API and it is specific to this store only.
*/
this.rules = {};
}
/**
* Adds one or more rules to the store.
*
* @param {(object|object[])} rules - The rule or an array of rules to be added to the store.
*
* @param {boolean=} override - Specifies whether existing rules should be replaced by the ones provided to this method. Rules are matched by their name.
* If this parameter is not specified or is false and there is a name conflict an error will be returned or thrown depending on the usage of the method.
*
* @param {function=} done - Optional callback function that will be called after the rule(s) have been added.
* If the method is unsuccessful an error object will be passed as a single parameter to the callback.
* If the callback is omitted and the method is unsuccessful an error will be thrown.
*
* @return {null}
*/
MemoryStore.prototype.setRules = function (rules, override, done) {
var that = this;
if (typeof override === "function") {
done = override;
override = null;
}
if (!done) {
done = function (err) {
if (err) {
throw err;
}
};
}
function setRule(rule, cb) {
if (!override && that.rules[rule.name]) {
return cb(new Error(Strings.ERR_RULE_EXISTS));
}
that.rules[rule.name] = rule;
cb();
}
if (Array.isArray(rules)) {
async.each(rules, function (item, callback) {
setRule(item, callback);
}, done);
} else {
setRule(rules, done);
}
};
/**
* Retrieves the specified rule from the store.
*
* @param {string} name - The name of the rule.
* @param {function} done - The callback that handles the result.
* The first parameter will always be null for this store while the second parameter will contain the requested rule or null if not found.
* @return {null}
*/
MemoryStore.prototype.getRule = function (name, done) {
done(null, this.rules[name]);
};
/**
* Removes the specified rules from the store.
*
* @param {(string|string[])} names - The name or an array of names to remove.
* @param {function=} done - Optional callback function that will be called after the rule(s) have been deleted.
* If the method is unsuccessful an error object will be passed as a single parameter to the callback.
* If the callback is omitted and the method is unsuccessful an error will be thrown.
* @return {null}
*/
MemoryStore.prototype.deleteRules = function (names, done) {
var that = this;
if (!done) {
done = function (err) {
if (err) {
throw err;
}
};
}
function remRule(name, cb) {
delete that.rules[name];
cb();
}
if (Array.isArray(names)) {
async.each(names, function (item, callback) {
remRule(item, callback);
}, done);
} else {
remRule(names, done);
}
};
/**
* Retrieves the names and descriptions of the rules present in the store and matching the specified criteria.
*
* All parameters are required.
*
* @param {number} start - The index at wich to begin retrieving names. The index of the first element is 0.
* @param {number} count - The number of names to retrieve. `0` denotes all remaining.
* @param {string} match - Wildcard expression to match names. `null` denotes any name. Example: `allow_*`
* @param {function} done - The callback that handles the result.
* The first parameter will always be null for this store while the second parameter will contain an array of matched objects `{ name: "string", description: "string" }`.
*/
MemoryStore.prototype.getRuleNames = function (start, count, match, done) {
var keys = Object.keys(this.rules),
res = [],
that = this,
regex;
if (match) {
regex = util.regExpFromWildExp(match);
keys = keys.filter(function (el) {
return regex.test(el);
});
}
if (start || count) {
if (count) {
count = start + count;
} else {
count = undefined;
}
keys = keys.splice(start, count);
}
keys.forEach(function (key) {
var rule = that.rules[key];
res.push({ name: rule.name, description: rule.description });
});
done(null, res);
};
/**
* Gets the total count of rules present in the store.
*
* @param {function} done - The callback that handles the result.
* The first parameter will always be null for this store while the second parameter will contain a number representing the total count of rules.
*/
MemoryStore.prototype.getRuleCount = function (done) {
done(null, Object.keys(this.rules).length);
};
module.exports = MemoryStore;