147 lines
4.1 KiB
JavaScript
147 lines
4.1 KiB
JavaScript
/**
|
|
* Minimaler lokaler HTTPS-Server für das Starface Outlook Sync Add-in.
|
|
* Liefert nur statische Dateien aus dem webroot-Verzeichnis aus.
|
|
* Wird als Windows-Dienst oder Scheduled Task ausgeführt.
|
|
*/
|
|
|
|
const https = require("https");
|
|
const http = require("http");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const url = require("url");
|
|
|
|
// Konfiguration aus config.json laden
|
|
const configPath = path.join(__dirname, "config.json");
|
|
if (!fs.existsSync(configPath)) {
|
|
console.error("config.json nicht gefunden:", configPath);
|
|
process.exit(1);
|
|
}
|
|
|
|
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
const PORT = config.port || 444;
|
|
const WEBROOT = path.join(__dirname, "webroot");
|
|
const CERT_DIR = path.join(__dirname, "certs");
|
|
|
|
// MIME-Types
|
|
const MIME_TYPES = {
|
|
".html": "text/html; charset=utf-8",
|
|
".js": "application/javascript; charset=utf-8",
|
|
".css": "text/css; charset=utf-8",
|
|
".json": "application/json; charset=utf-8",
|
|
".png": "image/png",
|
|
".jpg": "image/jpeg",
|
|
".svg": "image/svg+xml",
|
|
".ico": "image/x-icon",
|
|
".xml": "application/xml; charset=utf-8",
|
|
};
|
|
|
|
function getMimeType(filePath) {
|
|
const ext = path.extname(filePath).toLowerCase();
|
|
return MIME_TYPES[ext] || "application/octet-stream";
|
|
}
|
|
|
|
function handleRequest(req, res) {
|
|
// CORS-Header für Office Add-in
|
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
|
|
if (req.method === "OPTIONS") {
|
|
res.writeHead(204);
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
if (req.method !== "GET") {
|
|
res.writeHead(405, { "Content-Type": "text/plain" });
|
|
res.end("Method Not Allowed");
|
|
return;
|
|
}
|
|
|
|
// URL parsen und Pfad bereinigen
|
|
const parsedUrl = url.parse(req.url);
|
|
let filePath = decodeURIComponent(parsedUrl.pathname || "/");
|
|
|
|
// Directory index
|
|
if (filePath === "/" || filePath === "") {
|
|
filePath = "/taskpane.html";
|
|
}
|
|
|
|
// Pfad-Traversal verhindern
|
|
const safePath = path.normalize(filePath).replace(/^(\.\.[\/\\])+/, "");
|
|
const fullPath = path.join(WEBROOT, safePath);
|
|
|
|
// Sicherstellen, dass der Pfad innerhalb des webroot liegt
|
|
if (!fullPath.startsWith(WEBROOT)) {
|
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
res.end("Forbidden");
|
|
return;
|
|
}
|
|
|
|
// Datei ausliefern
|
|
fs.stat(fullPath, (err, stats) => {
|
|
if (err || !stats.isFile()) {
|
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
res.end("Not Found: " + safePath);
|
|
return;
|
|
}
|
|
|
|
const mimeType = getMimeType(fullPath);
|
|
res.writeHead(200, {
|
|
"Content-Type": mimeType,
|
|
"Cache-Control": "no-cache",
|
|
});
|
|
|
|
const stream = fs.createReadStream(fullPath);
|
|
stream.pipe(res);
|
|
stream.on("error", () => {
|
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
res.end("Internal Server Error");
|
|
});
|
|
});
|
|
}
|
|
|
|
// Zertifikate laden und HTTPS-Server starten
|
|
const certFile = path.join(CERT_DIR, "localhost.crt");
|
|
const keyFile = path.join(CERT_DIR, "localhost.key");
|
|
|
|
if (!fs.existsSync(certFile) || !fs.existsSync(keyFile)) {
|
|
console.error("Zertifikate nicht gefunden in:", CERT_DIR);
|
|
console.error("Bitte zuerst setup.ps1 ausführen.");
|
|
process.exit(1);
|
|
}
|
|
|
|
const serverOptions = {
|
|
cert: fs.readFileSync(certFile),
|
|
key: fs.readFileSync(keyFile),
|
|
};
|
|
|
|
const server = https.createServer(serverOptions, handleRequest);
|
|
|
|
server.listen(PORT, "127.0.0.1", () => {
|
|
console.log(`Starface Outlook Sync - Lokaler Server`);
|
|
console.log(`Läuft auf: https://localhost:${PORT}`);
|
|
console.log(`Webroot: ${WEBROOT}`);
|
|
console.log(`PID: ${process.pid}`);
|
|
});
|
|
|
|
server.on("error", (err) => {
|
|
if (err.code === "EADDRINUSE") {
|
|
console.error(`Port ${PORT} ist bereits belegt.`);
|
|
console.error("Bitte anderen Port in config.json wählen.");
|
|
} else {
|
|
console.error("Server-Fehler:", err.message);
|
|
}
|
|
process.exit(1);
|
|
});
|
|
|
|
// Graceful Shutdown
|
|
process.on("SIGINT", () => {
|
|
console.log("Server wird beendet...");
|
|
server.close(() => process.exit(0));
|
|
});
|
|
process.on("SIGTERM", () => {
|
|
console.log("Server wird beendet...");
|
|
server.close(() => process.exit(0));
|
|
});
|