Skip to content

Instantly share code, notes, and snippets.

@skleeschulte
Created March 8, 2017 21:00
Show Gist options
  • Save skleeschulte/1fc47b51863b922041bda9bb99be65da to your computer and use it in GitHub Desktop.
Save skleeschulte/1fc47b51863b922041bda9bb99be65da to your computer and use it in GitHub Desktop.
LoopBack 3 boot script for protecting userId properties on custom models
'use strict';
/**
* Add before safe hook and validation to all custom models with an userId property to prevent changing userId
* properties by non-admin users.
*/
const USER_ID_PROPERTY = 'userId';
const INVALID_USER_ID = -1;
function getBeforeSaveHook(app) {
return (ctx, next) => {
const accessToken = ctx.options.accessToken;
const userId = accessToken && accessToken.userId;
const data = ctx.instance || ctx.data;
if (data.hasOwnProperty(USER_ID_PROPERTY) && data.userId !== userId) {
const Role = app.models.Role;
const RoleMapping = app.models.RoleMapping;
Role.isInRole('admin', { principalType: RoleMapping.USER, principalId: userId }, (err, isInRole) => {
if (err) return next(err);
if (!isInRole) data.userId = INVALID_USER_ID;
next();
});
} else {
next();
}
};
}
module.exports = function(app) {
const builtInModels = ['User', 'AccessToken', 'ACL', 'RoleMapping', 'Role'];
const patchedModels = [];
for (let model in app.models) {
if (!app.models.hasOwnProperty(model)) continue;
// Don't patch in-built models.
if (builtInModels.indexOf(model) !== -1) continue;
model = app.models[model];
// Patch models only once.
if (patchedModels.indexOf(model) !== -1) continue;
if (model.definition.properties[USER_ID_PROPERTY]) {
model.observe('before save', getBeforeSaveHook(app));
model.validatesExclusionOf(USER_ID_PROPERTY, { in: [INVALID_USER_ID], message: 'Invalid userId.' });
patchedModels.push(model);
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment