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';
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 });
});
+++ /dev/null
-'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;
--- /dev/null
+'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
--- /dev/null
+'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
const defaultOptions = {
pageTitle: require('../package.json').name,
+ logoUrl: '/static/muRL.png',
selfBaseUrl: '',
staticDirectory: '/static/',
};
case Enum.ContentType.TextHTML:
default:
- return Template.rootHTML(ctx, this.pageTitle);
+ return Template.rootHTML(ctx, this.pageTitle, this.logoUrl);
}
}
* @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);
}
}
*/
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);
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);
*/
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);
*/
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);
*/
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);
*/
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);
*/
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);
*/
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);
'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>
<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">
<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>
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;