azify-logger 1.0.20 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -382,8 +382,17 @@ function createExpressLoggingMiddleware(options = {}) {
382
382
 
383
383
  const statusCode = res._actualStatusCode || res._statusCode || res.statusCode || 200
384
384
 
385
+ let parsedResponseBody = serializedResponseBody
386
+ try {
387
+ if (typeof serializedResponseBody === 'string' && serializedResponseBody.trim().startsWith('{')) {
388
+ parsedResponseBody = JSON.parse(serializedResponseBody)
389
+ } else if (typeof serializedResponseBody === 'string' && serializedResponseBody.trim().startsWith('[')) {
390
+ parsedResponseBody = JSON.parse(serializedResponseBody)
391
+ }
392
+ } catch (_) {}
393
+
385
394
  const responseMessage = serializedResponseBody && serializedResponseBody.length > 0
386
- ? `[RESPONSE] ${serializedResponseBody}`
395
+ ? `[RESPONSE] ${req.method} ${req.url} ${statusCode}`
387
396
  : `[RESPONSE] ${req.method} ${req.url} ${statusCode} ${duration}ms`
388
397
 
389
398
  const responseData = {
@@ -392,7 +401,7 @@ function createExpressLoggingMiddleware(options = {}) {
392
401
  statusCode: statusCode,
393
402
  responseTime: duration,
394
403
  responseHeaders: res.getHeaders ? res.getHeaders() : {},
395
- responseBody: serializedResponseBody
404
+ responseBody: parsedResponseBody // Use parsed object instead of string
396
405
  }
397
406
 
398
407
  try { res._azifyResponseLogged = true } catch (_) {}
@@ -282,8 +282,20 @@ function createRestifyLoggingMiddleware(options = {}) {
282
282
 
283
283
  const statusCode = res._actualStatusCode || res._statusCode || res.statusCode || 200
284
284
 
285
+ // Try to parse serializedResponseBody back to object for cleaner display in Grafana
286
+ let parsedResponseBody = serializedResponseBody
287
+ try {
288
+ if (typeof serializedResponseBody === 'string' && serializedResponseBody.trim().startsWith('{')) {
289
+ parsedResponseBody = JSON.parse(serializedResponseBody)
290
+ } else if (typeof serializedResponseBody === 'string' && serializedResponseBody.trim().startsWith('[')) {
291
+ parsedResponseBody = JSON.parse(serializedResponseBody)
292
+ }
293
+ } catch (_) {
294
+ // Keep as string if parsing fails
295
+ }
296
+
285
297
  const responseMessage = serializedResponseBody && serializedResponseBody.length > 0
286
- ? `[RESPONSE] ${serializedResponseBody}`
298
+ ? `[RESPONSE] ${req.method} ${req.url} ${statusCode}`
287
299
  : `[RESPONSE] ${req.method} ${req.url} ${statusCode} ${duration}ms`
288
300
 
289
301
  const responseData = {
@@ -292,7 +304,7 @@ function createRestifyLoggingMiddleware(options = {}) {
292
304
  statusCode: statusCode,
293
305
  responseTime: duration,
294
306
  responseHeaders: res.getHeaders ? res.getHeaders() : {},
295
- responseBody: serializedResponseBody
307
+ responseBody: parsedResponseBody // Use parsed object instead of string
296
308
  }
297
309
 
298
310
  try { res._azifyResponseLogged = true } catch (_) {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azify-logger",
3
- "version": "1.0.20",
3
+ "version": "1.0.23",
4
4
  "description": "Azify Logger Client - Centralized logging for OpenSearch",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -30,14 +30,11 @@
30
30
  "axios": "^1.6.0",
31
31
  "cors": "^2.8.5",
32
32
  "express": "^4.18.2",
33
- "express-session": "^1.17.3",
34
- "passport": "^0.6.0",
35
- "passport-azure-ad": "^4.3.5",
36
33
  "require-in-the-middle": "^7.4.0",
37
34
  "uuid": "^9.0.1"
38
35
  },
39
36
  "optionalDependencies": {
40
- "@opentelemetry/api": "^1.7.0",
37
+ "@opentelemetry/api": "^1.9.0",
41
38
  "@opentelemetry/auto-instrumentations-node": "^0.40.0",
42
39
  "@opentelemetry/core": "^1.28.0",
43
40
  "@opentelemetry/exporter-trace-otlp-http": "^0.45.0",
package/server.js CHANGED
@@ -27,19 +27,57 @@ app.use(express.json({ limit: '10mb' }))
27
27
  app.use(express.urlencoded({ extended: true, limit: '10mb' }))
28
28
  app.use(cors())
29
29
 
30
- const authEnabled = process.env.AZURE_AD_AUTH_ENABLED === 'true'
31
- let ensureAuthenticated = (req, res, next) => next()
30
+ const IS_LOCAL = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev' || !process.env.NODE_ENV
32
31
 
33
- if (authEnabled) {
34
- const { setupAuth, setupAuthRoutes, ensureAuthenticated: authMiddleware } = require('./auth')
35
- ensureAuthenticated = authMiddleware
36
- setupAuth(app)
37
- setupAuthRoutes(app)
38
- console.log(' Autenticação Azure AD habilitada')
39
- } else {
40
- console.log('⚠️ Autenticação Azure AD desabilitada')
32
+ function isPrivateOrLocalhost(ip) {
33
+ if (IS_LOCAL) {
34
+ return true
35
+ }
36
+
37
+ ip = ip.replace('::ffff:', '').replace('::1', '127.0.0.1')
38
+
39
+ if (ip === '127.0.0.1' || ip === 'localhost' || ip === '::1') {
40
+ return true
41
+ }
42
+
43
+ const parts = ip.split('.').map(Number)
44
+
45
+ if (parts.length !== 4) {
46
+ return false
47
+ }
48
+
49
+ if (parts[0] === 10) return true
50
+ if (parts[0] === 127) return true
51
+ if (parts[0] === 192 && parts[1] === 168) return true
52
+ if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true
53
+
54
+ return false
55
+ }
56
+
57
+ function validateNetworkAccess(req, res, next) {
58
+ if (req.path === '/health' || req.path === '/') {
59
+ return next()
60
+ }
61
+
62
+ const clientIP = req.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
63
+ req.headers['x-real-ip'] ||
64
+ req.ip ||
65
+ req.connection.remoteAddress ||
66
+ req.socket.remoteAddress
67
+
68
+ if (!IS_LOCAL && !isPrivateOrLocalhost(clientIP)) {
69
+ return res.status(403).json({
70
+ success: false,
71
+ message: 'Forbidden. Access denied - endpoint only accessible from same server (localhost/private IPs).',
72
+ clientIP: clientIP
73
+ })
74
+ }
75
+
76
+ next()
41
77
  }
42
78
 
79
+ app.use(validateNetworkAccess)
80
+
43
81
  const tracer = trace.getTracer('azify-logger', '1.0.0')
44
82
  const propagator = new W3CTraceContextPropagator()
45
83
 
@@ -66,7 +104,7 @@ async function ensureIndexTemplate() {
66
104
  },
67
105
  mappings: {
68
106
  properties: {
69
- timestamp: { type: 'date' },
107
+ '@timestamp': { type: 'date' },
70
108
  level: { type: 'keyword' },
71
109
  message: { type: 'text' },
72
110
  service: {
@@ -114,54 +152,6 @@ async function ensureIndexTemplate() {
114
152
 
115
153
  ensureIndexTemplate()
116
154
 
117
- /**
118
- * Escapes HTML special characters to prevent XSS attacks
119
- * This prevents script injection when data is rendered in OpenSearch Dashboards
120
- * @param {string} str - String to escape
121
- * @returns {string} Escaped string
122
- */
123
- function escapeHtml(str) {
124
- if (typeof str !== 'string') return str
125
- const map = {
126
- '&': '&amp;',
127
- '<': '&lt;',
128
- '>': '&gt;',
129
- '"': '&quot;',
130
- "'": '&#x27;',
131
- '/': '&#x2F;'
132
- }
133
- return str.replace(/[&<>"'/]/g, (m) => map[m])
134
- }
135
-
136
- /**
137
- * Sanitizes a value recursively to prevent XSS attacks
138
- * Escapes HTML special characters in strings that could be rendered in Dashboards
139
- * @param {any} value - Value to sanitize
140
- * @returns {any} Sanitized value
141
- */
142
- function sanitizeValue(value) {
143
- if (typeof value === 'string') {
144
- // Escape HTML special characters to prevent XSS when rendered in Dashboards
145
- return escapeHtml(value)
146
- }
147
-
148
- if (Array.isArray(value)) {
149
- return value.map(item => sanitizeValue(item))
150
- }
151
-
152
- if (value !== null && typeof value === 'object') {
153
- const sanitized = {}
154
- for (const key in value) {
155
- if (value.hasOwnProperty(key)) {
156
- sanitized[key] = sanitizeValue(value[key])
157
- }
158
- }
159
- return sanitized
160
- }
161
-
162
- return value
163
- }
164
-
165
155
  function generateTraceId() {
166
156
  return Math.random().toString(36).substring(2, 15) +
167
157
  Math.random().toString(36).substring(2, 15)
@@ -194,41 +184,24 @@ function getOrCreateTraceContext(requestId) {
194
184
  app.get('/health', (req, res) => {
195
185
  res.json({
196
186
  status: 'ok',
197
- service: 'azify-logger',
198
- authEnabled: authEnabled
187
+ service: 'azify-logger'
199
188
  })
200
189
  })
201
190
 
202
- app.get('/', ensureAuthenticated, (req, res) => {
191
+ app.get('/', (req, res) => {
203
192
  res.json({
204
193
  service: 'azify-logger',
205
194
  version: '1.0.0',
206
195
  endpoints: {
207
196
  health: '/health',
208
- testLog: '/test-log',
209
- auth: authEnabled ? {
210
- login: '/auth/login',
211
- logout: '/auth/logout',
212
- me: '/auth/me'
213
- } : null
214
- },
215
- user: req.user || null
197
+ testLog: '/test-log'
198
+ }
216
199
  })
217
200
  })
218
201
 
219
202
  app.post('/log', async (req, res) => {
220
203
  let { level, message, meta } = req.body
221
204
 
222
- if (typeof message === 'string') {
223
- message = sanitizeValue(message)
224
- }
225
- if (meta) {
226
- meta = sanitizeValue(meta)
227
- }
228
- if (typeof level === 'string') {
229
- level = sanitizeValue(level)
230
- }
231
-
232
205
  if (!level || !message) {
233
206
  return res.status(400).json({ success: false, message: 'Level and message are required.' })
234
207
  }
@@ -297,7 +270,7 @@ app.post('/log', async (req, res) => {
297
270
  }
298
271
 
299
272
  const logEntry = {
300
- timestamp: (meta && meta.timestamp) || new Date().toISOString(),
273
+ '@timestamp': (meta && meta.timestamp) || new Date().toISOString(),
301
274
  level,
302
275
  message,
303
276
  service: {