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');
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');
- if (fileStat && fileStat.mtimeMs) {
+ if (fileStat?.mtimeMs) {
hash.update(fileStat.mtimeMs.toString());
}
hash.update(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),
});
/**
- *
+ * 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;
* 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)) {
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) => {
/**
* Return a new object with selected props.
* @param {Object} obj
- * @param {string[]} props
+ * @param {String[]} props
+ * @returns {Object}
*/
const pick = (obj, props) => {
const picked = {};
/**
* 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?.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, [
/**
- * 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
};
/**
- * 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);
};
/**
- * 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,
};
/**
- * Populates any absent logger levels.
+ * Populates any absent logger level functions on a logger object.
* @param {Object} logger
+ * @returns {Object}
+ * @deprecated after v1.2.9 (this is not our responsibility)
*/
const ensureLoggerLevels = (logger = {}) => {
for (const level in nullLogger) {
/**
* Merges folded header lines
* @param {String[]} lines
+ * @returns {String}
*/
const unfoldHeaderLines = (lines) => {
const foldedLineRE = /^(\t| +)(.*)$/;
if (lines) {
- lines.reduceRight((_, line, idx) => {
+ lines.reduceRight((_, line, idx) => { // NOSONAR
const result = foldedLineRE.exec(line);
if (result && idx) {
const prevIdx = idx - 1;
mergeEnum,
nop,
nullLogger,
+ obscureAuthorizationHeader,
pick,
requestId,
requestLogData,
responseLogData,
+ scrubHeaderObject,
setOptions,
splitFirst,
unfoldHeaderLines,