ramirez/src/modules/webserver.js

136 lines
4.5 KiB
JavaScript
Raw Normal View History

const http = require('http');
const mime = require('mime');
const url = require('url');
const fs = require('fs');
2020-05-24 18:54:26 -04:00
const qs = require('querystring');
const moment = require('moment');
const config = require('../config');
const threads = require('../data/threads');
const attachments = require('../data/attachments');
const {THREAD_MESSAGE_TYPE} = require('../data/constants');
function notfound(res) {
res.statusCode = 404;
res.end('Page Not Found');
}
2020-05-24 18:54:26 -04:00
async function serveLogs(req, res, pathParts, query) {
const threadId = pathParts[pathParts.length - 1];
if (threadId.match(/^[0-9a-f\-]+$/) === null) return notfound(res);
const thread = await threads.findById(threadId);
if (! thread) return notfound(res);
2020-05-24 18:54:26 -04:00
let threadMessages = await thread.getThreadMessages();
if (query.simple) {
threadMessages = threadMessages.filter(message => {
return (
message.message_type !== THREAD_MESSAGE_TYPE.SYSTEM
&& message.message_type !== THREAD_MESSAGE_TYPE.SYSTEM_TO_USER
&& message.message_type !== THREAD_MESSAGE_TYPE.CHAT
&& message.message_type !== THREAD_MESSAGE_TYPE.COMMAND
);
});
}
const lines = threadMessages.map(message => {
// Legacy messages are the entire log in one message, so just serve them as they are
if (message.message_type === THREAD_MESSAGE_TYPE.LEGACY) {
return message.body;
}
2020-05-24 18:54:26 -04:00
let line = `[${moment.utc(message.created_at).format('YYYY-MM-DD HH:mm:ss')}]`;
if (query.verbose) {
if (message.dm_channel_id) {
line += ` [DM CHA ${message.dm_channel_id}]`;
}
if (message.dm_message_id) {
line += ` [DM MSG ${message.dm_message_id}]`;
}
}
if (message.message_type === THREAD_MESSAGE_TYPE.FROM_USER) {
2020-05-24 18:54:26 -04:00
line += ` [FROM USER] [${message.user_name}] ${message.body}`;
} else if (message.message_type === THREAD_MESSAGE_TYPE.TO_USER) {
2020-05-24 18:54:26 -04:00
line += ` [TO USER] [${message.user_name}] ${message.body}`;
} else if (message.message_type === THREAD_MESSAGE_TYPE.SYSTEM) {
2020-05-24 18:54:26 -04:00
line += ` [SYSTEM] ${message.body}`;
} else if (message.message_type === THREAD_MESSAGE_TYPE.SYSTEM_TO_USER) {
2020-05-24 18:54:26 -04:00
line += ` [SYSTEM TO USER] ${message.body}`;
} else if (message.message_type === THREAD_MESSAGE_TYPE.CHAT) {
2020-05-24 18:54:26 -04:00
line += ` [CHAT] [${message.user_name}] ${message.body}`;
} else if (message.message_type === THREAD_MESSAGE_TYPE.COMMAND) {
2020-05-24 18:54:26 -04:00
line += ` [COMMAND] [${message.user_name}] ${message.body}`;
} else {
2020-05-24 18:54:26 -04:00
line += ` [${message.user_name}] ${message.body}`;
}
return line;
});
2020-05-24 18:54:26 -04:00
const openedAt = moment(thread.created_at).format('YYYY-MM-DD HH:mm:ss');
let header = `# ModMail thread with ${thread.user_name} (${thread.user_id}) started at ${openedAt}.`;
header += `\n# All times are in UTC+0.`;
if (! query.simple) {
header += `\n# Add ?simple=1 to the end of the log link to view only messages from the user and replies.`;
}
if (! query.verbose) {
header += `\n# Add ?verbose=1 to the end of the log link to view message IDs.`;
}
const fullResponse = header + '\n\n' + lines.join('\n');
res.setHeader('Content-Type', 'text/plain; charset=UTF-8');
2020-05-24 18:54:26 -04:00
res.end(fullResponse);
}
2020-05-24 18:54:26 -04:00
function serveAttachments(req, res, pathParts) {
const desiredFilename = pathParts[pathParts.length - 1];
const id = pathParts[pathParts.length - 2];
if (id.match(/^[0-9]+$/) === null) return notfound(res);
if (desiredFilename.match(/^[0-9a-z._-]+$/i) === null) return notfound(res);
2019-03-06 16:31:24 -05:00
const attachmentPath = attachments.getLocalAttachmentPath(id);
fs.access(attachmentPath, (err) => {
if (err) return notfound(res);
const filenameParts = desiredFilename.split('.');
const ext = (filenameParts.length > 1 ? filenameParts[filenameParts.length - 1] : 'bin');
2018-08-07 18:10:38 -04:00
const fileMime = mime.getType(ext);
res.setHeader('Content-Type', fileMime);
const read = fs.createReadStream(attachmentPath);
read.pipe(res);
})
}
module.exports = () => {
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(`http://${req.url}`);
2020-05-24 18:54:26 -04:00
const pathParts = parsedUrl.pathname.split('/').filter(v => v !== '');
const query = qs.parse(parsedUrl.query);
2020-05-24 18:54:26 -04:00
if (parsedUrl.pathname.startsWith('/logs/')) {
serveLogs(req, res, pathParts, query);
} else if (parsedUrl.pathname.startsWith('/attachments/')) {
serveAttachments(req, res, pathParts, query);
} else {
notfound(res);
}
});
2018-08-07 17:54:01 -04:00
server.on('error', err => {
console.log('[WARN] Web server error:', err.message);
});
server.listen(config.port);
};