Initial commit: Veritas Suite Main Server and Core Engine
This commit is contained in:
@@ -0,0 +1,472 @@
|
||||
// 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!");
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user