From f09a48a504757b8b512f7d15c938c13f63b5a637 Mon Sep 17 00:00:00 2001
From: Justin Wind <justin.wind+git@gmail.com>
Date: Thu, 4 Nov 2021 17:51:20 -0700
Subject: [PATCH] keep sensitive credentials out of logs

---
 src/logger.js      |  8 ++++++++
 src/service.js     |  4 +++-
 test/src/logger.js | 13 +++++++++++++
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/src/logger.js b/src/logger.js
index 934c7da..00edfb8 100644
--- a/src/logger.js
+++ b/src/logger.js
@@ -66,6 +66,14 @@ class Logger {
   }
 
   payload(level, scope, message, data, ...other) {
+    // Try to keep credentials out of logs.
+    // This approach feels sort of jank, but it's better than nothing, for now.
+    if (data && data.ctx && data.ctx.parsedBody && data.ctx.parsedBody.credential) {
+      // Create copy of data
+      data = JSON.parse(JSON.stringify(data));
+      data.ctx.parsedBody.credential = '*'.repeat(data.ctx.parsedBody.credential.length);
+    }
+
     const now = new Date();
     return JSON.stringify({
       nodeId: this.nodeId,
diff --git a/src/service.js b/src/service.js
index 1d9b8a0..a0043f7 100644
--- a/src/service.js
+++ b/src/service.js
@@ -181,8 +181,9 @@ class Service extends Dingus {
 
 
   /**
-   * Same as super.ingestBody, but if no body was sent, do not parse (and
+   * Similar to super.ingestBody, but if no body was sent, do not parse (and
    * thus avoid possible unsupported media type error).
+   * Also removes raw body from context, to simplify scrubbing sensitive data from logs.
    * @param {http.ClientRequest} req
    * @param {http.ServerResponse} res
    * @param {Object} ctx
@@ -192,6 +193,7 @@ class Service extends Dingus {
     const contentType = Dingus.getRequestContentType(req);
     if (ctx.rawBody) {
       this.parseBody(contentType, ctx);
+      delete ctx.rawBody;
     }
   }
 
diff --git a/test/src/logger.js b/test/src/logger.js
index 2a20504..fc602aa 100644
--- a/test/src/logger.js
+++ b/test/src/logger.js
@@ -48,4 +48,17 @@ describe('Logger', function () {
     logger = new Logger(config);
     logger.info();
   });
+
+  it('masks credentials', function () {
+    logger = new Logger(config);
+    logger.info('testScope', 'message', {
+      ctx: {
+        parsedBody: {
+          identity: 'username',
+          credential: 'password',
+        },
+      },
+    });
+  });
+
 }); // Logger
-- 
2.49.0