Skip to content

Commit 3723dc1

Browse files
authored
Merge pull request #94 from mcode/email-cert-error
Support TLS Reject Unauthorized in config
2 parents 836b608 + a5b43f5 commit 3723dc1

File tree

4 files changed

+70
-2
lines changed

4 files changed

+70
-2
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ In order to send an email, users must specify the hostname or IP address of an S
111111
- `port`: (Optional) The port to connect to (defaults to 587)
112112
- `to`: Comma separated list or an array of recipients email addresses that will appear on the _To:_ field
113113
- `from`: (Optional) The email address of the sender. All email addresses can be plain `'sender@server.com'` or formatted `'"Sender Name" sender@server.com'` (defaults to mcode-extraction-errors@mitre.org, which cannot receive reply emails)
114+
- `tlsRejectUnauthorized`: (Optional) A boolean value to set the [node.js TLSSocket option](https://nodejs.org/api/tls.html#tls_class_tls_tlssocket) for rejecting any unauthorized connections, `tls.rejectUnauthorized`. (defaults to `true`)
114115

115116
An example of this object can be found in [`config/csv.config.example.json`](config/csv.config.example.json).
116117

@@ -126,6 +127,23 @@ Users can specify a different location for the file by using the `--run-log-file
126127
node src/cli/cli.js --run-log-filepath path/to/file.json
127128
```
128129

130+
### Masking Patient Data
131+
132+
Currently, patient data can be masked within the extracted `Patient` resource. When masked, the value of the field will be replaced with a [Data Absent Reason extension](https://www.hl7.org/fhir/extension-data-absent-reason.html) with the code `masked`.
133+
Patient properties that can be masked are: `gender`, `mrn`, `name`, `address`, `birthDate`, `language`, `ethnicity`, `birthsex`, and `race`.
134+
To mask a property, provide an array of the properties to mask in the `constructorArgs` of the Patient extractor. For example, the following configuration can be used to mask `address` and `birthDate`:
135+
136+
```bash
137+
{
138+
"label": "patient",
139+
"type": "CSVPatientExtractor",
140+
"constructorArgs": {
141+
"filePath": "./data/patient-information.csv"
142+
"mask": ["address", "birthDate"]
143+
}
144+
}
145+
```
146+
129147
### Extraction Date Range
130148

131149
The mCODE Extraction Client will extract all data that is provided in the CSV files by default, regardless of any dates associated with each row of data. It is recommended that any required date filtering is performed outside of the scope of this client.

config/csv.config.example.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"to": [
99
"demo@example.com",
1010
"test@example.com"
11-
]
11+
],
12+
"tlsRejectUnauthorized": true
1213
},
1314
"extractors": [
1415
{

src/cli/emailNotifications.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,15 @@ async function sendEmailNotification(notificationInfo, errors, debug = false) {
5757
emailBody += 'The stack trace information can be seen in the terminal as well as in the notification email.';
5858
}
5959

60+
// Ensure that the tlsRejectUnauthorized property is a boolean
61+
if (notificationInfo.tlsRejectUnauthorized && (notificationInfo.tlsRejectUnauthorized !== true || notificationInfo.tlsRejectUnauthorized !== false)) {
62+
logger.warn('The notificationInfo.tlsRejectUnauthorized should be a boolean value. The value provided will not be used.');
63+
}
64+
6065
const transporter = nodemailer.createTransport({
6166
host: notificationInfo.host,
6267
...(notificationInfo.port && { port: notificationInfo.port }),
68+
...((notificationInfo.tlsRejectUnauthorized === true || notificationInfo.tlsRejectUnauthorized === false) && { tls: { rejectUnauthorized: notificationInfo.tlsRejectUnauthorized } }),
6369
});
6470

6571
logger.debug('Sending email with error information');

test/cli/emailNotifications.test.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ describe('sendEmailNotification', () => {
7171
port: 123,
7272
to: ['something@example.com', 'someone@example.com'],
7373
from: 'other@example.com',
74+
tlsRejectUnauthorized: false,
7475
};
7576
const errors = {
7677
0: [],
@@ -79,7 +80,7 @@ describe('sendEmailNotification', () => {
7980
};
8081

8182
await expect(sendEmailNotification(notificationInfo, errors, false)).resolves.not.toThrow();
82-
expect(createTransportSpy).toBeCalledWith({ host: notificationInfo.host, port: notificationInfo.port });
83+
expect(createTransportSpy).toBeCalledWith({ host: notificationInfo.host, port: notificationInfo.port, tls: { rejectUnauthorized: notificationInfo.tlsRejectUnauthorized } });
8384
expect(sendMailMock).toBeCalled();
8485
const sendMailMockArgs = sendMailMock.mock.calls[0][0];
8586
expect(sendMailMockArgs.to).toEqual(notificationInfo.to);
@@ -93,6 +94,48 @@ describe('sendEmailNotification', () => {
9394
expect(sendMailMockArgs.text).not.toMatch(/Error at line 4`/i);
9495
});
9596

97+
it('should send an email with tlsRejectUnauthorized set to true, false, and not set', async () => {
98+
const notificationInfoTLSFalse = {
99+
host: 'my.host.com',
100+
to: ['something@example.com', 'someone@example.com'],
101+
tlsRejectUnauthorized: false,
102+
};
103+
const notificationInfoTLSTrue = {
104+
host: 'my.host.com',
105+
to: ['something@example.com', 'someone@example.com'],
106+
tlsRejectUnauthorized: true,
107+
};
108+
const notificationInfoNoTLS = {
109+
host: 'my.host.com',
110+
to: ['something@example.com', 'someone@example.com'],
111+
};
112+
const notificationInfoUnexpectedTLS = {
113+
host: 'my.host.com',
114+
to: ['something@example.com', 'someone@example.com'],
115+
tlsRejectUnauthorized: 'true', // Any value that is not true or false will log a warning and not be used
116+
};
117+
const errors = {
118+
0: [],
119+
1: [{ message: 'something bad', stack: 'Error at line 1' }],
120+
};
121+
createTransportSpy.mockReturnValueOnce({ sendMail: sendMailMock });
122+
await expect(sendEmailNotification(notificationInfoTLSFalse, errors, false)).resolves.not.toThrow();
123+
expect(createTransportSpy).toBeCalledWith({ host: notificationInfoTLSFalse.host, port: notificationInfoTLSFalse.port, tls: { rejectUnauthorized: false } });
124+
125+
createTransportSpy.mockReturnValueOnce({ sendMail: sendMailMock });
126+
await expect(sendEmailNotification(notificationInfoTLSTrue, errors, false)).resolves.not.toThrow();
127+
expect(createTransportSpy).toBeCalledWith({ host: notificationInfoTLSTrue.host, port: notificationInfoTLSTrue.port, tls: { rejectUnauthorized: true } });
128+
129+
createTransportSpy.mockReturnValueOnce({ sendMail: sendMailMock });
130+
await expect(sendEmailNotification(notificationInfoNoTLS, errors, false)).resolves.not.toThrow();
131+
expect(createTransportSpy).toBeCalledWith({ host: notificationInfoNoTLS.host, port: notificationInfoNoTLS.port }); // No tls object set
132+
133+
createTransportSpy.mockReturnValueOnce({ sendMail: sendMailMock });
134+
await expect(sendEmailNotification(notificationInfoUnexpectedTLS, errors, false)).resolves.not.toThrow();
135+
// A warning will be logged and the unexpected value will not be used
136+
expect(createTransportSpy).toBeCalledWith({ host: notificationInfoUnexpectedTLS.host, port: notificationInfoUnexpectedTLS.port });
137+
});
138+
96139
it('should send an email with stack traces if debug flag was used', async () => {
97140
createTransportSpy.mockReturnValueOnce({ sendMail: sendMailMock });
98141
const notificationInfo = {

0 commit comments

Comments
 (0)