minor updates master
authorJustin Wind <justin.wind+git@gmail.com>
Tue, 29 Mar 2022 18:39:07 +0000 (11:39 -0700)
committerJustin Wind <justin.wind+git@gmail.com>
Tue, 29 Mar 2022 18:39:07 +0000 (11:39 -0700)
server.js
src/logger.js [deleted file]
src/logger/data-sanitizers.js [new file with mode: 0644]
src/logger/index.js [new file with mode: 0644]
src/manager.js
src/service.js
src/template/root-html.js
static/index.html
static/muRL.png [new file with mode: 0644]
static/theme.css

index 404a7c59f2624a15948e5f43397f3d6c518947a1..17302b76bf1e2d5a6fe3dc9947c6c155443e4bcc 100644 (file)
--- a/server.js
+++ b/server.js
@@ -9,7 +9,7 @@ const Service = require('./src/service');
 const { fileScope } = require('./src/common');
 const { version } = require('./package.json');
 
-const _fileScope = fileScope(__filename)('main');
+const _scope = fileScope(__filename)('main');
 
 const PORT = process.env.PORT || 3001;
 const ADDR = process.env.LISTEN_ADDR || '127.0.0.1';
@@ -32,8 +32,8 @@ http.createServer((req, res) => {
   service.dispatch(req, res);
 }).listen(PORT, ADDR, (err) => {
   if (err) {
-    logger.error(_fileScope, 'error starting server:', err);
+    logger.error(_scope, 'error starting server:', err);
     throw err;
   }
-  logger.info(_fileScope, `server (version ${version}) started on ${ADDR}:${PORT}`);
+  logger.info(_scope, 'server started', { version, listenAddress: ADDR, listenPort: PORT });
 });
diff --git a/src/logger.js b/src/logger.js
deleted file mode 100644 (file)
index 7c8e3cb..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-'use strict';
-
-/**
- * Log as JSON to stdout/stderr.
- */
-
-const common = require('./common');
-
-// This is uncomfortable, but is the simplest way to let logging work for BigInts.
-// TODO: revisit with better solution
-BigInt.prototype.toJSON = function() {
-  return this.toString();
-}
-
-// Also uncomfortable
-Object.defineProperty(Error.prototype, 'toJSON', {
-  configurable: true,
-  value: function () {
-    const result = {};
-    const dupKey = function (key) {
-      // eslint-disable-next-line security/detect-object-injection
-      result[key] = this[key];
-    };
-    Object.getOwnPropertyNames(this).forEach(dupKey, this);
-    return result;
-  },
-});
-
-const defaultOptions = {
-  ignoreBelowLevel: 'debug',
-  backend: console,
-};
-
-class Logger {
-  constructor(options = {}) {
-    common.setOptions(this, defaultOptions, options);
-
-    this.logLevels = [
-      'error',
-      'warn',
-      'info',
-      'log',
-      'debug',
-    ];
-  
-    const ignoreLevelIdx = this.logLevels.indexOf(this.ignoreBelowLevel);
-    this.logLevels.forEach((level) => {
-      // eslint-disable-next-line security/detect-object-injection
-      this[level] = (this.logLevels.indexOf(level) > ignoreLevelIdx) ?
-        () => {} :
-        Logger.levelTemplateFn(this.backend, level);
-    });
-  }
-  
-  static levelTemplateFn(backend, level) {
-    return function (...args) {
-      // eslint-disable-next-line security/detect-object-injection
-      backend[level](Logger.payload(level, ...args));
-    };
-  }
-
-  static payload(level, scope, message, data, ...other) {
-    return JSON.stringify({
-      timestamp: Date.now(),
-      level: level,
-      scope: scope || '[unknown]',
-      message: message || '',
-      data: data || {},
-      ...(other.length && { other }),
-    });
-  }
-}
-
-module.exports = Logger;
diff --git a/src/logger/data-sanitizers.js b/src/logger/data-sanitizers.js
new file mode 100644 (file)
index 0000000..a6b444b
--- /dev/null
@@ -0,0 +1,25 @@
+'use strict';
+
+/**
+ * Scrub credential from POST login body data.
+ * @param {Object} data
+ * @param {Boolean} sanitize
+ * @returns {Boolean}
+ */
+function sanitizePostCredential(data, sanitize = true) {
+  let unclean = false;
+
+  const credentialLength = data && data.ctx && data.ctx.parsedBody && data.ctx.parsedBody.credential && data.ctx.parsedBody.credential.length;
+  if (credentialLength) {
+    unclean = true;
+  }
+  if (unclean && sanitize) {
+    data.ctx.parsedBody.credential = '*'.repeat(credentialLength);
+  }
+
+  return unclean;
+}
+
+module.exports = {
+  sanitizePostCredential,
+};
\ No newline at end of file
diff --git a/src/logger/index.js b/src/logger/index.js
new file mode 100644 (file)
index 0000000..7944cf6
--- /dev/null
@@ -0,0 +1,13 @@
+'use strict';
+
+const BaseLogger = require('@squeep/logger-json-console');
+const dataSanitizers = require('./data-sanitizers');
+
+class Logger extends BaseLogger {
+  constructor(options, ...args) {
+    super(options, ...args);
+    Array.prototype.push.apply(this.dataSanitizers, Object.values(dataSanitizers));
+  }
+}
+
+module.exports = Logger;
\ No newline at end of file
index a5035cd55d592d8f3f74d12af248f2cf12c75bf2..a46db552919a4286e0f7dd7f12634902a008f8a7 100644 (file)
@@ -11,6 +11,7 @@ const _fileScope = common.fileScope(__filename);
 
 const defaultOptions = {
   pageTitle: require('../package.json').name,
+  logoUrl: '/static/muRL.png',
   selfBaseUrl: '',
   staticDirectory: '/static/',
 };
@@ -44,7 +45,7 @@ class Manager {
 
       case Enum.ContentType.TextHTML:
       default:
-        return Template.rootHTML(ctx, this.pageTitle);
+        return Template.rootHTML(ctx, this.pageTitle, this.logoUrl);
     }
   }
 
index 1b09d2daf104a22426dc2fbd10f422d1f4f3094f..97ed85e6e9e678fbae45cd0512135eb749930f9c 100644 (file)
@@ -68,13 +68,13 @@ class Service extends Dingus {
    * @param {string} contentType 
    * @param {object} ctx 
    */
-  parseBody(contentType, ctx) {
+  parseBody(contentType, ctx, rawBody) {
     // eslint-disable-next-line sonarjs/no-small-switch
     switch (contentType) {
       // Handle any additional content types here
 
       default:
-        super.parseBody(contentType, ctx);
+        super.parseBody(contentType, ctx, rawBody);
     }
   }
 
@@ -107,10 +107,12 @@ class Service extends Dingus {
    */
   async handlerPostRoot(req, res, ctx) {
     const _scope = _fileScope('handlerPostRoot');
-    this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx });
+    this.logger.debug(_scope, 'called', { req, ctx });
 
     this.setResponseType(this.responseTypes, req, res, ctx);
-    await this.ingestBody(req, res, ctx);
+    await this.ingestBody(req, res, ctx, {
+      maximumBodySize: 1024 * 8,
+    });
     await this._postRootAuth(req, res, ctx);
 
     await this.manager.postRoot(res, ctx);
@@ -127,7 +129,7 @@ class Service extends Dingus {
     const responseTypes = [
       Enum.ContentType.TextHTML,
     ];
-    this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx });
+    this.logger.debug(_scope, 'called', { req, ctx });
 
     Dingus.setHeadHandler(req, res, ctx);
 
@@ -146,7 +148,7 @@ class Service extends Dingus {
    */
   async handlerGetId(req, res, ctx) {
     const _scope = _fileScope('handlerGetId');
-    this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx });
+    this.logger.debug(_scope, 'called', { req, ctx });
   
     Dingus.setHeadHandler(req, res, ctx);
 
@@ -172,7 +174,7 @@ class Service extends Dingus {
    */
   async handlerDeleteId(req, res, ctx) {
     const _scope = _fileScope('handlerDeleteId');
-    this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx });
+    this.logger.debug(_scope, 'called', { req, ctx });
   
     this.setResponseType(this.responseTypes, req, res, ctx);
     await this.authenticator.required(req, res, ctx);
@@ -188,7 +190,7 @@ class Service extends Dingus {
    */
   async handlerPutId(req, res, ctx) {
     const _scope = _fileScope('handlerPutId');
-    this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx });
+    this.logger.debug(_scope, 'called', { req, ctx });
 
     this.setResponseType(this.responseTypes, req, res, ctx);
     await this.ingestBody(req, res, ctx);
@@ -205,7 +207,7 @@ class Service extends Dingus {
    */
   async handlerGetIdInfo(req, res, ctx) {
     const _scope = _fileScope('handlerGetIdInfo');
-    this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx });
+    this.logger.debug(_scope, 'called', { req, ctx });
   
     Dingus.setHeadHandler(req, res, ctx);
 
@@ -223,7 +225,7 @@ class Service extends Dingus {
    */
   async handlerGetStatic(req, res, ctx) {
     const _scope = _fileScope('handlerGetStatic');
-    this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx });
+    this.logger.debug(_scope, 'called', { req, ctx });
 
     Dingus.setHeadHandler(req, res, ctx);
 
@@ -242,7 +244,7 @@ class Service extends Dingus {
    */
   async handlerGetAdminReport(req, res, ctx) {
     const _scope = _fileScope('handlerAdminReport');
-    this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx });
+    this.logger.debug(_scope, 'called', { req, ctx });
   
     Dingus.setHeadHandler(req, res, ctx);
 
index 65e34c73017c7500764d8339250c59823ef2966f..c7550c5e37251cdcc072acd5680c95da6d104946 100644 (file)
@@ -1,6 +1,7 @@
 'use strict';
 
-module.exports = (ctx, pageTitle) => {
+module.exports = (ctx, pageTitle, logoUrl) => {
+  const logoImg = logoUrl ? `<img src="${logoUrl}" class="logo">` : '';
   return `<!DOCTYPE html>
 <html lang="en">
   <head>
@@ -10,21 +11,26 @@ module.exports = (ctx, pageTitle) => {
     <link rel="stylesheet" href="static/theme.css">
   </head>
   <body>
-  <script type="text/javascript">
+  <script type="text/javascript">` + (!ctx.createdLink ? '0;' : `
     document.addEventListener('DOMContentLoaded', function () {
-      document.querySelector('.copy-button').addEventListener('click', function(event) {
+      let timeout;
+      document.querySelector('.copy-button').addEventListener('click', function (event) {
         const linkHref = document.querySelector('.link').href;
         navigator.clipboard.writeText(linkHref);
         const copyButton = this;
         copyButton.style.backgroundColor = 'lightgreen';
-        setTimeout(function () {
+        if (timeout) {
+          clearTimeout(timeout);
+        }
+        timeout = setTimeout(function () {
           copyButton.style.backgroundColor = 'initial';
+          timeout = undefined;
         }, 3000);
       });
-    });
-  </script>
+    });`) + `
+    </script>
     <header>
-      <h1>${pageTitle}</h1>
+      <h1>${logoImg}${pageTitle}</h1>
     </header>` +
     (!ctx.createdLink ? '' : `
     <section class="created-link">
index f1c14e1709ca56ccbdf27c63fa17438234e56993..9437f204aa7fdbda743d28fa7351b4d0817aa81c 100644 (file)
@@ -3,7 +3,7 @@
 <head>
        <meta charset="utf-8">
        <title>Static Assets</title>
-       <link rel="stylesheet" href="static/theme.css">
+       <link rel="stylesheet" href="theme.css">
 </head>
 <body>
        <header>
diff --git a/static/muRL.png b/static/muRL.png
new file mode 100644 (file)
index 0000000..49752f1
Binary files /dev/null and b/static/muRL.png differ
index a0de35db782027aa456d01e239fa8e82795f5bbb..f880e72cd3e5a7ff812c09ae77b67e764007826d 100644 (file)
@@ -7,6 +7,10 @@ body {
 header {
        background: linear-gradient(0deg, rgba(255,255,255,0) 0%, rgb(160, 82, 45) 100%);
 }
+.logo {
+       vertical-align: bottom;
+       height: 2em;
+}
 h1 {
        margin: 0;
        padding: 2em 1em .5em 1em;