Skip to content

Commit fda8287

Browse files
committed
now logs requests into the db
1 parent 65c5a53 commit fda8287

File tree

9 files changed

+305
-28
lines changed

9 files changed

+305
-28
lines changed

models/RequestLogs.js

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
"use strict";
2+
3+
var db = require('../services/database/mongo');
4+
5+
var collection = 'RequestLogs';
6+
7+
var service = 'Users';
8+
9+
var debug = require('debug')(collection);
10+
11+
var schemaObject = {
12+
RequestId: {
13+
type: 'String'
14+
},
15+
ipAddress: {
16+
type: 'String'
17+
},
18+
url: {
19+
type: 'String'
20+
},
21+
method: {
22+
type: 'String'
23+
},
24+
service: {
25+
type: 'String',
26+
default: service
27+
},
28+
body: {
29+
type: db.Schema.Types.Mixed
30+
},
31+
app: {
32+
type: db.Schema.Types.ObjectId,
33+
ref: 'Applications'
34+
},
35+
user: {
36+
type: db.Schema.Types.ObjectId,
37+
ref: 'Users'
38+
},
39+
device: {
40+
type: 'String'
41+
},
42+
response: {
43+
type: db.Schema.Types.Mixed
44+
},
45+
};
46+
47+
schemaObject.createdAt = {
48+
type: 'Date',
49+
default: Date.now
50+
};
51+
52+
schemaObject.updatedAt = {
53+
type: 'Date'
54+
// default: Date.now
55+
};
56+
57+
schemaObject.owner = {
58+
type: db.Schema.Types.ObjectId,
59+
ref: 'Users'
60+
};
61+
62+
schemaObject.createdBy = {
63+
type: db.Schema.Types.ObjectId,
64+
ref: 'Users'
65+
};
66+
67+
schemaObject.client = {
68+
type: db.Schema.Types.ObjectId,
69+
ref: 'Clients'
70+
};
71+
72+
schemaObject.developer = {
73+
type: db.Schema.Types.ObjectId,
74+
ref: 'Users'
75+
};
76+
77+
schemaObject.tags = {
78+
type: [String],
79+
index: 'text'
80+
};
81+
82+
// Let us define our schema
83+
var Schema = db.Schema(schemaObject);
84+
85+
// Index all text for full text search
86+
// MyModel.find({$text: {$search: searchString}})
87+
// .skip(20)
88+
// .limit(10)
89+
// .exec(function(err, docs) { ... });
90+
// Schema.index({'tags': 'text'});
91+
92+
Schema.statics.search = function(string) {
93+
return this.find({$text: {$search: string}}, { score : { $meta: "textScore" } })
94+
.sort({ score : { $meta : 'textScore' } });
95+
};
96+
97+
// assign a function to the "methods" object of our Schema
98+
// Schema.methods.someMethod = function (cb) {
99+
// return this.model(collection).find({}, cb);
100+
// };
101+
102+
// assign a function to the "statics" object of our Schema
103+
// Schema.statics.someStaticFunction = function(query, cb) {
104+
// eg. pagination
105+
// this.find(query, null, { skip: 10, limit: 5 }, cb);
106+
// };
107+
108+
// Adding hooks
109+
110+
Schema.pre('save', function(next) {
111+
// Indexing for search
112+
var ourDoc = this._doc;
113+
var split = [];
114+
for(var n in ourDoc){
115+
if(typeof ourDoc[n] === 'string'){
116+
split.push(ourDoc[n].split(' '));
117+
}
118+
}
119+
this.tags = split;
120+
next();
121+
});
122+
123+
Schema.post('init', function(doc) {
124+
debug('%s has been initialized from the db', doc._id);
125+
});
126+
127+
Schema.post('validate', function(doc) {
128+
debug('%s has been validated (but not saved yet)', doc._id);
129+
});
130+
131+
Schema.post('save', function(doc) {
132+
debug('%s has been saved', doc._id);
133+
});
134+
135+
Schema.post('remove', function(doc) {
136+
debug('%s has been removed', doc._id);
137+
});
138+
139+
Schema.pre('validate', function(next) {
140+
debug('this gets printed first');
141+
next();
142+
});
143+
144+
Schema.post('validate', function() {
145+
debug('this gets printed second');
146+
});
147+
148+
Schema.pre('find', function(next) {
149+
debug(this instanceof db.Query); // true
150+
this.start = Date.now();
151+
next();
152+
});
153+
154+
Schema.post('find', function(result) {
155+
debug(this instanceof db.Query); // true
156+
// prints returned documents
157+
debug('find() returned ' + JSON.stringify(result));
158+
// prints number of milliseconds the query took
159+
debug('find() took ' + (Date.now() - this.start) + ' millis');
160+
});
161+
162+
Schema.pre('update', function(next) {
163+
// Adding updated date
164+
165+
// Indexing for search
166+
var ourDoc = this._update.$set;
167+
var split = [];
168+
for(var n in ourDoc){
169+
if(typeof ourDoc[n] === 'string'){
170+
split.push(ourDoc[n].split(' '));
171+
}
172+
}
173+
174+
if(!split){
175+
this.update(this._conditions,{ $set: { updatedAt: new Date()} });
176+
}else{
177+
this.update(this._conditions,{ $set: { updatedAt: new Date()}, $addToSet: {tags: {$each: split}} });
178+
}
179+
180+
next();
181+
});
182+
183+
var Model = db.model(collection, Schema);
184+
185+
module.exports = Model;

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"express-enforces-ssl": "^1.1.0",
4949
"express-limiter": "^1.6.0",
5050
"express-validator": "^3.1.2",
51+
"fnv-plus": "^1.2.12",
5152
"helmet": "^3.6.1",
5253
"hpp": "^0.2.2",
5354
"lodash": "^4.17.4",

routes/index.js

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@ var cors = require('cors');
1717
var hpp = require('hpp');
1818
var contentLength = require('express-content-length-validator');
1919
var MAX_CONTENT_LENGTH_ACCEPTED = config.maxContentLength * 1;
20+
var url = require('url');
21+
var fnv = require('fnv-plus');
22+
var RequestLogs = require('../models/RequestLogs');
23+
24+
var sanitizeRequestUrl = function(req) {
25+
var requestUrl = url.format({
26+
protocol: req.protocol,
27+
host: req.hostname,
28+
pathname: req.originalUrl || req.url,
29+
query: req.query
30+
});
31+
32+
return requestUrl.replace(/(password=).*?(&|$)/ig, '$1<hidden>$2');
33+
};
2034

2135
var allRequestData = function(req,res,next){
2236
var requestData = {};
@@ -41,8 +55,6 @@ var enforceUserIdAndAppId = function(req,res,next){
4155
}else if(!appId){
4256
res.badRequest(false,'No appId parameter was passed in the payload of this request. Please pass an appId.');
4357
}else{
44-
// Do a middleware that validates userId and appID here. put the user service endpoint in the env var. ideally, this should be the gateway endpoint
45-
// Check if this user and app is allowed on this service
4658
req.userId = userId;
4759
req.appId = appId;
4860
next();
@@ -80,9 +92,32 @@ limiter({
8092

8193
router.use(response);
8294
router.use(expressValidator());
95+
// Log requests here
8396
router.use(function(req,res,next){
84-
log.info('[TIME: '+new Date().toISOString()+'] [IP Address: '+req.ip+'] [METHOD: '+req.method+'] [URL: '+req.originalUrl+']');
85-
next();
97+
var ipAddress = req.get('x-forwarded-for') || req.connection && req.connection.remoteAddress;
98+
req.requestId = fnv.hash(new Date().valueOf() + ipAddress, 128).str();
99+
100+
var reqLog = {
101+
RequestId: req.requestId,
102+
ipAddress: ipAddress,
103+
url: sanitizeRequestUrl(req),
104+
method: req.method,
105+
body: _.omit(req.body, ['password','cardno']),
106+
app: req.appId,
107+
user: req.userId,
108+
device: req.get('user-agent'),
109+
createdAt: new Date()
110+
};
111+
112+
RequestLogs.create(reqLog)
113+
.then(function(res){
114+
return _.identity(res);
115+
});
116+
117+
// persist RequestLog entry in the background; continue immediately
118+
119+
log.info(reqLog);
120+
next();
86121
});
87122

88123
router.get('/', function (req, res) {

services/response/badRequest.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
"use strict";
22
var log = require('../logger');
3+
var RequestLogs = require('../../models/RequestLogs');
4+
var _ = require('lodash');
35

46
module.exports = function(data, message){
57
log.warn('Sending bad request response: ', data, message || 'bad request');
8+
var req = this.req;
9+
var res = this;
10+
11+
RequestLogs.update({RequestId: req.requestId},{response: {status: 'error', data: data, message: message ? message : 'bad request'}})
12+
.then(function(res){
13+
return _.identity(res);
14+
});
615

716
if (data !== undefined && data !== null) {
817
if(Object.keys(data).length === 0 && JSON.stringify(data) === JSON.stringify({})){

services/response/forbidden.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
"use strict";
22
var log = require('../logger');
3+
var RequestLogs = require('../../models/RequestLogs');
4+
var _ = require('lodash');
35

46
module.exports = function(data, message){
57
log.warn('Sending forbidden response: ', data, message || 'forbidden');
8+
var req = this.req;
9+
var res = this;
10+
11+
RequestLogs.update({RequestId: req.requestId},{response: {status: 'error', data: data, message: message ? message : 'forbidden'}})
12+
.then(function(res){
13+
return _.identity(res);
14+
});
615

716
if (data !== undefined && data !== null) {
817
if(Object.keys(data).length === 0 && JSON.stringify(data) === JSON.stringify({})){

services/response/notFound.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
"use strict";
22
var log = require('../logger');
3+
var RequestLogs = require('../../models/RequestLogs');
4+
var _ = require('lodash');
35

46
module.exports = function(){
57
log.warn('Sending 404 response: '+'not found');
8+
var req = this.req;
9+
var res = this;
10+
11+
RequestLogs.update({RequestId: req.requestId},{response: {status: 'error', message: 'not found'}})
12+
.then(function(res){
13+
return _.identity(res);
14+
});
15+
616
this.status(404).json({status: 'error', message: 'not found'});
717
};

services/response/ok.js

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,43 @@ var log = require('../logger');
33
var config = require('../../config');
44
var encryption = require('../encryption');
55
var debug = require('debug')('response');
6+
var RequestLogs = require('../../models/RequestLogs');
7+
var _ = require('lodash');
68

79
module.exports = function(data){
810
debug("sending ok response");
911
var req = this.req;
1012
var res = this;
1113

12-
if(req.header('x-tag') && req.method === 'POST' && config.secureMode && data){
13-
debug("i want to encrypt");
14-
var key = req.header('x-tag');
15-
debug('our encryption key: ', key);
16-
var text = JSON.stringify(data);
17-
debug("about to call encryption method");
18-
encryption.encrypt(text, key)
19-
.then(function(resp){
20-
debug("got response from encryption method: ",resp);
21-
log.info('Sending ok response: ', data);
22-
res.status(200).json({status: 'success', data: resp, secure: true});
23-
})
24-
.catch(function(err){
25-
debug("got error from encryption method: ", err);
26-
res.serverError(err,'Error encrypting response.');
27-
});
28-
}else{
29-
log.info('Sending ok response: ', data);
30-
if(data){
31-
res.status(200).json({status: 'success', data: data});
32-
}else{
33-
res.status(200).json({status: 'success'});
34-
}
35-
}
14+
RequestLogs.update({RequestId: req.requestId},{response: {status: 'success', data: data}})
15+
.then(function(res){
16+
return _.identity(res);
17+
});
18+
19+
20+
21+
if(req.header('x-tag') && req.method === 'POST' && config.secureMode && data){
22+
debug("i want to encrypt");
23+
var key = req.header('x-tag');
24+
debug('our encryption key: ', key);
25+
var text = JSON.stringify(data);
26+
debug("about to call encryption method");
27+
encryption.encrypt(text, key)
28+
.then(function(resp){
29+
debug("got response from encryption method: ",resp);
30+
log.info('Sending ok response: ', data);
31+
res.status(200).json({status: 'success', data: resp, secure: true});
32+
})
33+
.catch(function(err){
34+
debug("got error from encryption method: ", err);
35+
res.serverError(err,'Error encrypting response.');
36+
});
37+
}else{
38+
log.info('Sending ok response: ', data);
39+
if(data){
40+
res.status(200).json({status: 'success', data: data});
41+
}else{
42+
res.status(200).json({status: 'success'});
43+
}
44+
}
3645
};

0 commit comments

Comments
 (0)