Compare commits

..

10 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
6 changed files with 54 additions and 66 deletions
+1
View File
@@ -8,3 +8,4 @@
!/README.md !/README.md
!/files/www/qonq.js !/files/www/qonq.js
!/favicon.ico !/favicon.ico
!/antiscrape.js
+6 -7
View File
@@ -17,13 +17,12 @@ The following environment variables are optional.
| Variable | Description | Default | | Variable | Description | Default |
|----------|-------------|---------| |----------|-------------|---------|
| `HOSTNAME` | Overrides the hostname for generating URLs. | hostname of the upload request | | `BASE_HOSTNAME` | Overrides the hostname for generating URLs. | host header on the upload request |
| `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) | | `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();
};
-14
View File
@@ -8,7 +8,6 @@
"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-favicon": "^2.5.0",
"serve-index": "^1.9.1" "serve-index": "^1.9.1"
} }
@@ -215,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",
@@ -743,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",
-1
View File
@@ -3,7 +3,6 @@
"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-favicon": "^2.5.0",
"serve-index": "^1.9.1" "serve-index": "^1.9.1"
} }
+19 -31
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 serveFavicon = require("serve-favicon");
var path = require("path"); var path = require("path");
var fs = require("fs"); var fs = require("fs");
try { try { var customGen = require("./customGen"); } catch(e) {}
var customUrlGen = require("./custom-urlgen");
} catch(e) {}
var FILES_DIR = process.env.FILES_DIR || "files"; var FILES_DIR = process.env.FILES_DIR || "files";
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;
@@ -32,17 +29,12 @@ 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") {
@@ -50,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);
var url = customUrlGen?.(filecode, req) || `${req.protocol}://${filecode}.${process.env.HOSTNAME || 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], {
@@ -83,9 +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}));
app.use((req, res) => {
if (req.method == "GET") res.status(404).send("This resource does not exist.");
else res.sendStatus(405);
});