Skip to content

Commit

Permalink
Merge pull request #215 from opencrvs/ocrvs-country-config-7181
Browse files Browse the repository at this point in the history
Redact sensitive user information from log
  • Loading branch information
tareq89 authored Sep 4, 2024
2 parents d012191 + 60727ae commit 081d9d1
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 30 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

- **Title** Description

### Improvements

- Auth token, ip address, remote address, mobile number, email redacted/masked from server log

### Infrastructure breaking changes

- **Title** Description
Expand Down
12 changes: 8 additions & 4 deletions src/api/notification/email-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/

import { logger } from '@countryconfig/logger'
import { logger, maskEmail } from '@countryconfig/logger'
import * as Handlebars from 'handlebars'
import * as nodemailer from 'nodemailer'
import {
Expand Down Expand Up @@ -50,12 +50,14 @@ export const sendEmail = async (params: {

if (formattedParams.to.endsWith('@example.com')) {
logger.info(
`Example email detected: ${formattedParams.to}. Not sending the email.`
`Example email detected: ${maskEmail(
formattedParams.to
)}. Not sending the email.`
)
return
}

logger.info(`Sending email to ${formattedParams.to}`)
logger.info(`Sending email to ${maskEmail(formattedParams.to)}`)

const emailTransport = nodemailer.createTransport({
host: SMTP_HOST,
Expand All @@ -77,7 +79,9 @@ export const sendEmail = async (params: {
logger.error(`Unable to send mass email for error : ${error}`)
} else {
logger.error(
`Unable to send email to ${formattedParams.to} for error : ${error}`
`Unable to send email to ${maskEmail(
formattedParams.to
)} for error : ${error}`
)
}

Expand Down
16 changes: 13 additions & 3 deletions src/api/notification/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import { logger } from '@countryconfig/logger'
import { logger, maskEmail, maskSms } from '@countryconfig/logger'
import * as Hapi from '@hapi/hapi'
import * as Joi from 'joi'
import { IApplicationConfig, getApplicationConfig } from '../../utils'
Expand Down Expand Up @@ -88,6 +88,14 @@ export async function notificationHandler(

if (process.env.NODE_ENV !== 'production') {
const { templateName, recipient, convertUnicode, type } = payload
if ('sms' in recipient) {
recipient.sms = maskSms(recipient.sms)
} else {
recipient.email = maskEmail(recipient.email)
recipient.bcc = Array.isArray(recipient.bcc)
? recipient.bcc.map(maskEmail)
: undefined
}
logger.info(
`Ignoring notification due to NODE_ENV not being 'production'. Params: ${JSON.stringify(
{
Expand All @@ -103,7 +111,9 @@ export async function notificationHandler(

if (isEmailPayload(applicationConfig, payload)) {
const { templateName, variables, recipient } = payload
logger.info(`Notification method is email and recipient ${recipient.email}`)
logger.info(
`Notification method is email and recipient ${maskEmail(recipient.email)}`
)

const template = getTemplate(templateName.email)
const emailSubject =
Expand Down Expand Up @@ -161,7 +171,7 @@ export async function emailHandler(
if (process.env.NODE_ENV !== 'production') {
logger.info(
`Ignoring email due to NODE_ENV not being 'production'. Params: ${JSON.stringify(
payload
{ ...payload, from: maskEmail(payload.from), to: maskEmail(payload.to) }
)}`
)
return h.response().code(200)
Expand Down
10 changes: 7 additions & 3 deletions src/api/notification/sms-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
INFOBIP_GATEWAY_ENDPOINT,
INFOBIP_SENDER_ID
} from './constant'
import { logger } from '@countryconfig/logger'
import { logger, maskSms } from '@countryconfig/logger'
import fetch from 'node-fetch'
import * as Handlebars from 'handlebars'
import { internal } from '@hapi/boom'
Expand Down Expand Up @@ -81,9 +81,13 @@ export async function sendSMS(

const responseBody = await response.text()
if (!response.ok) {
logger.error(`Failed to send sms to ${recipient}. Reason: ${responseBody}`)
logger.error(
`Failed to send sms to ${maskSms(recipient)}. Reason: ${responseBody}`
)
throw internal(
`Failed to send notification to ${recipient}. Reason: ${responseBody}`
`Failed to send notification to ${maskSms(
recipient
)}. Reason: ${responseBody}`
)
}
logger.info(`Response from Infobip: ${JSON.stringify(responseBody)}`)
Expand Down
26 changes: 25 additions & 1 deletion src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@
import pino from 'pino'
export const logger =
process.env.NODE_ENV === 'production'
? pino()
? pino({
redact: [
'req.headers.authorization',
'req.remoteAddress',
"req.headers['x-real-ip']"
]
})
: pino({
transport: {
target: 'pino-pretty',
Expand All @@ -25,3 +31,21 @@ export const logger =
if (process.env.NODE_ENV === 'test') {
logger.level = 'silent'
}

export function maskEmail(email: string) {
if (email.length <= 10)
return `${email.at(0)}${'*'.repeat(email.length - 2)}${email.at(-1)}`

// The regex matches everything EXCEPT the first 3 and last 4 characters.
return email.replace(/(?<=.{3}).*(?=.{4})/, (match) =>
'*'.repeat(match.length)
)
}

export function maskSms(sms: string) {
if (sms.length <= 8)
return `${sms.at(0)}${'*'.repeat(sms.length - 2)}${sms.at(-1)}`

// The regex matches everything EXCEPT the first 3 and last 2 characters.
return sms.replace(/(?<=.{3}).*(?=.{2})/, (match) => '*'.repeat(match.length))
}
24 changes: 5 additions & 19 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,25 @@
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@countryconfig/*": [
"./*"
]
"@countryconfig/*": ["./*"]
},
"target": "es6",
"module": "commonjs",
"outDir": "build/dist",
"sourceMap": true,
"moduleResolution": "node",
"rootDir": ".",
"lib": [
"esnext.asynciterable",
"es6",
"es2017",
"es2019"
],
"lib": ["esnext.asynciterable", "es6", "es2017", "es2019", "es2022"],
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"skipLibCheck": true,
"strictNullChecks": true,
"types": [
"fhir",
"geojson"
]
"types": ["fhir", "geojson"]
},
"include": [
"src/**/*.ts",
"infrastructure/environments/**/*.ts",
"typings"
],
"include": ["src/**/*.ts", "infrastructure/environments/**/*.ts", "typings"],
"exclude": [
"node_modules",
"cypress",
Expand All @@ -47,4 +33,4 @@
"ts-node": {
"files": true
}
}
}

0 comments on commit 081d9d1

Please sign in to comment.