Upload via GUI (202 Dateien)

This commit is contained in:
2026-10-11 07:05:41 +00:00
parent 4a7a619f35
commit c56b41de34
6 changed files with 35 additions and 5 deletions
+6 -1
View File
@@ -19,9 +19,14 @@ HOST=0.0.0.0
# weiterlaufen, bis alle das Update haben – danach das alte streichen.
# CF_PROXY_TOKEN=neues-token,altes-token
#
# Leer lassen = keine Tokenprüfung.
# Pflicht: Ohne Token startet der Dienst nicht – sonst könnte jeder, der die
# Adresse kennt, deinen API-Key und dein Download-Kontingent benutzen.
# Ein langes Zufalls-Token erzeugen, z. B.: openssl rand -hex 32
CF_PROXY_TOKEN=
# Nur für ein abgeschottetes Netz: Dienst bewusst OHNE Token betreiben.
# CF_PROXY_OFFEN=1
# Anfragen je Minute und Absender. 0 = keine Begrenzung.
RATE_LIMIT_PER_MIN=60
+2 -1
View File
@@ -101,7 +101,8 @@ Der Dienst steht offen im Netz. Eingebaut ist:
die Host-Liste geprüft, höchstens vier Sprünge.
- **Ratenbegrenzung** je Absender, einstellbar über `RATE_LIMIT_PER_MIN`.
- **Größengrenze** für durchgereichte Dateien über `MAX_DOWNLOAD_MB`.
- **Optionales Token** über `CF_PROXY_TOKEN`.
- **Token** über `CF_PROXY_TOKEN` – Pflicht: ohne Token startet der Dienst nicht
(bewusst offen nur mit `CF_PROXY_OFFEN=1`, z. B. im abgeschotteten Netz).
Zum Token eine ehrliche Einordnung: Es steckt dann auch im Launcher und ist
dort auslesbar. Es hält Gelegenheitsnutzer ab, keine entschlossenen. Die
+27 -3
View File
@@ -1,6 +1,7 @@
'use strict';
const http = require('http');
const crypto = require('crypto');
const { Readable } = require('stream');
const KEY = (process.env.CF_API_KEY || '').trim();
@@ -35,6 +36,17 @@ if (!KEY) {
process.exit(1);
}
// Ohne Token wäre der Dienst für jeden offen, der die Adresse kennt – und damit
// auch der API-Key und das Download-Kontingent dahinter. Deshalb startet er
// ohne CF_PROXY_TOKEN gar nicht erst. Wer ihn bewusst offen betreiben will
// (z. B. nur im eigenen Netz), muss das ausdrücklich sagen: CF_PROXY_OFFEN=1.
const OFFEN_ERLAUBT = process.env.CF_PROXY_OFFEN === '1';
if (!TOKENS.size && !OFFEN_ERLAUBT) {
console.error('CF_PROXY_TOKEN fehlt. Ohne Token könnte jeder den Dienst (und deinen API-Key) benutzen.');
console.error('Token setzen (siehe .env.example) – oder, nur für ein abgeschottetes Netz, CF_PROXY_OFFEN=1.');
process.exit(1);
}
// ---------------------------------------------------------------------------
// Ratenbegrenzung: einfaches Zeitfenster je Absender
// ---------------------------------------------------------------------------
@@ -88,9 +100,21 @@ function sendeJson(res, code, daten) {
res.end(koerper);
}
// Vergleich in gleichbleibender Zeit, damit sich ein Token nicht Zeichen für
// Zeichen über die Antwortdauer erraten lässt
function gleich(a, b) {
const x = crypto.createHash('sha256').update(a).digest();
const y = crypto.createHash('sha256').update(b).digest();
return crypto.timingSafeEqual(x, y);
}
function tokenOk(req) {
if (!TOKENS.size) return true;
return TOKENS.has(String(req.headers['x-aeromc-token'] || '').trim());
if (!TOKENS.size) return OFFEN_ERLAUBT; // ohne Token nur mit ausdrücklicher Freigabe
const erhalten = String(req.headers['x-aeromc-token'] || '').trim();
if (!erhalten) return false;
let ok = false;
for (const t of TOKENS) if (gleich(t, erhalten)) ok = true;
return ok;
}
function leseKoerper(req, maxBytes = 1_000_000) {
@@ -308,7 +332,7 @@ server.listen(PORT, HOST, () => {
console.log(`AeroMC CurseForge-Weiterleitung läuft auf ${HOST}:${PORT}`);
console.log(` Ratenbegrenzung: ${LIMIT_PRO_MIN > 0 ? LIMIT_PRO_MIN + '/Minute je Absender' : 'aus'}`);
// niemals die Token selbst ausgeben – Protokolle wandern schnell woanders hin
console.log(` Token verlangt : ${TOKENS.size ? 'ja (' + TOKENS.size + ' gültige)' : 'nein'}`);
console.log(` Token verlangt : ${TOKENS.size ? 'ja (' + TOKENS.size + ' gültige)' : 'NEIN – offen für jeden (CF_PROXY_OFFEN=1)'}`);
console.log(` Proxy-Stufen : ${PROXY_STUFEN} (${PROXY_STUFEN ? 'Absender aus X-Forwarded-For' : 'Absender aus der Verbindung'})`);
});