1
- /**
2
- * Created by derric on 8/22/17.
3
- */
4
1
'use strict'
5
- var _ = require ( 'lodash' ) ;
6
- var url = require ( 'url' ) ;
7
- var moesifapi = require ( 'moesifapi' ) ;
8
- var EventModel = moesifapi . EventModel ;
9
- var requestIp = require ( 'request-ip ' ) ;
10
- var logData = { } ;
11
- logData . request = { } ;
12
- logData . response = { } ;
13
- logData . request . time = Date . now ( ) ;
2
+ const _ = require ( 'lodash' ) ;
3
+ const url = require ( 'url' ) ;
4
+ const moesifapi = require ( 'moesifapi' ) ;
5
+ const requestIp = require ( 'request-ip' ) ;
6
+ const moesifConfigManager = require ( './moesifConfigManager ' ) ;
7
+ const EventModel = moesifapi . EventModel ;
8
+ const UserModel = moesifapi . UserModel ;
9
+ const CompanyModel = moesifapi . CompanyModel ;
10
+ var startTime = Date . now ( ) ;
14
11
15
12
//
16
13
// ### function moesifExpress(options)
@@ -39,9 +36,19 @@ module.exports = function (options, handler) {
39
36
( event . requestContext && event . requestContext . identity && event . requestContext . identity . user ) ||
40
37
event . user ;
41
38
} ;
39
+
40
+ options . identifyCompany = options . identifyCompany || function ( ) { } ;
41
+
42
42
options . getSessionToken = options . getSessionToken || function ( event , context ) {
43
- return ( event . requestContext && event . requestContext . identity && event . requestContext . identity . apiKey ) ;
43
+ return ( event . requestContext && event . requestContext . identity && event . requestContext . identity . apiKey ) ;
44
44
} ;
45
+ options . getMetadata = options . getMetadata || function ( event , context ) {
46
+ const metadata = { } ;
47
+ metadata . trace_id = context . awsRequestId ;
48
+ metadata . function_name = context . functionName ;
49
+ metadata . request_context = event && event . requestContext ;
50
+ return metadata ;
51
+ } ;
45
52
options . getTags = options . getTags || function ( ) {
46
53
return undefined ;
47
54
} ;
@@ -58,29 +65,68 @@ module.exports = function (options, handler) {
58
65
return false ;
59
66
} ;
60
67
68
+ var logBody = true ;
69
+ if ( typeof options . logBody !== 'undefined' && options . logBody !== null ) {
70
+ logBody = Boolean ( options . logBody ) ;
71
+ }
72
+ options . logBody = logBody ;
73
+
61
74
ensureValidOptions ( options ) ;
62
75
63
76
// config moesifapi
64
77
var config = moesifapi . configuration ;
65
- config . ApplicationId = options . applicationId || process . env . MOESIF_APPLICATION_ID ;
78
+ config . ApplicationId = options . applicationId || options . ApplicationId || process . env . MOESIF_APPLICATION_ID ;
79
+ config . BaseUri = options . baseUri || options . BaseUri || config . BaseUri ;
66
80
var moesifController = moesifapi . ApiController ;
67
81
68
82
var moesifMiddleware = function ( event , context , callback ) {
69
83
logMessage ( options . debug , 'moesifMiddleware' , 'start' ) ;
84
+ moesifConfigManager . tryGetConfig ( ) ;
70
85
71
- var next = function ( err , result ) {
72
- logEvent ( event , context , err , result , options , moesifController ) ;
73
- callback ( err , result )
74
- } ;
86
+ var next = function ( err , result ) {
87
+ logEvent ( event , context , err , result , options , moesifController ) ;
88
+ callback ( err , result )
89
+ } ;
75
90
76
- handler ( event , context , next ) ;
91
+ handler ( event , context , next ) ;
77
92
} ;
78
93
79
- moesifMiddleware . updateUser = function ( userModel , cb ) {
94
+ moesifMiddleware . updateUser = function ( userModel , cb ) {
95
+ const user = new UserModel ( userModel ) ;
80
96
logMessage ( options . debug , 'updateUser' , 'userModel=' + JSON . stringify ( userModel ) ) ;
81
- ensureValidUserModel ( userModel ) ;
97
+ ensureValidUserModel ( user ) ;
82
98
logMessage ( options . debug , 'updateUser' , 'userModel valid' ) ;
83
- moesifController . updateUser ( userModel , cb ) ;
99
+ moesifController . updateUser ( user , cb ) ;
100
+ } ;
101
+
102
+ moesifMiddleware . updateUsersBatch = function ( usersBatchModel , cb ) {
103
+ usersBatch = [ ] ;
104
+ for ( let userModel of usersBatchModel ) {
105
+ usersBatch . push ( new UserModel ( userModel ) ) ;
106
+ }
107
+ logMessage ( options . debug , 'updateUsersBatch' , 'usersBatchModel=' + JSON . stringify ( usersBatchModel ) ) ;
108
+ ensureValidUsersBatchModel ( usersBatch ) ;
109
+ logMessage ( options . debug , 'updateUsersBatch' , 'usersBatchModel valid' ) ;
110
+ moesifController . updateUsersBatch ( usersBatch , cb ) ;
111
+ } ;
112
+
113
+ moesifMiddleware . updateCompany = function ( companyModel , cb ) {
114
+ const company = new CompanyModel ( companyModel ) ;
115
+ logMessage ( options . debug , 'updateCompany' , 'companyModel=' + JSON . stringify ( companyModel ) ) ;
116
+ ensureValidCompanyModel ( company ) ;
117
+ logMessage ( options . debug , 'updateCompany' , 'companyModel valid' ) ;
118
+ moesifController . updateCompany ( company , cb ) ;
119
+ }
120
+
121
+ moesifMiddleware . updateCompaniesBatch = function ( companiesBatchModel , cb ) {
122
+ companiesBatch = [ ] ;
123
+ for ( let companyModel of companiesBatchModel ) {
124
+ companiesBatch . push ( new CompanyModel ( companyModel ) ) ;
125
+ }
126
+ logMessage ( options . debug , 'updateCompaniesBatch' , 'companiesBatchModel=' + JSON . stringify ( companiesBatchModel ) ) ;
127
+ ensureValidCompaniesBatchModel ( companiesBatch ) ;
128
+ logMessage ( options . debug , 'updateCompaniesBatch' , 'companiesBatchModel valid' ) ;
129
+ moesifController . updateCompaniesBatch ( companiesBatch , cb ) ;
84
130
} ;
85
131
86
132
logMessage ( options . debug , 'moesifInitiator' , 'returning moesifMiddleware Function' ) ;
@@ -89,10 +135,6 @@ module.exports = function (options, handler) {
89
135
90
136
function mapResponseHeaders ( event , context , result ) {
91
137
const headers = result . headers || { } ; // NOTE: Mutating event.headers; prefer deep clone of event.headers
92
-
93
- headers [ 'x-amzn-trace-id' ] = context . awsRequestId ;
94
- headers [ 'x-amzn-function-name' ] = context . functionName ;
95
- headers [ 'x-apigateway-trace-id' ] = ( event && event . requestContext && event . requestContext . requestId ) || ( context && context . requestContext && context . requestContext . requestId ) ;
96
138
return headers ;
97
139
}
98
140
@@ -104,41 +146,45 @@ function logEvent(event, context, err, result, options, moesifController) {
104
146
return ;
105
147
}
106
148
149
+ var logData = { } ;
150
+ logData . request = { } ;
151
+ logData . response = { } ;
152
+ logData . request . time = event && event . requestContext && event . requestContext . requestTimeEpoch ?
153
+ new Date ( event && event . requestContext && event . requestContext . requestTimeEpoch ) :
154
+ startTime ;
155
+
107
156
logData . request . uri = getPathWithQueryStringParams ( event ) ;
108
157
logData . request . verb = event . httpMethod ;
109
158
logData . request . apiVerion = options . getApiVersion ( event , context ) ;
110
159
logData . request . ipAddress = requestIp . getClientIp ( event ) || ( event . requestContext && event . requestContext . identity && event . requestContext . identity . sourceIp ) ;
111
160
logData . request . headers = event . headers || { } ;
161
+ logData . metadata = options . getMetadata ( event , context ) ;
112
162
113
- if ( event . body ) {
163
+ if ( options . logBody && event . body ) {
114
164
if ( event . isBase64Encoded ) {
115
- logData . request . transferEncoding = 'base64' ;
116
- logData . request . body = bodyToBase64 ( event . body ) ;
165
+ logData . request . body = event . body ;
166
+ logData . request . transferEncoding = 'base64' ;
117
167
} else {
118
- try {
119
- logData . request . body = JSON . parse ( event . body ) ;
120
- } catch ( err ) {
121
- logData . request . body = event . body ;
122
- }
168
+ const bodyWrapper = safeJsonParse ( event . body ) ;
169
+ logData . request . body = bodyWrapper . body
170
+ logData . request . transferEncoding = bodyWrapper . transferEncoding
123
171
}
124
172
}
125
173
126
174
logMessage ( options . debug , 'logEvent' , 'created request: \n' + JSON . stringify ( logData . request ) ) ;
127
175
var safeRes = result || { } ;
128
- logData . response . time = Date . now ( ) ;
176
+ logData . response . time = new Date ( Math . max ( logData . request . time . getTime ( ) , Date . now ( ) ) ) ;
129
177
logData . response . status = safeRes . statusCode ? parseInt ( safeRes . statusCode ) : 599 ;
130
178
logData . response . headers = mapResponseHeaders ( event , context , safeRes ) ;
131
179
132
- if ( safeRes . body ) {
180
+ if ( options . logBody && safeRes . body ) {
133
181
if ( safeRes . isBase64Encoded ) {
134
- logData . response . transferEncoding = 'base64' ;
135
- logData . response . body = bodyToBase64 ( safeRes . body ) ;
182
+ logData . response . body = safeRes . body ;
183
+ logData . response . transferEncoding = 'base64' ;
136
184
} else {
137
- try {
138
- logData . response . body = JSON . parse ( safeRes . body ) ;
139
- } catch ( err ) {
140
- logData . response . body = safeRes . body ;
141
- }
185
+ const bodyWrapper = safeJsonParse ( safeRes . body ) ;
186
+ logData . response . body = bodyWrapper . body
187
+ logData . response . transferEncoding = bodyWrapper . transferEncoding
142
188
}
143
189
}
144
190
@@ -147,6 +193,7 @@ function logEvent(event, context, err, result, options, moesifController) {
147
193
logData = options . maskContent ( logData ) ;
148
194
149
195
logData . userId = options . identifyUser ( event , context ) ;
196
+ logData . companyId = options . identifyCompany ( event , context ) ;
150
197
logData . sessionToken = options . getSessionToken ( event , context ) ;
151
198
logData . tags = options . getTags ( event , context ) ;
152
199
@@ -155,7 +202,7 @@ function logEvent(event, context, err, result, options, moesifController) {
155
202
ensureValidLogData ( logData ) ;
156
203
157
204
// This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
158
- if ( ! options . skip ( event , context ) ) {
205
+ if ( ! options . skip ( event , context ) && moesifConfigManager . shouldSend ( logData && logData . userId , logData && logData . companyId ) ) {
159
206
logMessage ( options . debug , 'logEvent' , 'sending data invoking moesifAPI' ) ;
160
207
161
208
moesifController . createEvent ( new EventModel ( logData ) , function ( err ) {
@@ -189,8 +236,48 @@ function bodyToBase64(body) {
189
236
}
190
237
}
191
238
239
+ function safeJsonParse ( body ) {
240
+ try {
241
+ if ( ! Buffer . isBuffer ( body ) &&
242
+ ( typeof body === 'object' || Array . isArray ( body ) ) ) {
243
+ return {
244
+ body : body ,
245
+ transferEncoding : undefined
246
+ }
247
+ }
248
+ return {
249
+ body : JSON . parse ( body . toString ( ) ) ,
250
+ transferEncoding : undefined
251
+ }
252
+ } catch ( e ) {
253
+ return {
254
+ body : bodyToBase64 ( body ) ,
255
+ transferEncoding : 'base64'
256
+ }
257
+ }
258
+ }
259
+
260
+ function bodyToBase64 ( body ) {
261
+ if ( ! body ) {
262
+ return body ;
263
+ }
264
+ if ( Buffer . isBuffer ( body ) ) {
265
+ return body . toString ( 'base64' ) ;
266
+ } else if ( typeof body === 'string' ) {
267
+ return Buffer . from ( body ) . toString ( 'base64' ) ;
268
+ } else if ( typeof body . toString === 'function' ) {
269
+ return Buffer . from ( body . toString ( ) ) . toString ( 'base64' ) ;
270
+ } else {
271
+ return '' ;
272
+ }
273
+ }
274
+
192
275
function getPathWithQueryStringParams ( event ) {
193
- return url . format ( { pathname : event . path , query : event . queryStringParameters } )
276
+ try {
277
+ return url . format ( { pathname : event . path , query : event . queryStringParameters } ) ;
278
+ } catch ( err ) {
279
+ return '/' ;
280
+ }
194
281
}
195
282
196
283
function ensureValidOptions ( options ) {
@@ -199,14 +286,20 @@ function ensureValidOptions(options) {
199
286
if ( options . identifyUser && ! _ . isFunction ( options . identifyUser ) ) {
200
287
throw new Error ( 'identifyUser should be a function' ) ;
201
288
}
289
+ if ( options . identifyCompany && ! _ . isFunction ( options . identifyCompany ) ) {
290
+ throw new Error ( 'identifyCompany should be a function' ) ;
291
+ }
202
292
if ( options . getSessionToken && ! _ . isFunction ( options . getSessionToken ) ) {
203
293
throw new Error ( 'getSessionToken should be a function' ) ;
204
294
}
295
+ if ( options . getMetadata && ! _ . isFunction ( options . getMetadata ) ) {
296
+ throw new Error ( 'getMetadata should be a function' ) ;
297
+ }
205
298
if ( options . getTags && ! _ . isFunction ( options . getTags ) ) {
206
299
throw new Error ( 'getTags should be a function' ) ;
207
300
}
208
301
if ( options . getApiVersion && ! _ . isFunction ( options . getApiVersion ) ) {
209
- throw new Error ( 'identifyUser should be a function' ) ;
302
+ throw new Error ( 'getApiVersion should be a function' ) ;
210
303
}
211
304
if ( options . maskContent && ! _ . isFunction ( options . maskContent ) ) {
212
305
throw new Error ( 'maskContent should be a function' ) ;
@@ -235,17 +328,20 @@ function ensureValidLogData(logData) {
235
328
throw new Error ( 'For Moesif events, request and response objects are required. Please check your maskContent function do not remove this' ) ;
236
329
}
237
330
else {
238
- // if (!logData.response.body) {
239
- // throw new Error('for log events, response body objects is required but can be empty object');
240
- // }
241
331
if ( ! logData . request . time ) {
242
332
throw new Error ( 'For Moesif events, response time is required. The middleware should populate it automatically. Please check your maskContent function do not remove this' ) ;
243
333
}
244
334
}
245
335
}
246
336
247
337
function ensureValidUserModel ( userModel ) {
248
- if ( ! userModel . userId ) {
338
+ if ( ! userModel || ! userModel . userId ) {
249
339
throw new Error ( 'To update user, a userId field is required' ) ;
250
340
}
251
341
}
342
+
343
+ function ensureValidCompanyModel ( companyModel ) {
344
+ if ( ! companyModel || ! companyModel . companyId ) {
345
+ throw new Error ( 'To update company, a companyId field is required' ) ;
346
+ }
347
+ }
0 commit comments