2.0.0 • Published 9 years ago

mastoose v2.0.0

Weekly downloads
5
License
ISC
Repository
github
Last release
9 years ago

#Mastoose

Mastoose (Master of Mongoose) is a utility that helps to deal with exposition and modification rules for Mongoose documents.

It allows to declare models access/modification logic in one place and not to worry of creating security issues when using them.

It's designed to be part of a resource reflection library.

Unlike some other libs, it does not require to define rules directly in the model schema.

It supports nested schemas, sub-models and aggregated/populated documents.

Build Status Coverage Status npm version Dependency Status devDependency Status


##Initialisation You need to pass the mongoose instance you use.

var mastoose = new Mastoose(mongoose);

##Defining rules

Given this model

var Model = mongoose.model('Model', new mongoose.Schema({
  ppte : String,
  ppte2 : String,
  nested : {
    ppte : String,
    ppte2 : String
  },
  to : [{
    type : mongoose.Schema.Types.ObjectId,
    ref : User.modelName
  }]
}));

We define rules for Model and User

mastoose.addRule(Model, {
	
  // define if this model can be accessed
  access : true/false/function(ctx, callback) {
	// `this` is the current model instance
	callback(err, true/false);
  },
   
  // define if a property should be exposed (by default all properties are exposed)
  exposes : {
    // boolean
    ppte : false/true,

    // or a function with a callback
    'nested.ppte' : function(ctx, callback) {
    	// `this` is the current model instance
        callback(err, true/false);
    }
  },    
  
  // define which paths can be modified (by default all can)
  allowsModification : {
    ppte : false/true,

    'nested.ppte' : function(ctx, callback) {
    	// `this` is the current model instance
        callback(err, true/false);
    }
  },
  
  // define authorizations for calling methods (by default all can be called)
  allows : {
  	method1 : true/false,
  	method2 : function(ctx, callback) {
  		// `this` is the current model instance
        callback(err, true/false);
  }
});

mastoose.addRule(User, {...});

Using Mastoose

  • Exposing a document

You can pass any kind of documents/objects. Mastoose will apply the exposes rules accordingly.

var ctx = {user : user, ... };
mastoose.expose(ctx, data, function(err, data_clean) {
  res.json(data_clean);
});

internally it uses the rule access. it will raise an error if a document in data should not be accessed.

  • Protecting a document modification/creation

You can check if pending modifications of a document (new or not) are allowed by the rules. Based on Mongoose isModified property.

mastoose.allowsModification(ctx, doc, function(err, allowed) {
  if (allowed) {
    model.save();
  }
})
  • Protecting a document method

You can check if a method can be used

mastoose.allows(ctx, doc, 'method', function(err, allowed) {
  if (allowed) {
    model.save();
  }
})

Use with Expoose

  • link them
var expoose = new Expoose(mongoose);

// command checker

expoose.on('command', function(method, req, model, callback) {
  if (method !== 'save') {
    mastoose.allows(req.user, model, method, function(err, allows) {
      callback(err || (!allows && new restify.NotAuthorizedError()));
    });
    return;
  }

  mastoose.allowsModification(req.user, model, function(err, allows) {
    callback(err || (!allows && new restify.NotAuthorizedError()));
  });
});

// data filtering

expoose.on('expose', function(req, data, callback) {
  mastoose.expose(req.user, data, function(err, filtered_data) {
  	callback(err, filtered_data);
  });
});

// error management

expoose.on('error', function(err, res) {
  if (err instanceof Mastoose.errors.CanNotAccess) {
    err = new restify.NotAuthorizedError();
  }

  if (!(err instanceof restify.HttpError)) {
    switch (err.type) {
      case 'InvalidArgument':
        err = new restify.InvalidArgumentError(err.message);
        break;
      default :
        err = new restify.InternalError(err.message);
    }
  }

  res.json(err);
});
  • use Expoose without worrying to make security mistakes
server
  .get(
    '/users/:user_id',
    middlewares.get('me'),
    expoose.detail(User, {id : 'user_id'})
  );

server
  .post(
    'users',
    expoose.insert(User)
  );

server.get(
  '/users',
  expoose.list(User)
);

server
  .del(
    'users/:user_id',
    expoose.remove(User, {id : 'user_id'})
  );
  
server
  .get(
    '/users/:user_id/discussions',
    middlewares.get('me'),
    expoose.method(User, 'discussions', {id : 'user_id'})
  );

The idea is that all validations and eventual reactions to models changes are handled thanks to mongoose hooks and/or plugins. It allows to make a nice model/event driven API.

Expoose has currently not been open sourced. Some work is still needed.