2020-08-12 17:08:37 -04:00
|
|
|
const http = require("http");
|
|
|
|
const mime = require("mime");
|
|
|
|
const url = require("url");
|
|
|
|
const fs = require("fs");
|
|
|
|
const qs = require("querystring");
|
|
|
|
const moment = require("moment");
|
|
|
|
const config = require("../cfg");
|
|
|
|
const threads = require("../data/threads");
|
|
|
|
const attachments = require("../data/attachments");
|
|
|
|
|
|
|
|
const {THREAD_MESSAGE_TYPE} = require("../data/constants");
|
2018-02-11 14:54:30 -05:00
|
|
|
|
|
|
|
function notfound(res) {
|
|
|
|
res.statusCode = 404;
|
2020-08-12 17:08:37 -04:00
|
|
|
res.end("Page Not Found");
|
2018-02-11 14:54:30 -05:00
|
|
|
}
|
|
|
|
|
2020-05-24 18:54:26 -04:00
|
|
|
async function serveLogs(req, res, pathParts, query) {
|
2018-02-11 14:54:30 -05:00
|
|
|
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
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-11 14:54:30 -05:00
|
|
|
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-08-12 17:08:37 -04:00
|
|
|
let line = `[${moment.utc(message.created_at).format("YYYY-MM-DD HH:mm:ss")}]`;
|
2020-05-24 18:54:26 -04:00
|
|
|
|
|
|
|
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}]`;
|
|
|
|
}
|
|
|
|
}
|
2018-02-11 14:54:30 -05:00
|
|
|
|
2020-05-24 18:33:10 -04:00
|
|
|
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}`;
|
2018-02-11 14:54:30 -05:00
|
|
|
} 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}`;
|
2020-05-24 18:33:10 -04:00
|
|
|
} else if (message.message_type === THREAD_MESSAGE_TYPE.SYSTEM) {
|
2020-05-24 18:54:26 -04:00
|
|
|
line += ` [SYSTEM] ${message.body}`;
|
2020-05-24 18:33:10 -04:00
|
|
|
} 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}`;
|
2020-05-24 18:33:10 -04:00
|
|
|
} else if (message.message_type === THREAD_MESSAGE_TYPE.CHAT) {
|
2020-05-24 18:54:26 -04:00
|
|
|
line += ` [CHAT] [${message.user_name}] ${message.body}`;
|
2020-05-24 18:33:10 -04:00
|
|
|
} else if (message.message_type === THREAD_MESSAGE_TYPE.COMMAND) {
|
2020-05-24 18:54:26 -04:00
|
|
|
line += ` [COMMAND] [${message.user_name}] ${message.body}`;
|
2018-02-11 14:54:30 -05:00
|
|
|
} else {
|
2020-05-24 18:54:26 -04:00
|
|
|
line += ` [${message.user_name}] ${message.body}`;
|
2018-02-11 14:54:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return line;
|
|
|
|
});
|
|
|
|
|
2020-08-12 17:08:37 -04:00
|
|
|
const openedAt = moment(thread.created_at).format("YYYY-MM-DD HH:mm:ss");
|
2020-05-25 16:56:48 -04:00
|
|
|
const header = `# Modmail thread with ${thread.user_name} (${thread.user_id}) started at ${openedAt}. All times are in UTC+0.`;
|
2020-05-24 18:54:26 -04:00
|
|
|
|
2020-08-12 17:08:37 -04:00
|
|
|
const fullResponse = header + "\n\n" + lines.join("\n");
|
2020-05-24 18:54:26 -04:00
|
|
|
|
2020-08-12 17:08:37 -04:00
|
|
|
res.setHeader("Content-Type", "text/plain; charset=UTF-8");
|
2020-05-24 18:54:26 -04:00
|
|
|
res.end(fullResponse);
|
2018-02-11 14:54:30 -05:00
|
|
|
}
|
|
|
|
|
2020-05-24 18:54:26 -04:00
|
|
|
function serveAttachments(req, res, pathParts) {
|
2018-02-11 14:54:30 -05:00
|
|
|
const desiredFilename = pathParts[pathParts.length - 1];
|
|
|
|
const id = pathParts[pathParts.length - 2];
|
|
|
|
|
|
|
|
if (id.match(/^[0-9]+$/) === null) return notfound(res);
|
2018-03-11 17:17:14 -04:00
|
|
|
if (desiredFilename.match(/^[0-9a-z._-]+$/i) === null) return notfound(res);
|
2018-02-11 14:54:30 -05:00
|
|
|
|
2019-03-06 16:31:24 -05:00
|
|
|
const attachmentPath = attachments.getLocalAttachmentPath(id);
|
2018-02-11 14:54:30 -05:00
|
|
|
fs.access(attachmentPath, (err) => {
|
|
|
|
if (err) return notfound(res);
|
|
|
|
|
2020-08-12 17:08:37 -04:00
|
|
|
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);
|
2018-02-11 14:54:30 -05:00
|
|
|
|
2020-08-12 17:08:37 -04:00
|
|
|
res.setHeader("Content-Type", fileMime);
|
2018-02-11 14:54:30 -05:00
|
|
|
|
|
|
|
const read = fs.createReadStream(attachmentPath);
|
|
|
|
read.pipe(res);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = () => {
|
|
|
|
const server = http.createServer((req, res) => {
|
|
|
|
const parsedUrl = url.parse(`http://${req.url}`);
|
2020-08-12 17:08:37 -04:00
|
|
|
const pathParts = parsedUrl.pathname.split("/").filter(v => v !== "");
|
2020-05-24 18:54:26 -04:00
|
|
|
const query = qs.parse(parsedUrl.query);
|
2018-02-11 14:54:30 -05:00
|
|
|
|
2020-08-12 17:08:37 -04:00
|
|
|
if (parsedUrl.pathname.startsWith("/logs/")) {
|
2020-05-24 18:54:26 -04:00
|
|
|
serveLogs(req, res, pathParts, query);
|
2020-08-12 17:08:37 -04:00
|
|
|
} else if (parsedUrl.pathname.startsWith("/attachments/")) {
|
2020-05-24 18:54:26 -04:00
|
|
|
serveAttachments(req, res, pathParts, query);
|
2018-02-11 14:54:30 -05:00
|
|
|
} else {
|
|
|
|
notfound(res);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-08-12 17:08:37 -04:00
|
|
|
server.on("error", err => {
|
|
|
|
console.log("[WARN] Web server error:", err.message);
|
2018-08-07 17:54:01 -04:00
|
|
|
});
|
|
|
|
|
2018-02-11 14:54:30 -05:00
|
|
|
server.listen(config.port);
|
|
|
|
};
|