473 lines
19 KiB
JavaScript
473 lines
19 KiB
JavaScript
// Veritas Suite Web Portal App Logic
|
|
|
|
const API_BASE = "";
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
checkServerHealth();
|
|
restoreSession();
|
|
fetchDownloads();
|
|
|
|
// Check if we are on admin page
|
|
if (window.location.pathname === "/admin" || window.location.pathname.endsWith("admin.html")) {
|
|
checkAdminPageSession();
|
|
}
|
|
});
|
|
|
|
// Check Server Connection
|
|
async function checkServerHealth() {
|
|
const indicator = document.querySelector(".status-indicator");
|
|
const statusText = document.getElementById("status-text");
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/health`);
|
|
if (response.ok) {
|
|
if (indicator) indicator.classList.add("online");
|
|
if (statusText) statusText.textContent = "VPS Server: Online (200 OK)";
|
|
} else {
|
|
if (statusText) statusText.textContent = "VPS Server: Fehler";
|
|
}
|
|
} catch (e) {
|
|
if (statusText) statusText.textContent = "VPS Server: Offline";
|
|
}
|
|
}
|
|
|
|
// Filter Sparten Tools
|
|
function filterSparten(category) {
|
|
document.querySelectorAll(".filter-btn").forEach(btn => btn.classList.remove("active"));
|
|
|
|
const activeBtn = Array.from(document.querySelectorAll(".filter-btn")).find(btn =>
|
|
btn.getAttribute("onclick") && btn.getAttribute("onclick").includes(`'${category}'`)
|
|
);
|
|
if (activeBtn) activeBtn.classList.add("active");
|
|
|
|
const cards = document.querySelectorAll(".tool-card");
|
|
cards.forEach(card => {
|
|
if (category === "all" || card.getAttribute("data-sparte") === category) {
|
|
card.style.display = "flex";
|
|
} else {
|
|
card.style.display = "none";
|
|
}
|
|
});
|
|
}
|
|
|
|
// Restore Session from LocalStorage
|
|
function restoreSession() {
|
|
const sessionStr = localStorage.getItem("veritas_session");
|
|
if (sessionStr) {
|
|
try {
|
|
const session = JSON.parse(sessionStr);
|
|
if (session && session.user_id) {
|
|
showLoggedInState(session);
|
|
} else {
|
|
showLoggedOutState();
|
|
}
|
|
} catch (e) {
|
|
localStorage.removeItem("veritas_session");
|
|
showLoggedOutState();
|
|
}
|
|
} else {
|
|
showLoggedOutState();
|
|
}
|
|
}
|
|
|
|
function showLoggedInState(session) {
|
|
const loggedOutDiv = document.getElementById("dash-logged-out");
|
|
const loggedInDiv = document.getElementById("dash-logged-in");
|
|
const userEmailSpan = document.getElementById("dash-user-email");
|
|
const userStatusBar = document.getElementById("user-status-bar");
|
|
const authForms = document.getElementById("auth-forms-container");
|
|
const navAdminLink = document.getElementById("nav-admin-link");
|
|
const btnAdminPanel = document.getElementById("btn-admin-panel");
|
|
|
|
if (loggedOutDiv) loggedOutDiv.style.display = "none";
|
|
if (loggedInDiv) loggedInDiv.style.display = "block";
|
|
if (userEmailSpan) userEmailSpan.textContent = session.email;
|
|
if (userStatusBar) userStatusBar.style.display = "inline-flex";
|
|
if (authForms) authForms.style.display = "none";
|
|
|
|
// Show Admin Buttons ONLY if logged-in user is an Admin
|
|
if (session.is_admin) {
|
|
if (navAdminLink) navAdminLink.style.display = "inline-flex";
|
|
if (btnAdminPanel) btnAdminPanel.style.display = "inline-block";
|
|
} else {
|
|
if (navAdminLink) navAdminLink.style.display = "none";
|
|
if (btnAdminPanel) btnAdminPanel.style.display = "none";
|
|
}
|
|
|
|
refreshDashboard();
|
|
}
|
|
|
|
function showLoggedOutState() {
|
|
const loggedOutDiv = document.getElementById("dash-logged-out");
|
|
const loggedInDiv = document.getElementById("dash-logged-in");
|
|
const userStatusBar = document.getElementById("user-status-bar");
|
|
const authForms = document.getElementById("auth-forms-container");
|
|
const navAdminLink = document.getElementById("nav-admin-link");
|
|
const btnAdminPanel = document.getElementById("btn-admin-panel");
|
|
|
|
if (loggedOutDiv) loggedOutDiv.style.display = "block";
|
|
if (loggedInDiv) loggedInDiv.style.display = "none";
|
|
if (userStatusBar) userStatusBar.style.display = "none";
|
|
if (authForms) authForms.style.display = "grid";
|
|
if (navAdminLink) navAdminLink.style.display = "none";
|
|
if (btnAdminPanel) btnAdminPanel.style.display = "none";
|
|
}
|
|
|
|
function logout() {
|
|
localStorage.removeItem("veritas_session");
|
|
showLoggedOutState();
|
|
showAlert("Erfolgreich abgemeldet.", "success");
|
|
if (window.location.pathname === "/admin" || window.location.pathname.endsWith("admin.html")) {
|
|
window.location.href = "/portal";
|
|
}
|
|
}
|
|
|
|
// Handle Customer Registration
|
|
async function handleRegister(event) {
|
|
event.preventDefault();
|
|
const email = document.getElementById("reg-email").value;
|
|
const password = document.getElementById("reg-password").value;
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/auth/register`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ email, password })
|
|
});
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showAlert(data.message, "success");
|
|
const session = { user_id: data.user_id, email: data.email, token: data.auth_token, is_admin: data.is_admin };
|
|
localStorage.setItem("veritas_session", JSON.stringify(session));
|
|
showLoggedInState(session);
|
|
} else {
|
|
showAlert(data.message, "error");
|
|
}
|
|
} catch (e) {
|
|
showAlert("Netzwerkfehler bei der Registrierung.", "error");
|
|
}
|
|
}
|
|
|
|
// Handle Customer & Admin Login in Portal
|
|
async function handleLogin(event) {
|
|
event.preventDefault();
|
|
const email = document.getElementById("login-email").value;
|
|
const password = document.getElementById("login-password").value;
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/auth/login`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ email, password })
|
|
});
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showAlert(data.message, "success");
|
|
const session = { user_id: data.user_id, email: data.email, token: data.auth_token, is_admin: data.is_admin };
|
|
localStorage.setItem("veritas_session", JSON.stringify(session));
|
|
showLoggedInState(session);
|
|
|
|
if (data.is_admin) {
|
|
showAlert("👑 Willkommen Admin! Du hast Zugriff auf die Admin-Zentrale.", "success");
|
|
}
|
|
} else {
|
|
showAlert(data.message, "error");
|
|
}
|
|
} catch (e) {
|
|
showAlert("Netzwerkfehler beim Anmelden.", "error");
|
|
}
|
|
}
|
|
|
|
// Check Admin Page Session (Requires Admin Login in Customer Portal)
|
|
function checkAdminPageSession() {
|
|
const sessionStr = localStorage.getItem("veritas_session");
|
|
const loggedOutState = document.getElementById("admin-logged-out-state");
|
|
const loggedInState = document.getElementById("admin-logged-in-state");
|
|
const userEmailDisplay = document.getElementById("admin-user-email-display");
|
|
|
|
if (sessionStr) {
|
|
try {
|
|
const session = JSON.parse(sessionStr);
|
|
if (session && session.is_admin) {
|
|
if (loggedOutState) loggedOutState.style.display = "none";
|
|
if (loggedInState) loggedInState.style.display = "block";
|
|
if (userEmailDisplay) userEmailDisplay.textContent = session.email;
|
|
fetchAdminStats();
|
|
return;
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
|
|
if (loggedOutState) loggedOutState.style.display = "block";
|
|
if (loggedInState) loggedInState.style.display = "none";
|
|
}
|
|
|
|
function logoutAdmin() {
|
|
logout();
|
|
}
|
|
|
|
// Refresh Customer Dashboard Data
|
|
async function refreshDashboard() {
|
|
const sessionStr = localStorage.getItem("veritas_session");
|
|
if (!sessionStr) return;
|
|
|
|
const session = JSON.parse(sessionStr);
|
|
const container = document.getElementById("license-list");
|
|
if (!container) return;
|
|
container.innerHTML = "<p style='color:#94a3b8;'>Lizenzen werden geladen...</p>";
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/account/dashboard?user_id=${session.user_id}`);
|
|
const data = await response.json();
|
|
|
|
if (data.success && data.licenses && data.licenses.length > 0) {
|
|
container.innerHTML = "";
|
|
data.licenses.forEach(lic => {
|
|
const percent = Math.min(100, (lic.activated_devices / lic.max_devices) * 100);
|
|
const cardHtml = `
|
|
<div class="lic-card glass-panel" style="background: rgba(24, 34, 53, 0.7); padding: 1.25rem; border-radius: 12px; border: 1px solid rgba(255,255,255,0.08); margin-bottom: 1rem;">
|
|
<div class="lic-top" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem;">
|
|
<span class="lic-plan" style="font-weight: 700; color: #fff; font-size: 1.1rem;">🛡️ ${lic.plan_name}</span>
|
|
<span class="status-badge ${lic.active ? 'badge-active' : 'badge-planned'}" style="padding: 4px 10px; border-radius: 6px; font-size: 0.8rem; font-weight: 600;">${lic.active ? '🟢 AKTIV' : '🔴 GESPERRT'}</span>
|
|
</div>
|
|
<div class="lic-key-row" style="display: flex; align-items: center; justify-content: space-between; background: rgba(3, 7, 18, 0.6); padding: 10px 14px; border-radius: 8px; margin-bottom: 0.75rem;">
|
|
<code style="font-family: monospace; color: #38bdf8; font-size: 1.05rem;">${lic.license_key}</code>
|
|
<button class="btn btn-glass btn-small" onclick="copyKey('${lic.license_key}')">📋 Kopieren</button>
|
|
</div>
|
|
<div>
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 4px;">
|
|
<small style="color: #94a3b8;">Aktivierte Geräte</small>
|
|
<small style="color: #6366f1; font-weight: 600;">${lic.activated_devices} / ${lic.max_devices} Geräte</small>
|
|
</div>
|
|
<div class="progress-bg" style="background: rgba(255,255,255,0.1); height: 8px; border-radius: 4px; overflow: hidden;">
|
|
<div class="progress-fill" style="width: ${percent}%; background: linear-gradient(90deg, #6366f1, #34d399); height: 100%;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
container.innerHTML += cardHtml;
|
|
|
|
const simKeyInput = document.getElementById("sim-key");
|
|
if (simKeyInput) simKeyInput.value = lic.license_key;
|
|
});
|
|
} else {
|
|
container.innerHTML = "<p style='color:#94a3b8;'>Keine aktiven Lizenzen für dieses Konto gefunden.</p>";
|
|
}
|
|
} catch (e) {
|
|
container.innerHTML = "<p class='error' style='color:#f87171;'>Fehler beim Laden des Dashboards.</p>";
|
|
}
|
|
}
|
|
|
|
// Fetch Software Downloads
|
|
async function fetchDownloads() {
|
|
const container = document.getElementById("downloads-container");
|
|
if (!container) return;
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/downloads/list`);
|
|
const items = await response.json();
|
|
|
|
container.innerHTML = "";
|
|
items.forEach(item => {
|
|
const card = `
|
|
<div class="tool-card glass-panel">
|
|
<div class="card-top">
|
|
<span class="sparte-tag tag-cura">${item.category}</span>
|
|
<span class="status-badge ${item.is_available ? 'badge-active' : 'badge-planned'}">${item.version}</span>
|
|
</div>
|
|
<h3>${item.name}</h3>
|
|
<p class="tool-desc">${item.description}</p>
|
|
<div class="card-footer" style="justify-content: space-between; align-items: center;">
|
|
<span class="tech-tag">Größe: ${item.file_size}</span>
|
|
${item.is_available ?
|
|
`<a class="btn btn-emerald btn-small" href="${item.download_url}" download>📥 Download .exe</a>` :
|
|
`<button class="btn btn-glass btn-small" disabled style="opacity:0.5">Demnächst</button>`}
|
|
</div>
|
|
</div>
|
|
`;
|
|
container.innerHTML += card;
|
|
});
|
|
} catch (e) {
|
|
container.innerHTML = "<p>Fehler beim Laden der Download-Liste.</p>";
|
|
}
|
|
}
|
|
|
|
// Fetch Admin Stats (Sends Authorization Bearer token)
|
|
async function fetchAdminStats() {
|
|
const sessionStr = localStorage.getItem("veritas_session");
|
|
if (!sessionStr) return;
|
|
const session = JSON.parse(sessionStr);
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/admin/stats`, {
|
|
headers: {
|
|
"Authorization": `Bearer ${session.token}`
|
|
}
|
|
});
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
const usersEl = document.getElementById("admin-stat-users");
|
|
const licsEl = document.getElementById("admin-stat-licenses");
|
|
const actsEl = document.getElementById("admin-stat-activations");
|
|
|
|
if (usersEl) usersEl.textContent = data.total_users;
|
|
if (licsEl) licsEl.textContent = data.total_licenses;
|
|
if (actsEl) actsEl.textContent = data.total_activations;
|
|
|
|
const tbody = document.getElementById("admin-licenses-table-body");
|
|
if (tbody) {
|
|
tbody.innerHTML = "";
|
|
data.licenses.forEach(lic => {
|
|
const tr = `
|
|
<tr style="border-bottom: 1px solid rgba(255,255,255,0.05);">
|
|
<td style="padding: 12px;">#${lic.id}</td>
|
|
<td style="padding: 12px;"><code style="color:#38bdf8">${lic.license_key}</code></td>
|
|
<td style="padding: 12px;">${lic.user_email || 'Gast / System'}</td>
|
|
<td style="padding: 12px;">${lic.plan_name}</td>
|
|
<td style="padding: 12px;">${lic.activated_devices} / ${lic.max_devices}</td>
|
|
<td style="padding: 12px;"><span class="status-badge ${lic.active ? 'badge-active' : 'badge-planned'}">${lic.active ? '🟢 AKTIV' : '🔴 GESPERRT'}</span></td>
|
|
<td style="padding: 12px;">
|
|
<button class="btn btn-small ${lic.active ? 'btn-outline-danger' : 'btn-emerald'}" onclick="toggleLicense('${lic.license_key}', ${!lic.active})">
|
|
${lic.active ? '🚫 Sperren' : '✅ Freischalten'}
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
tbody.innerHTML += tr;
|
|
});
|
|
}
|
|
} else {
|
|
showAdminAlert("Zugriff verweigert: " + (data.message || "Admin Privilegien erforderlich"), "error");
|
|
}
|
|
} catch (e) {
|
|
console.error("Admin stats fetch failed", e);
|
|
}
|
|
}
|
|
|
|
// Admin Create License Handler (Sends Authorization Bearer token)
|
|
async function handleAdminCreateLicense(event) {
|
|
event.preventDefault();
|
|
const sessionStr = localStorage.getItem("veritas_session");
|
|
if (!sessionStr) return;
|
|
const session = JSON.parse(sessionStr);
|
|
|
|
const userId = parseInt(document.getElementById("admin-create-uid").value);
|
|
const planName = document.getElementById("admin-create-plan").value;
|
|
const maxDevices = parseInt(document.getElementById("admin-create-max").value);
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/admin/create-license`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Authorization": `Bearer ${session.token}`
|
|
},
|
|
body: JSON.stringify({ user_id: userId, plan_name: planName, max_devices: maxDevices })
|
|
});
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showAdminAlert("Lizenz erfolgreich erstellt: " + data.message, "success");
|
|
fetchAdminStats();
|
|
} else {
|
|
showAdminAlert("Fehler: " + data.message, "error");
|
|
}
|
|
} catch (e) {
|
|
showAdminAlert("Netzwerkfehler beim Erstellen der Lizenz.", "error");
|
|
}
|
|
}
|
|
|
|
// Admin Toggle License Active/Deactive (Sends Authorization Bearer token)
|
|
async function toggleLicense(licenseKey, newActiveState) {
|
|
const sessionStr = localStorage.getItem("veritas_session");
|
|
if (!sessionStr) return;
|
|
const session = JSON.parse(sessionStr);
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/admin/toggle-license`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Authorization": `Bearer ${session.token}`
|
|
},
|
|
body: JSON.stringify({ license_key: licenseKey, active: newActiveState })
|
|
});
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showAdminAlert("Lizenz-Status aktualisiert.", "success");
|
|
fetchAdminStats();
|
|
} else {
|
|
showAdminAlert("Fehler: " + data.message, "error");
|
|
}
|
|
} catch (e) {
|
|
showAdminAlert("Netzwerkfehler beim Ändern des Lizenzstatus.", "error");
|
|
}
|
|
}
|
|
|
|
// Handle Activation Test
|
|
async function handleTestActivation(event) {
|
|
event.preventDefault();
|
|
const licenseKey = document.getElementById("sim-key").value;
|
|
const hardwareId = document.getElementById("sim-hwid").value;
|
|
const appName = document.getElementById("sim-app").value;
|
|
|
|
const outputBox = document.getElementById("sim-output-box");
|
|
const jsonText = document.getElementById("sim-json-text");
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/activate`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
license_key: licenseKey,
|
|
hardware_id: hardwareId,
|
|
app_name: appName
|
|
})
|
|
});
|
|
const data = await response.json();
|
|
|
|
outputBox.style.display = "block";
|
|
jsonText.textContent = JSON.stringify(data, null, 2);
|
|
|
|
refreshDashboard();
|
|
} catch (e) {
|
|
outputBox.style.display = "block";
|
|
jsonText.textContent = "Fehler bei der Kommunikation mit dem VPS Server.";
|
|
}
|
|
}
|
|
|
|
// Helper: Show Alert for Customer Portal
|
|
function showAlert(msg, type) {
|
|
const box = document.getElementById("auth-alert");
|
|
if (!box) return;
|
|
box.textContent = msg;
|
|
box.className = `alert-box ${type}`;
|
|
box.style.display = "block";
|
|
setTimeout(() => {
|
|
box.style.display = "none";
|
|
}, 5000);
|
|
}
|
|
|
|
// Helper: Show Alert for Admin Portal
|
|
function showAdminAlert(msg, type) {
|
|
const box = document.getElementById("admin-alert");
|
|
if (!box) return;
|
|
box.textContent = msg;
|
|
box.className = `alert-box ${type}`;
|
|
box.style.display = "block";
|
|
setTimeout(() => {
|
|
box.style.display = "none";
|
|
}, 5000);
|
|
}
|
|
|
|
// Helper: Copy Key
|
|
function copyKey(text) {
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
alert("Lizenzschlüssel in die Zwischenablage kopiert!");
|
|
});
|
|
}
|