1- /**
2- * Created by derric on 8/22/17.
3- */
41'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 ( ) ;
1411
1512//
1613// ### function moesifExpress(options)
@@ -43,8 +40,15 @@ module.exports = function (options, handler) {
4340 options . identifyCompany = options . identifyCompany || function ( ) { } ;
4441
4542 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 ) ;
4744 } ;
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+ } ;
4852 options . getTags = options . getTags || function ( ) {
4953 return undefined ;
5054 } ;
@@ -61,15 +65,23 @@ module.exports = function (options, handler) {
6165 return false ;
6266 } ;
6367
68+ var logBody = true ;
69+ if ( typeof options . logBody !== 'undefined' && options . logBody !== null ) {
70+ logBody = Boolean ( options . logBody ) ;
71+ }
72+ options . logBody = logBody ;
73+
6474 ensureValidOptions ( options ) ;
6575
6676 // config moesifapi
6777 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 ;
6980 var moesifController = moesifapi . ApiController ;
7081
7182 var moesifMiddleware = function ( event , context , callback ) {
7283 logMessage ( options . debug , 'moesifMiddleware' , 'start' ) ;
84+ moesifConfigManager . tryGetConfig ( ) ;
7385
7486 var next = function ( err , result ) {
7587 logEvent ( event , context , err , result , options , moesifController ) ;
@@ -79,18 +91,42 @@ module.exports = function (options, handler) {
7991 handler ( event , context , next ) ;
8092 } ;
8193
82- moesifMiddleware . updateUser = function ( userModel , cb ) {
94+ moesifMiddleware . updateUser = function ( userModel , cb ) {
95+ const user = new UserModel ( userModel ) ;
8396 logMessage ( options . debug , 'updateUser' , 'userModel=' + JSON . stringify ( userModel ) ) ;
84- ensureValidUserModel ( userModel ) ;
97+ ensureValidUserModel ( user ) ;
8598 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 ) ;
87111 } ;
88112
89- moesifMiddleware . updateCompany = function ( companyModel , cb ) {
113+ moesifMiddleware . updateCompany = function ( companyModel , cb ) {
114+ const company = new CompanyModel ( companyModel ) ;
90115 logMessage ( options . debug , 'updateCompany' , 'companyModel=' + JSON . stringify ( companyModel ) ) ;
91- ensureValidCompanyModel ( companyModel ) ;
116+ ensureValidCompanyModel ( company ) ;
92117 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 ) ;
94130 } ;
95131
96132 logMessage ( options . debug , 'moesifInitiator' , 'returning moesifMiddleware Function' ) ;
@@ -99,10 +135,6 @@ module.exports = function (options, handler) {
99135
100136function mapResponseHeaders ( event , context , result ) {
101137 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 ) ;
106138 return headers ;
107139}
108140
@@ -114,44 +146,45 @@ function logEvent(event, context, err, result, options, moesifController) {
114146 return ;
115147 }
116148
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+
117156 logData . request . uri = getPathWithQueryStringParams ( event ) ;
118157 logData . request . verb = event . httpMethod ;
119158 logData . request . apiVerion = options . getApiVersion ( event , context ) ;
120159 logData . request . ipAddress = requestIp . getClientIp ( event ) || ( event . requestContext && event . requestContext . identity && event . requestContext . identity . sourceIp ) ;
121160 logData . request . headers = event . headers || { } ;
161+ logData . metadata = options . getMetadata ( event , context ) ;
122162
123- if ( event . body ) {
163+ if ( options . logBody && event . body ) {
124164 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' ;
127167 } 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
133171 }
134172 }
135173
136174 logMessage ( options . debug , 'logEvent' , 'created request: \n' + JSON . stringify ( logData . request ) ) ;
137175 var safeRes = result || { } ;
138- logData . response . time = Date . now ( ) ;
176+ logData . response . time = new Date ( Math . max ( logData . request . time . getTime ( ) , Date . now ( ) ) ) ;
139177 logData . response . status = safeRes . statusCode ? parseInt ( safeRes . statusCode ) : 599 ;
140178 logData . response . headers = mapResponseHeaders ( event , context , safeRes ) ;
141179
142- if ( safeRes . body ) {
180+ if ( options . logBody && safeRes . body ) {
143181 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' ;
147184 } 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
155188 }
156189 }
157190
@@ -169,7 +202,7 @@ function logEvent(event, context, err, result, options, moesifController) {
169202 ensureValidLogData ( logData ) ;
170203
171204 // 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 ) ) {
173206 logMessage ( options . debug , 'logEvent' , 'sending data invoking moesifAPI' ) ;
174207
175208 moesifController . createEvent ( new EventModel ( logData ) , function ( err ) {
@@ -203,8 +236,48 @@ function bodyToBase64(body) {
203236 }
204237}
205238
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+
206275function 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+ }
208281}
209282
210283function ensureValidOptions ( options ) {
@@ -213,14 +286,20 @@ function ensureValidOptions(options) {
213286 if ( options . identifyUser && ! _ . isFunction ( options . identifyUser ) ) {
214287 throw new Error ( 'identifyUser should be a function' ) ;
215288 }
289+ if ( options . identifyCompany && ! _ . isFunction ( options . identifyCompany ) ) {
290+ throw new Error ( 'identifyCompany should be a function' ) ;
291+ }
216292 if ( options . getSessionToken && ! _ . isFunction ( options . getSessionToken ) ) {
217293 throw new Error ( 'getSessionToken should be a function' ) ;
218294 }
295+ if ( options . getMetadata && ! _ . isFunction ( options . getMetadata ) ) {
296+ throw new Error ( 'getMetadata should be a function' ) ;
297+ }
219298 if ( options . getTags && ! _ . isFunction ( options . getTags ) ) {
220299 throw new Error ( 'getTags should be a function' ) ;
221300 }
222301 if ( options . getApiVersion && ! _ . isFunction ( options . getApiVersion ) ) {
223- throw new Error ( 'identifyUser should be a function' ) ;
302+ throw new Error ( 'getApiVersion should be a function' ) ;
224303 }
225304 if ( options . maskContent && ! _ . isFunction ( options . maskContent ) ) {
226305 throw new Error ( 'maskContent should be a function' ) ;
@@ -249,9 +328,6 @@ function ensureValidLogData(logData) {
249328 throw new Error ( 'For Moesif events, request and response objects are required. Please check your maskContent function do not remove this' ) ;
250329 }
251330 else {
252- // if (!logData.response.body) {
253- // throw new Error('for log events, response body objects is required but can be empty object');
254- // }
255331 if ( ! logData . request . time ) {
256332 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' ) ;
257333 }
0 commit comments