Browse files

Add options to hide exposed fields and avoid http post rewriting

  • Loading branch information...
1 parent 445c0b7 commit 832a520d61ff75d30fd79e7de20cb992359af938 @Unitech committed Nov 28, 2012
Showing with 104 additions and 27 deletions.
  1. +1 −0 .npmignore
  2. +7 −0 README.md
  3. +73 −22 lib/index.js
  4. +23 −5 package.json
View
1 .npmignore
@@ -0,0 +1 @@
+node_modules/*
View
7 README.md
@@ -24,6 +24,9 @@ var PizzaSchema = new Schema({
},
size : {
type : Number
+ },
+ password : { // You can hide it from read and write ! (check after)
+ type : String
}
});
@@ -40,6 +43,10 @@ var angularBridge = new (require('angular-bridge'))(app, {
});
angularBridge.addRessource('pizzas', db.Pizza);
+//
+// You can also hide fields
+// angularBridge.addRessource('pizzas', db.Pizza, { hide : ['_id', 'password']});
+//
```
That's all for the backend, now in Angular :
View
95 lib/index.js
@@ -11,7 +11,7 @@ var util = require('util');
var AngularBridge = function(app, options, dontRegisterRoutes) {
this.app = app;
this.options = _.extend({
- urlPath: '/'
+ urlPrefix: '/',
}, options || {});
this.resources = [ ];
this.registerRoutes();
@@ -28,32 +28,35 @@ module.exports = exports = AngularBridge;
*/
AngularBridge.prototype.registerRoutes = function() {
- this.app.all(this.options.urlPath + ':resourceName', this.collection());
- this.app.get(this.options.urlPath + ':resourceName', this.collectionGet());
+ this.app.all(this.options.urlPrefix + ':resourceName', this.collection());
+ this.app.get(this.options.urlPrefix + ':resourceName', this.collectionGet());
- this.app.post(this.options.urlPath + ':resourceName', this.collectionPost());
+ this.app.post(this.options.urlPrefix + ':resourceName', this.collectionPost());
- this.app.all(this.options.urlPath + ':resourceName/:id', this.entity());
- this.app.get(this.options.urlPath + ':resourceName/:id', this.entityGet());
+ this.app.all(this.options.urlPrefix + ':resourceName/:id', this.entity());
+ this.app.get(this.options.urlPrefix + ':resourceName/:id', this.entityGet());
// You can POST or PUT to update data
- this.app.post(this.options.urlPath + ':resourceName/:id', this.entityPut());
- this.app.put(this.options.urlPath + ':resourceName/:id', this.entityPut());
+ this.app.post(this.options.urlPrefix + ':resourceName/:id', this.entityPut());
+ this.app.put(this.options.urlPrefix + ':resourceName/:id', this.entityPut());
- this.app.delete(this.options.urlPath + ':resourceName/:id', this.entityDelete());
+ this.app.delete(this.options.urlPrefix + ':resourceName/:id', this.entityDelete());
};
-AngularBridge.prototype.addResource = function(singularName, model, pluralName, defaultSort) {
- pluralName = singularName;
+AngularBridge.prototype.addResource = function(resource_name, model, options) {
+ var resource = {
+ resource_name: resource_name,
+ model: model,
+ options : options || null
+ };
- var resource = { singularName: singularName, pluralName: pluralName, model: model };
this.resources.push(resource);
};
AngularBridge.prototype.getResource = function(name) {
return _.find(this.resources, function(resource) {
- return resource.pluralName === name;
+ return resource.resource_name === name;
});
};
@@ -73,7 +76,7 @@ AngularBridge.prototype.redirect = function (address, req, res, next) {
res.send(address);
};
-/**
+/**
* All entities rest functions have to go through this first.
*/
AngularBridge.prototype.collection = function() {
@@ -95,7 +98,8 @@ AngularBridge.prototype.collectionGet = function() {
}
var self = this;
- var query = req.resource.model.find();
+ var hidden_fields = this.generateHiddenFields(req.resource);
+ var query = req.resource.model.find().select(hidden_fields);
query.exec(function(err, docs) {
if (err) {
@@ -114,7 +118,8 @@ AngularBridge.prototype.collectionPost = function() {
var self = this;
if (!req.body) throw new Error('Nothing submitted.');
- var doc = new req.resource.model(req.body);
+ var epured_body = this.epureRequest(req.body, req.resource);
+ var doc = new req.resource.model(epured_body);
doc.save(function(err) {
if (err) { error(err); return; }
@@ -123,6 +128,44 @@ AngularBridge.prototype.collectionPost = function() {
}, this);
};
+/**
+ * Generate an object of fields to not expose
+ */
+AngularBridge.prototype.generateHiddenFields = function(resource) {
+ var hidden_fields = {};
+
+ if (resource.options == null || typeof resource.options['hide'] == 'undefined')
+ return {};
+
+ resource.options.hide.forEach(function(dt) {
+ hidden_fields[dt] = false;
+ });
+ return hidden_fields;
+}
+
+
+/** Sec issue
+ * Epure incoming data to avoid overwritte and POST request forgery
+ */
+AngularBridge.prototype.epureRequest = function(req_data, resource) {
+
+
+ if (resource.options == null || typeof resource.options['hide'] == 'undefined')
+ return req_data;
+
+ var hidden_fields = resource.options.hide;
+
+ _.each(req_data, function(num, key) {
+ _.each(hidden_fields, function(fi) {
+ if (fi == key)
+ delete req_data[key];
+ });
+ });
+
+ return req_data;
+}
+
+
/*
* Entity request goes there first
* It retrieves the resource
@@ -131,9 +174,15 @@ AngularBridge.prototype.entity = function() {
return _.bind(function(req, res, next) {
var self = this;
if (!(req.resource = this.getResource(req.params.resourceName))) { next(); return; }
-
- req.resource.model.findOne({ _id: req.params.id }, function(err, doc) {
- console.log(err);
+
+ var hidden_fields = this.generateHiddenFields(req.resource);
+
+ //
+ // select({_id : false}) invert the select process (hidde the _id field)
+ //
+ var query = req.resource.model.findOne({ _id: req.params.id }).select(hidden_fields);
+
+ query.exec(function(err, doc) {
if (err) {
return res.send({
success : false,
@@ -175,19 +224,21 @@ AngularBridge.prototype.entityPut = function() {
var self = this;
if (!req.body) throw new Error('Nothing submitted.');
+
+ var epured_body = this.epureRequest(req.body, req.resource);
// Merge
- _.each(req.body, function(value, name) {
+ _.each(epured_body, function(value, name) {
req.doc[name] = value;
});
+
req.doc.save(function(err) {
- console.log(req.doc);
if (err) {
return res.send({success:false});
}
- return res.send({success:true});
+ return res.send(req.doc);
});
}, this);
View
28 package.json
@@ -1,16 +1,34 @@
{
"name": "angular-bridge",
- "description": "Mongoose Express Angular ressources bridge",
- "version": "1.0.0",
+ "author": {
+ "name": "as"
+ },
+ "description": "Mongoose Express Angular resources bridge",
+ "version": "0.1.1",
"main": "./index.js",
"private": false,
"dependencies": {
"underscore": "1.x"
},
"repository": {
"type": "git",
- "url": "git://github.com/"
+ "url": "git://github.com/Alexandre-Strzelewicz/angular-bridge.git"
+ },
+ "homepage": "https://github.com/Alexandre-Strzelewicz/angular-bridge",
+ "readmeFilename": "README.md",
+ "_npmUser": {
+ "name": "tknew",
+ "email": "strzelewicz.alexandre@gmail.com"
+ },
+ "_id": "angular-bridge@0.1.1",
+ "devDependencies": {},
+ "optionalDependencies": {},
+ "engines": {
+ "node": "*"
},
- "homepage": "",
- "readmeFilename": "Readme.md"
+ "_engineSupported": true,
+ "_npmVersion": "1.1.24",
+ "_nodeVersion": "v0.6.19",
+ "_defaultsLoaded": true,
+ "_from": "angular-bridge@*"
}

0 comments on commit 832a520

Please sign in to comment.