Last active
December 10, 2016 19:14
-
-
Save jmakeig/48037528b074e2ac0b88c8d0f993072a to your computer and use it in GitHub Desktop.
This file contains hidden or 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
'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); | |
This file contains hidden or 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
'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; |
This file contains hidden or 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
'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