2021-06-15 15:47:18 +08:00
|
|
|
'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);
|
|
|
|
|
2023-01-09 17:57:15 +08:00
|
|
|
// res.pipe does not work if Gzip is enabled
|
2023-01-19 16:46:12 +08:00
|
|
|
//server.use(restify.plugins.gzipResponse());
|
2021-06-15 15:47:18 +08:00
|
|
|
|
|
|
|
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 => {
|
2022-02-03 00:35:30 +08:00
|
|
|
if (!config.acme || !config.acme.agent || !config.acme.agent.enabled) {
|
2021-06-15 15:47:18 +08:00
|
|
|
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);
|
|
|
|
});
|
|
|
|
};
|