clean up some lint issues
[squeep-api-dingus] / lib / common.js
index ff68e9d7ac7b5ea5258ce1aab70cb99f991d037f..e2e2a8c640f58ba4df827cd6e7afcc5ffb69fd4b 100644 (file)
@@ -11,8 +11,15 @@ const uuid = require('uuid');
 const Enum = require('./enum');
 
 /**
- * Return a function which combines a part of the filename with a scope, for use in logging.
- * @param {string} filename
+ * @callback ScopeFn
+ * @param {String} scope
+ * @returns {String}
+ */
+/**
+ * Return a function which prefixes a provided scope with the most-
+ * relevant part of the filename, for use in logging.
+ * @param {String} filename
+ * @returns {ScopeFn}
  */
 const fileScope = (filename) => {
   let fScope = path.basename(filename, '.js');
@@ -20,13 +27,14 @@ const fileScope = (filename) => {
     fScope = path.basename(path.dirname(filename));
   }
   return (scope) => `${fScope}:${scope}`;
-}
+};
 
 /**
  * Simple ETag from data.
- * @param {string} filePath 
- * @param {object} fileStat 
- * @param {*} fileData 
+ * @param {String} filePath (currently unused)
+ * @param {fs.Stats} fileStat
+ * @param {crypto.BinaryLike} fileData content
+ * @returns {String}
  */
 const generateETag = (_filePath, fileStat, fileData) => {
   const hash = crypto.createHash('sha256');
@@ -39,16 +47,19 @@ const generateETag = (_filePath, fileStat, fileData) => {
 };
 
 /**
- * @param {object} obj 
- * @param {string} prop 
- * @param {*} def 
+ * Access property with default.
+ * @param {Object} obj
+ * @param {String} prop
+ * @param {*} def default value if prop does not exist for obj
+ * @return {*}
  */
 const get = (obj, prop, def) => obj && prop && (prop in obj) ? obj[prop] : def;
 
 /**
  * @param {http.ClientRequest} req 
  * @param {http.ServerResponse} res 
- * @param {object} ctx 
+ * @param {Object} ctx 
+ * @deprecated after v1.2.5 (integrated into logger module)
  */
 const handlerLogData = (req, res, ctx) => ({
   req: requestLogData(req),
@@ -57,10 +68,12 @@ const handlerLogData = (req, res, ctx) => ({
 });
 
 /**
- * 
+ * Determine whether a client has already requested a resource,
+ * based on If-Modified-Since and If-None-Match headers.
  * @param {http.ClientRequest} req 
  * @param {Number} modifiedTimeMs 
- * @param {string} eTag 
+ * @param {String} eTag 
+ * @returns {Boolean}
  */
 const isClientCached = (req, modifiedTimeMs, eTag) => {
   let clientCached = false;
@@ -93,6 +106,7 @@ const isClientCached = (req, modifiedTimeMs, eTag) => {
  * Expects only one-level deep, is not recursive!
  * @param {Object} origEnum
  * @param {Object} additionalEnum
+ * @returns {Object}
  */
 const mergeEnum = (origEnum, additionalEnum) => {
   for (const e of Object.keys(additionalEnum)) {
@@ -118,9 +132,9 @@ const httpStatusCodeClass = (statusCode) => Math.floor(statusCode / 100);
 const _isObject = (obj) => obj && typeof obj === 'object';
 const _isArray = (obj) => Array.isArray(obj);
 /**
- * Return a new object with all objects combined.
- * @param  {...any} objects
- * @returns
+ * Return a new object with all objects combined, later properties taking precedence.
+ * @param  {...Object} objects
+ * @returns {Object}
  */
 const mergeDeep = (...objects) => {
   return objects.reduce((acc, obj) => {
@@ -144,7 +158,8 @@ const mergeDeep = (...objects) => {
 /**
  * Return a new object with selected props.
  * @param {Object} obj
- * @param {string[]} props
+ * @param {String[]} props
+ * @returns {Object}
  */
 const pick = (obj, props) => {
   const picked = {};
@@ -158,22 +173,58 @@ const pick = (obj, props) => {
 
 /**
  * Return a subset of a request object, suitable for logging.
+ * Obscures sensitive header values.
  * @param {http.ClientRequest} req 
+ * @deprecated after v1.2.5 (integrated into logger module)
  */
 const requestLogData = (req) => {
-  return pick(req, [
+  const data = pick(req, [
     'method',
     'url',
     'httpVersion',
     'headers',
     'trailers',
   ]);
+  scrubHeaderObject(data);
+  return data;
+};
+
+
+/**
+ * Remove sensitive header data.
+ * @param {Object} data
+ * @param {Object} data.headers
+ * @deprecated after v1.2.5 (integrated into logger module)
+ */
+const scrubHeaderObject = (data) => {
+  if (data && data.headers && 'authorization' in data.headers) {
+    data.headers = Object.assign({}, data.headers, {
+      authorization: obscureAuthorizationHeader(data.headers['authorization']),
+    });
+  }
+};
+
+
+/**
+ * Hide sensitive part of an Authorization header.
+ * @param {String} authHeader
+ * @returns {String}
+ * @deprecated after v1.2.5 (integrated into logger module)
+ */
+const obscureAuthorizationHeader = (authHeader) => {
+  if (!authHeader) {
+    return authHeader;
+  }
+  const space = authHeader.indexOf(' ');
+  // This blurs entire string if no space found, because -1.
+  return authHeader.slice(0, space + 1) + '*'.repeat(authHeader.length - (space + 1));
 };
 
 
 /**
  * Return a subset of a response object, suitable for logging.
  * @param {http.ServerResponse} res 
+ * @deprecated after v1.2.5 (integrated into logger module)
  */
 const responseLogData = (res) => {
   const response = pick(res, [
@@ -186,7 +237,7 @@ const responseLogData = (res) => {
 
 
 /**
- * Store updates to defaultOptions, but no new properties.
+ * Store all properties in defaultOptions on target from either options or defaultOptions.
  * @param {Object} target 
  * @param {Object} defaultOptions 
  * @param {Object} options 
@@ -196,10 +247,10 @@ const setOptions = (target, defaultOptions, options) => {
 };
 
 /**
- * Return a list of source split at first delimiter.
- * @param {string} src 
- * @param {string} delimiter 
- * @param {string} fill trailing stand-in if no delimiter in src
+ * Return a two-item list of src, split at first delimiter encountered.
+ * @param {String} src 
+ * @param {String} delimiter 
+ * @param {String} fill trailing stand-in if no delimiter in src
  */
 const splitFirst = (src, delimiter, fill) => {
   const idx = src.indexOf(delimiter);
@@ -211,14 +262,21 @@ const splitFirst = (src, delimiter, fill) => {
 };
 
 /**
- * Generate a new request identifier.
+ * Generate a new request identifier, a time/host-based uuid.
  * @returns {String}
  */
 const requestId = () => {
   return uuid.v1();
 };
 
+/**
+ * Do nothing.
+ */
 const nop = () => { /**/ };
+
+/**
+ * A logger object which does nothing.
+ */
 const nullLogger = {
   error: nop,
   warn: nop,
@@ -228,8 +286,9 @@ const nullLogger = {
 };
 
 /**
- * Populates any absent logger levels.
+ * Populates any absent logger level functions on a logger object.
  * @param {Object} logger
+ * @returns {Object}
  */
 const ensureLoggerLevels = (logger = {}) => {
   for (const level in nullLogger) {
@@ -243,6 +302,7 @@ const ensureLoggerLevels = (logger = {}) => {
 /**
  * Merges folded header lines
  * @param {String[]} lines
+ * @returns {String}
  */
 const unfoldHeaderLines = (lines) => {
   const foldedLineRE = /^(\t| +)(.*)$/;
@@ -272,10 +332,12 @@ module.exports = {
   mergeEnum,
   nop,
   nullLogger,
+  obscureAuthorizationHeader,
   pick,
   requestId,
   requestLogData,
   responseLogData,
+  scrubHeaderObject,
   setOptions,
   splitFirst,
   unfoldHeaderLines,