'use strict'; const config = require('wild-config'); const restify = require('restify'); const log = require('npmlog'); const logger = require('restify-logger'); const db = require('./lib/db'); const Gelf = require('gelf'); const os = require('os'); const acmeRoutes = require('./lib/api/acme'); let loggelf; const serverOptions = { name: 'WildDuck ACME Agent', strictRouting: true, maxParamLength: 196 }; const server = restify.createServer(serverOptions); server.use(restify.plugins.gzipResponse()); server.use( restify.plugins.queryParser({ allowDots: true, mapParams: true }) ); logger.token('user-ip', req => ((req.params && req.params.ip) || '').toString().substr(0, 40) || '-'); logger.token('user-sess', req => (req.params && req.params.sess) || '-'); logger.token('user', req => (req.user && req.user.toString()) || '-'); logger.token('url', req => { if (/\baccessToken=/.test(req.url)) { return req.url.replace(/\baccessToken=[^&]+/g, 'accessToken=' + 'x'.repeat(6)); } return req.url; }); server.use( logger(':remote-addr :user [:user-ip/:user-sess] :method :url :status :time-spent :append', { stream: { write: message => { message = (message || '').toString(); if (message) { log.http('ACME', message.replace('\n', '').trim()); } } } }) ); module.exports = done => { if (!config.acme.agent.enabled) { return setImmediate(() => done(null, false)); } let started = false; const component = config.log.gelf.component || 'wildduck'; const hostname = config.log.gelf.hostname || os.hostname(); const gelf = config.log.gelf && config.log.gelf.enabled ? new Gelf(config.log.gelf.options) : { // placeholder emit: (key, message) => log.info('Gelf', JSON.stringify(message)) }; loggelf = message => { if (typeof message === 'string') { message = { short_message: message }; } message = message || {}; if (!message.short_message || message.short_message.indexOf(component.toUpperCase()) !== 0) { message.short_message = component.toUpperCase() + ' ' + (message.short_message || ''); } message.facility = component; // facility is deprecated but set by the driver if not provided message.host = hostname; message.timestamp = Date.now() / 1000; message._component = component; Object.keys(message).forEach(key => { if (!message[key]) { delete message[key]; } }); gelf.emit('gelf.log', message); }; server.loggelf = message => loggelf(message); acmeRoutes(db, server); server.on('error', err => { if (!started) { started = true; return done(err); } log.error('ACME', err); }); server.listen(config.acme.agent.port, config.acme.agent.host, () => { if (started) { return server.close(); } started = true; log.info('ACME', 'Server listening on %s:%s', config.acme.agent.host || '0.0.0.0', config.acme.agent.port); done(null, server); }); };