Upload via GUI (194 Dateien)
@@ -1,58 +1,29 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/*
|
|
||||||
* AeroMC – CurseForge-Weiterleitung
|
|
||||||
* ---------------------------------
|
|
||||||
* Hält den CurseForge-API-Schlüssel und stellt die Anfragen stellvertretend
|
|
||||||
* für den Launcher. So bleibt der Schlüssel auf dem Server: in der verteilten
|
|
||||||
* .exe wäre er für jeden auslesbar, und CurseForge untersagt die Weitergabe
|
|
||||||
* an Dritte ausdrücklich.
|
|
||||||
*
|
|
||||||
* Wege:
|
|
||||||
* GET /health – Lebenszeichen, ohne Schlüsselangaben
|
|
||||||
* POST /v1/mods/files – Dateiliste auflösen (Rumpf: { fileIds: [...] })
|
|
||||||
* GET /v1/download?url=... – Mod-Datei durchreichen (CDN verlangt seit
|
|
||||||
* Juli 2026 ebenfalls einen Schlüssel)
|
|
||||||
*
|
|
||||||
* Einstellungen über Umgebungsvariablen, siehe .env.example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const { Readable } = require('stream');
|
const { Readable } = require('stream');
|
||||||
|
|
||||||
const KEY = (process.env.CF_API_KEY || '').trim();
|
const KEY = (process.env.CF_API_KEY || '').trim();
|
||||||
const PORT = Number(process.env.PORT || 8420);
|
const PORT = Number(process.env.PORT || 8420);
|
||||||
const HOST = process.env.HOST || '0.0.0.0';
|
const HOST = process.env.HOST || '0.0.0.0';
|
||||||
/*
|
|
||||||
* Ein oder mehrere gültige Token, durch Komma getrennt.
|
|
||||||
*
|
|
||||||
* Mehrere deshalb, weil das Token in ausgelieferten Paketen steckt: Beim
|
|
||||||
* Wechsel trägst du eine Zeit lang altes und neues ein, damit ältere
|
|
||||||
* Installationen weiterlaufen, bis alle das Update haben. Danach das alte
|
|
||||||
* streichen.
|
|
||||||
*/
|
|
||||||
const TOKENS = new Set(
|
const TOKENS = new Set(
|
||||||
String(process.env.CF_PROXY_TOKEN || '')
|
String(process.env.CF_PROXY_TOKEN || '')
|
||||||
.split(',').map((t) => t.trim()).filter(Boolean),
|
.split(',').map((t) => t.trim()).filter(Boolean),
|
||||||
);
|
);
|
||||||
const LIMIT_PRO_MIN = Number(process.env.RATE_LIMIT_PER_MIN || 60);
|
const LIMIT_PRO_MIN = Number(process.env.RATE_LIMIT_PER_MIN || 60);
|
||||||
const MAX_MB = Number(process.env.MAX_DOWNLOAD_MB || 512);
|
const MAX_MB = Number(process.env.MAX_DOWNLOAD_MB || 512);
|
||||||
// Anzahl der Reverse-Proxies davor. 0 = keiner, 1 = z. B. Nginx Proxy Manager,
|
|
||||||
// 2 = z. B. Cloudflare vor dem Proxy Manager.
|
|
||||||
const PROXY_STUFEN = Math.max(0, Number(process.env.TRUST_PROXY || 0) || 0);
|
const PROXY_STUFEN = Math.max(0, Number(process.env.TRUST_PROXY || 0) || 0);
|
||||||
|
|
||||||
const CF_API = 'https://api.curseforge.com/v1';
|
const CF_API = 'https://api.curseforge.com/v1';
|
||||||
|
|
||||||
// Ohne User-Agent weisen Dienste hinter Cloudflare Anfragen gerne mit 403 ab.
|
|
||||||
const UA = 'AeroMC-Launcher-Proxy/1.0 (+https://git.viper.ipv64.net)';
|
const UA = 'AeroMC-Launcher-Proxy/1.0 (+https://git.viper.ipv64.net)';
|
||||||
|
|
||||||
function cfKopfzeilen(weitere) {
|
function cfKopfzeilen(weitere) {
|
||||||
return Object.assign({ 'x-api-key': KEY, Accept: 'application/json', 'User-Agent': UA }, weitere || {});
|
return Object.assign({ 'x-api-key': KEY, Accept: 'application/json', 'User-Agent': UA }, weitere || {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nur diese Hosts dürfen durchgereicht werden. Ohne diese Liste wäre der
|
|
||||||
// Server ein offenes Tor in dein Netz – jemand könnte ihn Adressen im
|
|
||||||
// Heimnetz abrufen lassen und die Antwort mitlesen.
|
|
||||||
const ERLAUBTE_HOSTS = new Set([
|
const ERLAUBTE_HOSTS = new Set([
|
||||||
'edge.forgecdn.net',
|
'edge.forgecdn.net',
|
||||||
'mediafilez.forgecdn.net',
|
'mediafilez.forgecdn.net',
|
||||||
|
|||||||
|
After Width: | Height: | Size: 207 B |
|
After Width: | Height: | Size: 207 B |
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"providers": [
|
||||||
|
{
|
||||||
|
"type": "bitmap",
|
||||||
|
"file": "aeromc:font/symbole.png",
|
||||||
|
"ascent": 7,
|
||||||
|
"height": 8,
|
||||||
|
"chars": [
|
||||||
|
"\ue900\ue901\ue902\ue903\ue904\ue905"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 359 B |
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"gui": {
|
||||||
|
"scaling": {
|
||||||
|
"type": "nine_slice",
|
||||||
|
"width": 200,
|
||||||
|
"height": 20,
|
||||||
|
"border": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 692 B |
|
After Width: | Height: | Size: 353 B |
|
After Width: | Height: | Size: 676 B |
|
After Width: | Height: | Size: 5.2 MiB |