Compare commits

...

15 Commits

Author SHA1 Message Date
lamp da1b0ab58c no 405 2023-03-03 02:39:46 -06:00
lamp ff8b626b8a rename env var 2022-01-18 15:38:30 -06:00
lamp e7b770b177 tweak 2022-01-18 15:29:15 -06:00
lamp 5d203d2ca7 tweak 2022-01-18 15:24:22 -06:00
lamp 4e99509d96 Merge branch 'master' of gitea.moe:lamp/qonq 2021-12-05 02:40:36 -06:00
lamp 16afa0abc5 add antiscrape 2021-12-05 02:40:33 -06:00
lamp 794b84a152 Update 'README.md' 2021-12-05 01:18:50 -06:00
lamp c09993d9bc simple binary upload instead of form 2021-12-05 01:17:35 -06:00
lamp 2c0d3ef78e rename HOSTNAME env because conflict 2021-12-05 00:44:10 -06:00
lamp 2448d69f1f hmm 2021-12-03 16:51:58 -06:00
lamp 7f57c0ed23 Merge branch 'master' of gitea.moe:lamp/qonq 2021-10-22 17:43:22 -05:00
lamp 292ff9297d custom url gen 2021-10-22 17:42:17 -05:00
lamp 9897bcd577 Update 'README.md' 2021-10-22 16:51:20 -05:00
lamp 847950c726 favicon 2021-10-22 16:49:31 -05:00
lamp 6da1f4d556 404 handler 2021-10-22 16:30:40 -05:00
7 changed files with 111 additions and 64 deletions
+2
View File
@@ -7,3 +7,5 @@
!/package-lock.json !/package-lock.json
!/README.md !/README.md
!/files/www/qonq.js !/files/www/qonq.js
!/favicon.ico
!/antiscrape.js
+8 -9
View File
@@ -17,13 +17,12 @@ The following environment variables are optional.
| Variable | Description | Default | | Variable | Description | Default |
|----------|-------------|---------| |----------|-------------|---------|
| `HOSTNAMES` | Comma-separated list of hostnames that will be chosen at random for the URL sent back after an upload. | request hostname | | `BASE_HOSTNAME` | Overrides the hostname for generating URLs. | host header on the upload request |
| `DISCORD_WEBHOOK` | Discord webhook url that uploads will be sent to to make them pre-load the embed, which theoretically makes it faster. | undefined (disabled) | | `DISCORD_WEBHOOK` | Discord webhook url that newly-uploaded URLs will be sent to to pre-load their embed, which theoretically makes them embed again faster. | `undefined` (disabled) |
| `PORT` | TCP port to listen on | `8568` | | `PORT` | TCP port to listen on | `8568` |
| `ADDRESS` | Address to bind to | `'0.0.0.0'` (all) | | `ADDRESS` | Address to bind to | `'0.0.0.0'` (all) |
| `FILES_DIR` | Directory to store the files in | files (relative of working directory) | | `FILES_DIR` | Directory to store the files in | `'files'` (relative of working directory) |
| `TMP_DIR` | Directory to store pending uploads in | os.tmpdir() | | `TRUST_PROXY` | Value for express's [`'trust proxy'`](https://expressjs.com/en/5x/api.html#trust.proxy.options.table) setting | `'loopback'` |
| `TRUST_PROXY` | Value for express's [`'trust proxy'`](https://expressjs.com/en/5x/api.html#trust.proxy.options.table) setting | `'127.0.0.1'` |
Run with `node qonq.js` or your favorite init system. Run with `node qonq.js` or your favorite init system.
@@ -35,12 +34,12 @@ Run with `node qonq.js` or your favorite init system.
"Version": "12.4.1", "Version": "12.4.1",
"DestinationType": "ImageUploader, TextUploader, FileUploader", "DestinationType": "ImageUploader, TextUploader, FileUploader",
"RequestMethod": "POST", "RequestMethod": "POST",
"RequestURL": "http://localhost:8568/upload", "RequestURL": "https://qonq.gq/",
"Headers": { "Headers": {
"authentication": "paste value of AUTH_TOKEN here" "authentication": "paste value of AUTH_TOKEN here",
"filename": "$filename$"
}, },
"Body": "MultipartFormData", "Body": "Binary"
"FileFormName": "file"
} }
``` ```
You can import this custom uploader config and modify the Request URL and authentication fields as necessary. You can import this custom uploader config and modify the Request URL and authentication fields as necessary.
+15
View File
@@ -0,0 +1,15 @@
// someone could iterate over all ~1.6 million possible file codes to download all files.
// prevent this by banning IP addresses that request too many non-existant files.
var ip404 = {};
module.exports = (req, res, next) => {
if (ip404[req.ip]?.size > 10)
return res.status(403).send("Banned");
res.on("finish", () => {
if (res.statusCode == 404 && req.filecode) {
if (!ip404[req.ip]) ip404[req.ip] = new Set();
ip404[req.ip].add(req.filecode);
}
});
next();
};
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

+50 -14
View File
@@ -8,7 +8,7 @@
"colors": "^1.4.0", "colors": "^1.4.0",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"formidable": "^1.2.2", "serve-favicon": "^2.5.0",
"serve-index": "^1.9.1" "serve-index": "^1.9.1"
} }
}, },
@@ -214,14 +214,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/formidable": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
"integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==",
"funding": {
"url": "https://ko-fi.com/tunnckoCore/commissions"
}
},
"node_modules/forwarded": { "node_modules/forwarded": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@@ -445,6 +437,31 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}, },
"node_modules/serve-favicon": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz",
"integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=",
"dependencies": {
"etag": "~1.8.1",
"fresh": "0.5.2",
"ms": "2.1.1",
"parseurl": "~1.3.2",
"safe-buffer": "5.1.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/serve-favicon/node_modules/ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"node_modules/serve-favicon/node_modules/safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"node_modules/serve-index": { "node_modules/serve-index": {
"version": "1.9.1", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
@@ -717,11 +734,6 @@
"unpipe": "~1.0.0" "unpipe": "~1.0.0"
} }
}, },
"formidable": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
"integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q=="
},
"forwarded": { "forwarded": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@@ -890,6 +902,30 @@
} }
} }
}, },
"serve-favicon": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz",
"integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=",
"requires": {
"etag": "~1.8.1",
"fresh": "0.5.2",
"ms": "2.1.1",
"parseurl": "~1.3.2",
"safe-buffer": "5.1.1"
},
"dependencies": {
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
}
}
},
"serve-index": { "serve-index": {
"version": "1.9.1", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+1 -1
View File
@@ -3,7 +3,7 @@
"colors": "^1.4.0", "colors": "^1.4.0",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"formidable": "^1.2.2", "serve-favicon": "^2.5.0",
"serve-index": "^1.9.1" "serve-index": "^1.9.1"
} }
} }
+22 -27
View File
@@ -1,22 +1,19 @@
require("dotenv").config(); require("dotenv").config();
var colors = require("colors"); var colors = require("colors");
var express = require("express"); var express = require("express");
var formidable = require("formidable");
var serveIndex = require("serve-index"); var serveIndex = require("serve-index");
var serveFavicon = require("serve-favicon");
var path = require("path"); var path = require("path");
var fs = require("fs"); var fs = require("fs");
try { var customGen = require("./customGen"); } catch(e) {}
var FILES_DIR = process.env.FILES_DIR || "files"; var FILES_DIR = process.env.FILES_DIR || "files";
if (process.env.HOSTNAMES) {
var HOSTNAMES = process.env.HOSTNAMES.split(',');
var randomHostname = () => HOSTNAMES[Math.floor(Math.random() * HOSTNAMES.length)];
}
var app = express(); var app = express();
app.set("env", "production"); app.set("env", "production");
app.set('trust proxy', process.env.TRUST_PROXY || "127.0.0.1"); app.set('trust proxy', process.env.TRUST_PROXY || "loopback");
app.listen(process.env.PORT || 8568, process.env.ADDRESS); app.listen(process.env.PORT || 8568, process.env.ADDRESS);
app.use((req,res,next) => { res.header("Access-Control-Allow-Origin", '*'); next(); });
app.use((req, res, next)=>{ app.use((req, res, next)=>{
var d = new Date; var d = new Date;
@@ -27,20 +24,17 @@ app.use((req, res, next)=>{
next(); next();
}); });
app.use(serveFavicon("favicon.ico"));
app.post("*", (req, res, next) => { app.post("*", (req, res, next) => {
if (req.headers.authentication != process.env.AUTH_TOKEN) return void res.status(403).send("Unauthorized"); if (req.headers.authentication != process.env.AUTH_TOKEN) return void res.status(403).send("Unauthorized");
var form = new formidable.IncomingForm({
maxFileSize: 2**30, // 1 GiB
maxFields: 1,
uploadDir: process.env.TMP_DIR
});
form.parse(req, function(err, fields, files) {
if (err) return void next(err);
var file = files.file;
if (!file) return void res.sendStatus(400);
(function trymkdir() { (function trymkdir() {
var filecode = Math.random().toString(36).slice(2).substring(0,4); if (customGen) {
var g = customGen(req);
var filecode = g.next().value;
}
filecode ||= Math.random().toString(36).slice(2).substring(0,4);
var webroot = path.join(FILES_DIR, filecode); var webroot = path.join(FILES_DIR, filecode);
fs.mkdir(webroot, function (error) { fs.mkdir(webroot, function (error) {
if (error) if (error.code == "EEXIST") { if (error) if (error.code == "EEXIST") {
@@ -48,28 +42,30 @@ app.post("*", (req, res, next) => {
trymkdir(); trymkdir();
} else next(error); } else next(error);
else { else {
fs.rename(file.path, path.join(webroot, file.name), function (error) { var filename = req.headers.filename || "file";
if (error) return void next(error); var filepath = path.join(webroot, filename);
let url = `${req.protocol}://${filecode}.${randomHostname?.() || req.hostname}`; req.pipe(fs.createWriteStream(filepath));
res.send(url); req.on("close", () => {
var url = g?.next().value || `${req.protocol}://${filecode}.${process.env.BASE_HOSTNAME || req.hostname}`;
res.type('text').send(url);
require("./discord-preloader.js")(url); require("./discord-preloader.js")(url);
}); });
} }
}); });
})(); })();
}); });
});
app.use(require("./antiscrape"));
app.get(['/', '/:code/', '/:code/*'], function(req, res, next){ app.get(['/', '/:code/', '/:code/*'], function(req, res, next){
var subdomain = req.subdomains.at(-1); var subdomain = req.subdomains.at(-1);
var filecode = subdomain || req.params.code; req.filecode = subdomain || req.params.code;
if (!filecode) filecode = "www"; if (!req.filecode) req.filecode = "www";
var webroot = path.join(FILES_DIR, filecode); var webroot = path.join(FILES_DIR, req.filecode);
fs.readdir(webroot, function(error, webrootdirlist) { fs.readdir(webroot, function(error, webrootdirlist) {
if (error) return void next(error.code == "ENOENT" ? "route" : error); if (error) return void next(error.code == "ENOENT" ? "route" : error);
if (webrootdirlist.length > 1) { if (webrootdirlist.length > 1) {
if (subdomain) req.url = path.join(filecode, req.url); if (subdomain) req.url = path.join(req.filecode, req.url);
next(); next();
} else if (webrootdirlist.length == 1) { } else if (webrootdirlist.length == 1) {
res.sendFile(webrootdirlist[0], { res.sendFile(webrootdirlist[0], {
@@ -81,4 +77,3 @@ app.get(['/', '/:code/', '/:code/*'], function(req, res, next){
} }
}); });
}, express.static(FILES_DIR), serveIndex(FILES_DIR, {icons: true})); }, express.static(FILES_DIR), serveIndex(FILES_DIR, {icons: true}));