bump package version to 1.5.0
[squeep-authentication-module] / lib / common.js
index c0aaf3799c7f3d2609ae2ce7ee8c6cec3482facb..5563254f0bab35b7b54322dd46ad0cfa9c49e3c4 100644 (file)
@@ -1,25 +1,73 @@
 'use strict';
 
 const { common } = require('@squeep/api-dingus');
+const { randomBytes } = require('node:crypto');
+const { promisify } = require('node:util');
 
+const randomBytesAsync = promisify(randomBytes);
 
 /**
  * Recursively freeze an object.
- * @param {Object} o
- * @returns {Object}
+ * @param {object} o object to freeze
+ * @returns {object} frozen object
  */
 const freezeDeep = (o) => {
   Object.freeze(o);
   Object.getOwnPropertyNames(o).forEach((prop) => {
-    if (Object.hasOwnProperty.call(o, prop)
+    if (Object.hasOwn(o, prop)
     &&  ['object', 'function'].includes(typeof o[prop]) // eslint-disable-line security/detect-object-injection
     &&  !Object.isFrozen(o[prop])) { // eslint-disable-line security/detect-object-injection
       return freezeDeep(o[prop]); // eslint-disable-line security/detect-object-injection
     }
   });
   return o;
-}
+};
+
+/**
+ * Return a new object duplicating `o`, without the properties specified.
+ * @param {object} o source object
+ * @param {string[]} props list of property names to omit
+ * @returns {object} pruned object
+ */
+const omit = (o, props) => {
+  return Object.fromEntries(Object.entries(o).filter(([k]) => !props.includes(k)));
+};
+
+/**
+ * Helper to log mystery-box statistics.
+ * @param {object} logger logger
+ * @param {Function} logger.debug log debug
+ * @param {string} scope scope
+ * @returns {Function} stats log decorator
+ */
+const mysteryBoxLogger = (logger, scope) => {
+  return (s) => {
+    logger.debug(scope, `${s.packageName}@${s.packageVersion}:${s.method}`, omit(s, [
+      'packageName',
+      'packageVersion',
+      'method',
+    ]));
+  };
+};
+
+/**
+ * Hide sensitive part of an Authorization header.
+ * @param {string} authHeader header value
+ * @returns {string} scrubbed header value
+ */
+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));
+};
 
 module.exports = Object.assign(Object.create(common), {
   freezeDeep,
-});
\ No newline at end of file
+  mysteryBoxLogger,
+  obscureAuthorizationHeader,
+  omit,
+  randomBytesAsync,
+});