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)
@@ -43,8 +40,15 @@ module.exports = function (options, handler) {
43
40
options . identifyCompany = options . identifyCompany || function ( ) { } ;
44
41
45
42
options . getSessionToken = options . getSessionToken || function ( event , context ) {
46
- return ( event . requestContext && event . requestContext . identity && event . requestContext . identity . apiKey ) ;
43
+ return ( event . requestContext && event . requestContext . identity && event . requestContext . identity . apiKey ) ;
47
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
+ } ;
48
52
options . getTags = options . getTags || function ( ) {
49
53
return undefined ;
50
54
} ;
@@ -61,15 +65,23 @@ module.exports = function (options, handler) {
61
65
return false ;
62
66
} ;
63
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
+
64
74
ensureValidOptions ( options ) ;
65
75
66
76
// config moesifapi
67
77
var config = moesifapi . configuration ;
68
- 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 ;
69
80
var moesifController = moesifapi . ApiController ;
70
81
71
82
var moesifMiddleware = function ( event , context , callback ) {
72
83
logMessage ( options . debug , 'moesifMiddleware' , 'start' ) ;
84
+ moesifConfigManager . tryGetConfig ( ) ;
73
85
74
86
var next = function ( err , result ) {
75
87
logEvent ( event , context , err , result , options , moesifController ) ;
@@ -79,18 +91,42 @@ module.exports = function (options, handler) {
79
91
handler ( event , context , next ) ;
80
92
} ;
81
93
82
- moesifMiddleware . updateUser = function ( userModel , cb ) {
94
+ moesifMiddleware . updateUser = function ( userModel , cb ) {
95
+ const user = new UserModel ( userModel ) ;
83
96
logMessage ( options . debug , 'updateUser' , 'userModel=' + JSON . stringify ( userModel ) ) ;
84
- ensureValidUserModel ( userModel ) ;
97
+ ensureValidUserModel ( user ) ;
85
98
logMessage ( options . debug , 'updateUser' , 'userModel valid' ) ;
86
- 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 ) ;
87
111
} ;
88
112
89
- moesifMiddleware . updateCompany = function ( companyModel , cb ) {
113
+ moesifMiddleware . updateCompany = function ( companyModel , cb ) {
114
+ const company = new CompanyModel ( companyModel ) ;
90
115
logMessage ( options . debug , 'updateCompany' , 'companyModel=' + JSON . stringify ( companyModel ) ) ;
91
- ensureValidCompanyModel ( companyModel ) ;
116
+ ensureValidCompanyModel ( company ) ;
92
117
logMessage ( options . debug , 'updateCompany' , 'companyModel valid' ) ;
93
- moesifController . updateCompany ( companyModel , cb ) ;
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 ) ;
94
130
} ;
95
131
96
132
logMessage ( options . debug , 'moesifInitiator' , 'returning moesifMiddleware Function' ) ;
@@ -99,10 +135,6 @@ module.exports = function (options, handler) {
99
135
100
136
function mapResponseHeaders ( event , context , result ) {
101
137
const headers = result . headers || { } ; // NOTE: Mutating event.headers; prefer deep clone of event.headers
102
-
103
- headers [ 'x-amzn-trace-id' ] = context . awsRequestId ;
104
- headers [ 'x-amzn-function-name' ] = context . functionName ;
105
- headers [ 'x-apigateway-trace-id' ] = ( event && event . requestContext && event . requestContext . requestId ) || ( context && context . requestContext && context . requestContext . requestId ) ;
106
138
return headers ;
107
139
}
108
140
@@ -114,44 +146,45 @@ function logEvent(event, context, err, result, options, moesifController) {
114
146
return ;
115
147
}
116
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
+
117
156
logData . request . uri = getPathWithQueryStringParams ( event ) ;
118
157
logData . request . verb = event . httpMethod ;
119
158
logData . request . apiVerion = options . getApiVersion ( event , context ) ;
120
159
logData . request . ipAddress = requestIp . getClientIp ( event ) || ( event . requestContext && event . requestContext . identity && event . requestContext . identity . sourceIp ) ;
121
160
logData . request . headers = event . headers || { } ;
161
+ logData . metadata = options . getMetadata ( event , context ) ;
122
162
123
- if ( event . body ) {
163
+ if ( options . logBody && event . body ) {
124
164
if ( event . isBase64Encoded ) {
125
- logData . request . transferEncoding = 'base64' ;
126
- logData . request . body = bodyToBase64 ( event . body ) ;
165
+ logData . request . body = event . body ;
166
+ logData . request . transferEncoding = 'base64' ;
127
167
} else {
128
- try {
129
- logData . request . body = JSON . parse ( event . body ) ;
130
- } catch ( err ) {
131
- logData . request . body = event . body ;
132
- }
168
+ const bodyWrapper = safeJsonParse ( event . body ) ;
169
+ logData . request . body = bodyWrapper . body
170
+ logData . request . transferEncoding = bodyWrapper . transferEncoding
133
171
}
134
172
}
135
173
136
174
logMessage ( options . debug , 'logEvent' , 'created request: \n' + JSON . stringify ( logData . request ) ) ;
137
175
var safeRes = result || { } ;
138
- logData . response . time = Date . now ( ) ;
176
+ logData . response . time = new Date ( Math . max ( logData . request . time . getTime ( ) , Date . now ( ) ) ) ;
139
177
logData . response . status = safeRes . statusCode ? parseInt ( safeRes . statusCode ) : 599 ;
140
178
logData . response . headers = mapResponseHeaders ( event , context , safeRes ) ;
141
179
142
- if ( safeRes . body ) {
180
+ if ( options . logBody && safeRes . body ) {
143
181
if ( safeRes . isBase64Encoded ) {
144
- // does this flag exists from AWS?
145
- logData . response . transferEncoding = 'base64' ;
146
- logData . response . body = bodyToBase64 ( safeRes . body ) ;
182
+ logData . response . body = safeRes . body ;
183
+ logData . response . transferEncoding = 'base64' ;
147
184
} else {
148
- try {
149
- logData . response . body = JSON . parse ( safeRes . body ) ;
150
- } catch ( err ) {
151
- // if JSON decode fails, we'll try to base64 encode the body.
152
- logData . response . transferEncoding = 'base64' ;
153
- logData . response . body = bodyToBase64 ( safeRes . body ) ;
154
- }
185
+ const bodyWrapper = safeJsonParse ( safeRes . body ) ;
186
+ logData . response . body = bodyWrapper . body
187
+ logData . response . transferEncoding = bodyWrapper . transferEncoding
155
188
}
156
189
}
157
190
@@ -169,7 +202,7 @@ function logEvent(event, context, err, result, options, moesifController) {
169
202
ensureValidLogData ( logData ) ;
170
203
171
204
// This is fire and forget, we don't want logging to hold up the request so don't wait for the callback
172
- if ( ! options . skip ( event , context ) ) {
205
+ if ( ! options . skip ( event , context ) && moesifConfigManager . shouldSend ( logData && logData . userId , logData && logData . companyId ) ) {
173
206
logMessage ( options . debug , 'logEvent' , 'sending data invoking moesifAPI' ) ;
174
207
175
208
moesifController . createEvent ( new EventModel ( logData ) , function ( err ) {
@@ -203,8 +236,48 @@ function bodyToBase64(body) {
203
236
}
204
237
}
205
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
+
206
275
function getPathWithQueryStringParams ( event ) {
207
- 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
+ }
208
281
}
209
282
210
283
function ensureValidOptions ( options ) {
@@ -213,14 +286,20 @@ function ensureValidOptions(options) {
213
286
if ( options . identifyUser && ! _ . isFunction ( options . identifyUser ) ) {
214
287
throw new Error ( 'identifyUser should be a function' ) ;
215
288
}
289
+ if ( options . identifyCompany && ! _ . isFunction ( options . identifyCompany ) ) {
290
+ throw new Error ( 'identifyCompany should be a function' ) ;
291
+ }
216
292
if ( options . getSessionToken && ! _ . isFunction ( options . getSessionToken ) ) {
217
293
throw new Error ( 'getSessionToken should be a function' ) ;
218
294
}
295
+ if ( options . getMetadata && ! _ . isFunction ( options . getMetadata ) ) {
296
+ throw new Error ( 'getMetadata should be a function' ) ;
297
+ }
219
298
if ( options . getTags && ! _ . isFunction ( options . getTags ) ) {
220
299
throw new Error ( 'getTags should be a function' ) ;
221
300
}
222
301
if ( options . getApiVersion && ! _ . isFunction ( options . getApiVersion ) ) {
223
- throw new Error ( 'identifyUser should be a function' ) ;
302
+ throw new Error ( 'getApiVersion should be a function' ) ;
224
303
}
225
304
if ( options . maskContent && ! _ . isFunction ( options . maskContent ) ) {
226
305
throw new Error ( 'maskContent should be a function' ) ;
@@ -249,9 +328,6 @@ function ensureValidLogData(logData) {
249
328
throw new Error ( 'For Moesif events, request and response objects are required. Please check your maskContent function do not remove this' ) ;
250
329
}
251
330
else {
252
- // if (!logData.response.body) {
253
- // throw new Error('for log events, response body objects is required but can be empty object');
254
- // }
255
331
if ( ! logData . request . time ) {
256
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' ) ;
257
333
}
0 commit comments