Skip to content

Instantly share code, notes, and snippets.

@jmakeig
Last active December 10, 2016 19:14
Show Gist options
  • Save jmakeig/48037528b074e2ac0b88c8d0f993072a to your computer and use it in GitHub Desktop.
Save jmakeig/48037528b074e2ac0b88c8d0f993072a to your computer and use it in GitHub Desktop.
'use strict';
/** {@link https://gist.github.com/jmakeig/0a331823ad9a458167f6#file-apply-as-9-sjs} */
function applyAs(fct,options,thisArg){return function(){const f=()=>{return[fct.call(thisArg,...arguments)]};options=options||{};if('string'===typeof options.database){options.database=xdmp.database(options.database)}if(options.user){options.userId=xdmp.user(options.user);delete options.user}if(fct.transactionMode&&!(options.transactionMode)){options.transactionMode=fct.transactionMode}return fn.head(xdmp.invokeFunction(f,options)).pop();}};
/** {@link https://gist.github.com/jmakeig/0a331823ad9a458167f6#file-hof-mapper-sjs} */
function map(fct,mapper){const ident=item=>item;mapper=mapper||ident;return function*_map(){const itr=fct.apply(null,arguments);if('string'===typeof itr||!(itr[Symbol.iterator])){yield itr}else{for(const item of itr){yield mapper(item)}}}};
const sec = require('/MarkLogic/security');
/**
* Generate hashes of permission terms for the cross product of roles and capabilities (read,
* update, insert, execute). Use `cts.termQuery(hash)` to match documents by their terms.
*
* @param {string|Iterable.<string>} [roleIDs] - One or more role IDs. Defaults to all roles.
* @returns {GeneratorFunction} - A generator that yields permission term hashes for the
* cross-product of roles and capabilities
*/
function* getPermissionTerms(roleIDs) {
const capabilities = ['read', 'update', 'insert', 'execute'];
/** @function */
const getRoleIDs = map(applyAs(sec.getRoleIds, { database: xdmp.securityDatabase() }), fn.data);
function permHash(roleID, capability) {
return xdmp.add64(
xdmp.mul64(
xdmp.add64(
xdmp.mul64(roleID, 5), xdmp.hash64(capability)
), 5
), xdmp.hash64('permission()')
);
}
for(const roleID of roleIDs || getRoleIDs()) {
for(const capability of capabilities) {
yield permHash(roleID, capability);
}
}
}
const query = cts.orQuery(
[...getPermissionTerms(/* Array of roleIDs here to limit to specific roles */)]
.map(term => cts.termQuery(term))
);
// URIs of the documents that have the supplied permissions
cts.uris(null, null, query);
'use strict';
const sec = require('/MarkLogic/security');
function applyAs(fct,options,thisArg){return function(){const f=()=>{return[fct.call(thisArg,...arguments)]};options=options||{};if('string'===typeof options.database){options.database=xdmp.database(options.database)}if(options.user){options.userId=xdmp.user(options.user);delete options.user}if(fct.transactionMode&&!(options.transactionMode)){options.transactionMode=fct.transactionMode}return fn.head(xdmp.invokeFunction(f,options)).pop();}};
const getRoleNames = applyAs(sec.getRoleNames, { database: xdmp.securityDatabase() });
function roleNames(roleIDs) {
const p = (i, n) => `${n} (${i})`;
if(!Array.isArray(roleIDs)) {
roleIDs = [roleIDs];
}
for(const roleID of roleIDs) {
try {
return p(roleID, fn.data(getRoleNames(roleID)));
} catch(error) {
if('SEC-ROLEDNE' === error.name) {
return p(roleID, '**ORPHANED**');
}
throw error;
}
}
}
//cts.uris().toArray().map(uri => xdmp.documentGetPermissions(uri))
const out = Object.create(null);
for(const uri of cts.uris()) {
out[uri] = xdmp.documentGetPermissions(uri)
.map(perm => roleNames(perm.roleId))
}
out;
'use strict';
const sec = require('/MarkLogic/security');
function applyAs(fct,options,thisArg){return function(){const f=()=>{return[fct.call(thisArg,...arguments)]};options=options||{};if('string'===typeof options.database){options.database=xdmp.database(options.database)}if(options.user){options.userId=xdmp.user(options.user);delete options.user}if(fct.transactionMode&&!(options.transactionMode)){options.transactionMode=fct.transactionMode}return fn.head(xdmp.invokeFunction(f,options)).pop();}};
declareUpdate();
const createRole = applyAs(sec.createRole, { database: xdmp.securityDatabase(), transactionMode: 'update-auto-commit'});
const removeRole = applyAs(sec.removeRole, { database: xdmp.securityDatabase(), transactionMode: 'update-auto-commit'});
const dummyRoles = ['TEMP-1', 'TEMP-2', 'TEMP-3', 'TEMP-4', 'TEMP-5'];
/**
* Create temporary roles. Idempontent, so it doesn‘t error
* if they already exist.
*/
dummyRoles
.map(role => {
try {
return createRole(role, null, null, null, null, null, null)
} catch(error) {
if('SEC-ROLEEXISTS' !== error.name) {
throw error;
}
}
});
// FIXME: This doesn't work
function fndata(f) {
return function*() {
for(const el of f.apply(null, arguments)) {
yield fn.data(el);
}
}
}
const randomPermission = (function() {
const getRoleIds = applyAs(sec.getRoleIds, { database: xdmp.securityDatabase() });
const getRoleNames = applyAs(sec.getRoleNames, { database: xdmp.securityDatabase() });
const roleIDs = getRoleIds();
const roleNames = Array.from(getRoleNames(roleIDs), el => fn.data(el))
.filter(name => !(/^TEMP/.test(name)));
console.dir(roleNames);
return function _randomPermission(roleName) {
const capabilities = ['read', 'update', 'insert', 'execute'];
const randRole = Math.floor(Math.random() * roleNames.length);
const randCapability = Math.floor(Math.random() * capabilities.length);
return xdmp.permission(roleName || roleNames[randRole], capabilities[randCapability]);
}
})();
/**
* Gets an array of random permission instances of length `num`.
*
* @param {number} num=1 - The number of permissions
* @returns - A randomly generated array of permissions
*/
function randomPermissions(num) {
const perms = new Array(num || 1);
for(let i = 0; i < num; i++) {
perms[i] = randomPermission();
}
return perms;
}
const TOTAL = 10;
const orphans = [];
for(let i = 0; i < TOTAL; i++) {
let perms = randomPermissions(Math.floor(Math.random() * 10) + 1);
//if(0 === Math.floor(Math.random() * 10)) {
if(0 === i % 3) {
orphans.push(`/${String(i)}.json`);
perms = perms.concat(
dummyRoles
.slice(0, Math.max(1, Math.floor(Math.random() * dummyRoles.length)))
.map(role => randomPermission(role))
)
}
xdmp.documentInsert(`/${String(i)}.json`, { num: i }, {permissions: perms});
}
dummyRoles.map(role => removeRole(role));
orphans
.join('\r');
// Verify with:
// cts.uris().toArray().map(uri => xdmp.documentGetPermissions(uri))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment