pc-webserver/index.js

103 lines
3.0 KiB
JavaScript

var express = require("express");
var multer = require("multer");
var sanitizeFilename = require("sanitize-filename");
var serveIndex = require("serve-index");
var colors = require("colors");
var {WebSocketServer} = require("ws");
var qs = require("qs");
var proxyaddr = require("proxy-addr");
var fs = require("fs");
var app = express();
app.set("env", "production");
app.set("trust proxy", "loopback");
app.set("view engine", "pug");
var server = app.listen(process.env.PORT || 80);
var upload = multer({storage: multer.diskStorage({
destination: "uploads",
filename: (req, file, cb) => cb(null, safeFilename(file.filename))
})});
var wss = new WebSocketServer({server, maxPayload: 0});
wss.on("connection", (ws, req) => {
req.query = qs.parse(req.url.substring(req.url.indexOf('?')+1));
req.ip = proxyaddr(req, app.get("trust proxy"));
if (!req.query.name) return ws.close();
var d = new Date;
var filename = safeFilename(req.query.name);
var tmpname = Math.random().toString(36).substring(2);
try {
var fd = fs.openSync(`tmp/${tmpname}`, 'w');
} catch(error) {
ws.send(error.message);
return;
}
var complete = false;
ws.on("message", (data, isBinary) => {
if (isBinary) {
fs.write(fd, data, (error) => ws.send(error?.message));
} else {
if (data == "end") {
complete = true;
fs.closeSync(fd);
fs.renameSync(`tmp/${tmpname}`, `uploads/${filename}`);
ws.close();
}
}
});
ws.on("close", () => {
console.log(`${`[${d.toISOString()}]`.magenta} ${req.ip.cyan} ${"WebSocket".bold.yellow} ${req.headers.host}${req.url} ${`"${req.headers["user-agent"]}"`.gray} ${Date.now()-d}ms`);
if (!complete) {
fs.closeSync(fd);
fs.unlinkSync(`tmp/${tmpname}`);
}
});
});
app.use((req, res, next)=>{
var d = new Date;
res.on("finish", () => {
var sc = res.statusCode.toString(), sc = sc.startsWith('2') ? sc.green : sc.startsWith('3') ? sc.cyan : sc.startsWith('4') ? sc.red : sc.startsWith('5') ? sc.yellow.bgRed : sc;
console.log(`${`[${d.toISOString()}]`.magenta} ${req.ip.cyan} ${req.method.bold.yellow} ${req.hostname}${req.url} ${sc} ${`"${req.headers["user-agent"]}"`.gray} ${Date.now()-d}ms`);
});
next();
});
app.get("/upload", (req, res) => {
var files = fs.readdirSync("uploads").map(name => Object.assign({name}, fs.statSync(`uploads/${name}`))).sort((a,b) => b.mtime - a.mtime);
res.render("upload", {files});
});
app.post("/upload", upload.array("file"), (req, res) => {
res.header("Refresh", 3);
res.type("json").send(require('util').inspect(req.files));
});
app.use("/assets/", express.static("assets"));
//app.use((req, res) => serveHandler(req, res, {public: "public"}));
app.use(express.static("public"), serveIndex("public", {icons: true}));
function safeFilename(f) {
f = sanitizeFilename(f);
while (fs.existsSync(`uploads/${f}`)) {
var x = f.lastIndexOf('.');
if (x != -1) {
var fn = f.substring(0, x);
var fe = f.substring(x);
} else var fn = f, fe = '';
var m = fn.match(/(.*)(?<= )(\d+)$/);
if (m) fn = m[1] + ++m[2];
else fn += " 2";
f = fn + fe;
}
return f;
}