Mehrfachlogin nicht mehr möglich

This commit is contained in:
Cay 2026-03-13 13:22:52 +00:00
parent 4d8681ac86
commit fd116db132
11 changed files with 157 additions and 143 deletions

31
middleware/auth.js Normal file
View File

@ -0,0 +1,31 @@
const db = require("../database/database");
async function auth(req, res, next) {
if (!req.session.user) {
return res.redirect("/");
}
try {
const [rows] = await db.query(
"SELECT session_token FROM accounts WHERE id = ?",
[req.session.user.id],
);
if (!rows.length) {
req.session.destroy();
return res.redirect("/");
}
if (rows[0].session_token !== req.session.user.token) {
req.session.destroy();
return res.redirect("/");
}
next();
} catch (error) {
console.error(error);
res.redirect("/");
}
}
module.exports = auth;

View File

@ -1,5 +1,10 @@
fetch("/api/buildings") fetch("/api/buildings")
.then((res) => res.json()) .then((res) => {
if (!res.ok) {
throw new Error("API Fehler");
}
return res.json();
})
.then((buildings) => { .then((buildings) => {
buildings.forEach((building) => { buildings.forEach((building) => {
const element = document.querySelector( const element = document.querySelector(
@ -10,7 +15,6 @@ fetch("/api/buildings")
let title = element.querySelector("title"); let title = element.querySelector("title");
// Falls kein title existiert → erstellen
if (!title) { if (!title) {
title = document.createElementNS("http://www.w3.org/2000/svg", "title"); title = document.createElementNS("http://www.w3.org/2000/svg", "title");
element.prepend(title); element.prepend(title);
@ -18,4 +22,7 @@ fetch("/api/buildings")
title.textContent = building.name; title.textContent = building.name;
}); });
})
.catch((error) => {
console.error("Buildings API Fehler:", error);
}); });

View File

@ -2,6 +2,10 @@ const popup = document.getElementById("building-popup");
const title = document.getElementById("popup-title"); const title = document.getElementById("popup-title");
const tooltip = document.getElementById("map-tooltip"); const tooltip = document.getElementById("map-tooltip");
/* ================================
Tabs zurücksetzen
================================ */
function resetTabs() { function resetTabs() {
document document
.querySelectorAll(".tab") .querySelectorAll(".tab")
@ -10,7 +14,6 @@ function resetTabs() {
.querySelectorAll(".tab-content") .querySelectorAll(".tab-content")
.forEach((c) => c.classList.remove("active")); .forEach((c) => c.classList.remove("active"));
// erster Tab aktiv
const firstTab = document.querySelector(".tab"); const firstTab = document.querySelector(".tab");
const firstContent = document.querySelector(".tab-content"); const firstContent = document.querySelector(".tab-content");
@ -18,57 +21,67 @@ function resetTabs() {
if (firstContent) firstContent.classList.add("active"); if (firstContent) firstContent.classList.add("active");
} }
document.querySelectorAll(".building").forEach((b) => { /* ================================
b.addEventListener("click", async (e) => { Gebäude Popup öffnen
================================ */
document.querySelectorAll(".building").forEach((building) => {
building.addEventListener("click", async (e) => {
e.preventDefault(); e.preventDefault();
const name = b.querySelector("title").textContent; try {
const url = b.getAttribute("href"); const name = building.querySelector("title")?.textContent || "Gebäude";
const url = building.getAttribute("href");
title.innerText = name; title.innerText = name;
// Position des Gebäudes popup.style.left = "50%";
const rect = b.getBoundingClientRect(); popup.style.top = "50%";
popup.style.display = "block";
popup.style.left = "50%"; resetTabs();
popup.style.top = "50%";
popup.style.display = "block"; const res = await fetch("/api" + url);
resetTabs();
// AJAX Gebäudedaten laden if (!res.ok) throw new Error("API Fehler");
const res = await fetch("/api" + url);
const data = await res.json();
document.getElementById("tab-info").innerHTML = ` const data = await res.json();
<h3>${data.name}</h3>
<p>Level: ${data.level}</p> document.getElementById("tab-info").innerHTML = `
<p>Punkte: ${data.points} / ${data.nextLevelPoints}</p> <h3>${data.name}</h3>
<p>${data.description}</p> <p>Level: ${data.level}</p>
<div class="progress-bar"> <p>Punkte: ${data.points} / ${data.nextLevelPoints}</p>
<div class="progress-fill" <p>${data.description}</p>
style="width:${(data.points / data.nextLevelPoints) * 100}%"> <div class="progress-bar">
<div class="progress-fill"
style="width:${(data.points / data.nextLevelPoints) * 100}%">
</div>
</div> </div>
</div> `;
`;
document.getElementById("tab-actions").innerHTML = ` document.getElementById("tab-actions").innerHTML = `
<button>Betreten</button> <button>Betreten</button>
<button>Handeln</button> <button>Handeln</button>
`; `;
document.getElementById("tab-upgrade").innerHTML = ` document.getElementById("tab-upgrade").innerHTML = `
<p>Kosten: ${data.upgradeCost}</p> <p>Kosten: ${data.upgradeCost}</p>
<button>Upgrade</button> <button>Upgrade</button>
`; `;
document.getElementById("tab-history").innerHTML = ` document.getElementById("tab-history").innerHTML = `
<p>${data.history}</p> <p>${data.history}</p>
`; `;
} catch (error) {
console.error("Gebäude konnte nicht geladen werden:", error);
}
}); });
}); });
// Tabs /* ================================
Tabs wechseln
================================ */
document.querySelectorAll(".tab").forEach((tab) => { document.querySelectorAll(".tab").forEach((tab) => {
tab.addEventListener("click", () => { tab.addEventListener("click", () => {
document document
@ -84,53 +97,42 @@ document.querySelectorAll(".tab").forEach((tab) => {
}); });
}); });
/* ================================
Popup schließen
================================ */
document.querySelector(".popup-close").onclick = () => { document.querySelector(".popup-close").onclick = () => {
popup.style.display = "none"; popup.style.display = "none";
}; };
async function loadBuilding(buildingId) { /* ================================
try { Tooltip
const res = await fetch("/api/building/" + buildingId); ================================ */
const data = await res.json();
document.getElementById("tab-info").innerHTML = `
<h3>${data.name}</h3>
<p>Level: ${data.level}</p>
<p>Punkte: ${data.points} / ${data.nextLevelPoints}</p>
<p>${data.description}</p>
`;
document.getElementById("tab-upgrade").innerHTML = `
<p>Nächstes Level benötigt:</p>
<p>${data.nextLevelPoints} Punkte</p>
<p>Kosten: ${data.upgradeCost}</p>
`;
document.getElementById("tab-history").innerHTML = `
<p>${data.history}</p>
`;
} catch (err) {
console.error("Fehler beim Laden des Gebäudes:", err);
}
}
document.querySelectorAll(".building").forEach((building) => { document.querySelectorAll(".building").forEach((building) => {
building.addEventListener("mouseenter", async (e) => { building.addEventListener("mouseenter", async (e) => {
const id = building.dataset.id; try {
const id = building.dataset.id;
const res = await fetch("/api/building/" + id); const res = await fetch("/api/building/" + id);
const data = await res.json();
tooltip.innerHTML = ` if (!res.ok) throw new Error("API Fehler");
<strong>${data.name}</strong><br>
Level ${data.level}<br>
Punkte ${data.points}/${data.nextLevelPoints}<br>
<hr>
Upgrade Kosten:<br>
${data.upgradeCost}
`;
tooltip.style.display = "block"; const data = await res.json();
tooltip.innerHTML = `
<strong>${data.name}</strong><br>
Level ${data.level}<br>
Punkte ${data.points}/${data.nextLevelPoints}<br>
<hr>
Upgrade Kosten:<br>
${data.upgradeCost}
`;
tooltip.style.display = "block";
} catch (err) {
console.error("Tooltip Fehler:", err);
}
}); });
building.addEventListener("mousemove", (e) => { building.addEventListener("mousemove", (e) => {

View File

@ -1,23 +1,28 @@
const express = require("express"); const express = require("express");
const router = express.Router(); const router = express.Router();
const auth = require("../middleware/auth");
router.get("/castle", (req, res) => { /* ================================
Gebäude Seiten
================================ */
router.get("/castle", auth, (req, res) => {
res.render("buildings/castle"); res.render("buildings/castle");
}); });
router.get("/market", (req, res) => { router.get("/market", auth, (req, res) => {
res.render("buildings/market"); res.render("buildings/market");
}); });
router.get("/church", (req, res) => { router.get("/church", auth, (req, res) => {
res.render("buildings/church"); res.render("buildings/church");
}); });
router.get("/portal", (req, res) => { router.get("/portal", auth, (req, res) => {
res.render("buildings/portal"); res.render("buildings/portal");
}); });
router.get("/tower", (req, res) => { router.get("/tower", auth, (req, res) => {
res.render("buildings/tower"); res.render("buildings/tower");
}); });

View File

@ -1,11 +1,12 @@
const express = require("express"); const express = require("express");
const router = express.Router(); const router = express.Router();
const auth = require("../middleware/auth");
router.get("/", (req, res) => { /* ================================
if (!req.session.user) { Launcher Seite
return res.redirect("/"); ================================ */
}
router.get("/", auth, (req, res) => {
res.render("launcher", { res.render("launcher", {
character: { character: {
name: req.session.user.username, name: req.session.user.username,
@ -13,8 +14,4 @@ router.get("/", (req, res) => {
}); });
}); });
router.get("/launcher-dev", (req, res) => {
res.render("launcher-dev");
});
module.exports = router; module.exports = router;

View File

@ -2,6 +2,7 @@ const express = require("express");
const router = express.Router(); const router = express.Router();
const db = require("../database/database"); const db = require("../database/database");
const bcrypt = require("bcrypt"); const bcrypt = require("bcrypt");
const crypto = require("crypto");
/* ================================ /* ================================
Login verarbeiten Login verarbeiten
@ -14,6 +15,7 @@ router.post("/", async (req, res) => {
/* Server laden (für index.ejs) */ /* Server laden (für index.ejs) */
const [servers] = await db.query("SELECT * FROM servers"); const [servers] = await db.query("SELECT * FROM servers");
/* User laden */
const [rows] = await db.query( const [rows] = await db.query(
"SELECT * FROM accounts WHERE username = ? AND verified = 1", "SELECT * FROM accounts WHERE username = ? AND verified = 1",
[username], [username],
@ -28,6 +30,7 @@ router.post("/", async (req, res) => {
const user = rows[0]; const user = rows[0];
/* Passwort prüfen */
const passwordMatch = await bcrypt.compare(password, user.password); const passwordMatch = await bcrypt.compare(password, user.password);
if (!passwordMatch) { if (!passwordMatch) {
@ -37,25 +40,41 @@ router.post("/", async (req, res) => {
}); });
} }
/* Session speichern */ /* ================================
Session Token erstellen
================================= */
const sessionToken = crypto.randomBytes(64).toString("hex");
/* Token in DB speichern (überschreibt alten Login) */
await db.query("UPDATE accounts SET session_token = ? WHERE id = ?", [
sessionToken,
user.id,
]);
/* ================================
Session speichern
================================= */
req.session.user = { req.session.user = {
id: user.id, id: user.id,
username: user.username, username: user.username,
token: sessionToken,
}; };
/* Wenn kein Charaktername existiert */ /* ================================
Weiterleitung
================================= */
if (!user.ingame_name) { if (!user.ingame_name) {
return res.redirect("/create-character"); return res.redirect("/create-character");
} }
/* Wenn Charakter existiert */ return res.redirect("/launcher");
res.redirect("/launcher");
} catch (error) { } catch (error) {
console.error(error); console.error("Login Fehler:", error);
res.send("Login Fehler"); res.status(500).send("Serverfehler beim Login");
} }
}); });

View File

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<title>Schloss</title>
<link rel="stylesheet" href="/css/building.css" />
</head>
<body>
<div class="building">
<h1>Schloss</h1>
<p>Hier kannst du deine Charaktere verwalten.</p>
<a class="back" href="/launcher"> Zurück zur Karte </a>
</div>
</body>
</html>

View File

@ -1,7 +0,0 @@
<div class="building">
<h1>Kirche</h1>
<p>Segnungen und Heilungen.</p>
<a href="/launcher">Zurück zur Karte</a>
</div>

View File

@ -1,7 +0,0 @@
<div class="building">
<h1>Marktplatz</h1>
<p>Hier kannst du Items kaufen.</p>
<a href="/launcher">Zurück zur Karte</a>
</div>

View File

@ -1,7 +0,0 @@
<div class="building">
<h1>Portal</h1>
<p>Dungeon Zugang.</p>
<a href="/launcher">Zurück zur Karte</a>
</div>

View File

@ -1,7 +0,0 @@
<div class="building">
<h1>Turm</h1>
<p>PvP Arena.</p>
<a href="/launcher">Zurück zur Karte</a>
</div>