This commit is contained in:
2025-11-24 02:12:49 +01:00
parent 71b0a4c72a
commit b2584bc828
8 changed files with 656 additions and 0 deletions

View File

@@ -4,6 +4,19 @@ document.addEventListener("DOMContentLoaded", () => {
const baseUrl = window.fakecheckBaseUrl || "";
const locale = window.fakecheckLocale || "en";
// Neu: API-Basis-URL (prod/staging) über Config oder Fallback anhand Host
const apiBaseUrl = window.fakecheckApiBaseUrl || detectApiBaseUrl();
function detectApiBaseUrl() {
const host = window.location.hostname || "";
// einfache Heuristik: staging-Domain → staging-API
if (host === "staging.usbcheck.it" || host.endsWith(".staging.usbcheck.it")) {
return "https://api.staging.usbcheck.it";
}
// default: production
return "https://api.usbcheck.it";
}
const root = document.getElementById("fc-root");
if (!root) {
// Auf anderen Seiten eingebunden? Dann einfach nichts tun.
@@ -682,6 +695,168 @@ document.addEventListener("DOMContentLoaded", () => {
}
}
// --- Seriennummer-Quickcheck (API-gestützt) -----------------------------
function initSerialCheckWidget() {
const rootSc = document.getElementById("serialcheck-root");
if (!rootSc) return; // Serialcheck-Partial nicht eingebunden → nichts tun
const form = rootSc.querySelector("#serialcheck-form");
const errorBox = rootSc.querySelector("#serialcheck-error");
const resultBox = rootSc.querySelector("#serialcheck-result");
const manufacturerInput = rootSc.querySelector("#sc-manufacturer");
const vidInput = rootSc.querySelector("#sc-vid");
const pidInput = rootSc.querySelector("#sc-pid");
const serialInput = rootSc.querySelector("#sc-serial");
function showScError(msg) {
if (!errorBox) return;
errorBox.textContent = msg || "Es ist ein Fehler aufgetreten.";
errorBox.classList.remove("hidden");
if (resultBox) resultBox.classList.add("hidden");
}
function clearScError() {
if (!errorBox) return;
errorBox.classList.add("hidden");
errorBox.textContent = "";
}
function renderScResult(data) {
if (!resultBox) return;
clearScError();
resultBox.classList.remove("hidden");
const rating = data.rating || "unknown";
let ratingLabel = "";
let ratingDesc = "";
if (rating === "ok") {
ratingLabel = "Plausibel";
ratingDesc = "Keine deutlichen Auffälligkeiten erkannt.";
} else if (rating === "needs_review") {
ratingLabel = "Überprüfen empfohlen";
ratingDesc = "Leichte Auffälligkeiten. In Kombination mit einem technischen Test ergibt sich ein klareres Bild.";
} else if (rating === "suspicious") {
ratingLabel = "Auffällig / Verdächtig";
ratingDesc = "Deutliche Auffälligkeiten erkannt. Ein Kapazitäts-/Geschwindigkeitstest ist dringend empfohlen.";
} else if (rating === "invalid") {
ratingLabel = "Ungültig";
ratingDesc = "Die Seriennummer konnte nicht sinnvoll bewertet werden.";
} else {
ratingLabel = "Unklar";
ratingDesc = "Bewertung nicht eindeutig möglich.";
}
const input = data.input || {};
const vendorInfo = data.vendor_detected || {};
const serialInfo = data.serial_analysis || {};
const consistency = data.consistency || {};
const issues = serialInfo.issues || [];
const notes = consistency.notes || [];
const issuesList = issues.length
? '<ul class="list-disc list-inside mt-1">' +
issues.map(i => '<li>' + i + '</li>').join("") +
"</ul>"
: '<span class="text-emerald-600 text-[11px]">Keine besonderen Auffälligkeiten.</span>';
const vendorLine = vendorInfo.found
? (vendorInfo.vendor + " (VID " + vendorInfo.vid + ")")
: (vendorInfo.vid ? ("Unbekannter Hersteller für VID " + vendorInfo.vid) : "Keine Vendor-ID angegeben");
const notesList = notes.length
? '<ul class="list-disc list-inside mt-1 text-[11px]">' +
notes.map(n => "<li>" + n + "</li>").join("") +
"</ul>"
: "";
resultBox.innerHTML = `
<div class="mb-3">
<span class="inline-flex items-center rounded-full px-3 py-1 text-[11px] font-semibold
${rating === "ok" ? "bg-emerald-100 text-emerald-800" : ""}
${rating === "needs_review" ? "bg-amber-100 text-amber-800" : ""}
${rating === "suspicious" ? "bg-red-100 text-red-800" : ""}
${rating === "invalid" ? "bg-slate-100 text-slate-700" : ""}
">
Bewertung: ${ratingLabel}
</span>
<p class="mt-1 text-xs text-slate-600 dark:text-slate-300">${ratingDesc}</p>
</div>
<div class="border border-slate-200 dark:border-slate-700 rounded-xl p-3 mb-3">
<h3 class="text-xs font-semibold mb-1 text-slate-800 dark:text-slate-100">Eingabedaten</h3>
<dl class="text-[11px] space-y-1 text-slate-600 dark:text-slate-300">
<div><dt class="font-medium">Hersteller (Angabe):</dt><dd>${input.manufacturer || '<span class="text-slate-400">keine Angabe</span>'}</dd></div>
<div><dt class="font-medium">VID / PID:</dt><dd>${(input.vid || "") + " / " + (input.pid || "")}</dd></div>
<div><dt class="font-medium">Vendor aus VID:</dt><dd>${vendorLine}</dd></div>
</dl>
</div>
<div class="border border-slate-200 dark:border-slate-700 rounded-xl p-3 mb-3">
<h3 class="text-xs font-semibold mb-1 text-slate-800 dark:text-slate-100">Seriennummer-Analyse</h3>
<dl class="text-[11px] space-y-1 text-slate-600 dark:text-slate-300">
<div><dt class="font-medium">Seriennummer:</dt><dd><code class="text-[10px] bg-slate-100 dark:bg-slate-800 px-1.5 py-0.5 rounded">${serialInfo.serial || ""}</code></dd></div>
<div><dt class="font-medium">Länge:</dt><dd>${serialInfo.length || 0} Zeichen</dd></div>
<div><dt class="font-medium">Kategorie:</dt><dd>${serialInfo.category || "-"}</dd></div>
<div><dt class="font-medium">Score:</dt><dd>${typeof serialInfo.score === "number" ? serialInfo.score : "-"} / 100</dd></div>
<div><dt class="font-medium">Auffälligkeiten:</dt><dd>${issuesList}</dd></div>
</dl>
</div>
<div class="border border-slate-200 dark:border-slate-700 rounded-xl p-3">
<h3 class="text-xs font-semibold mb-1 text-slate-800 dark:text-slate-100">Hersteller-Konsistenz</h3>
${notesList}
<p class="mt-2 text-[10px] text-slate-500">
Diese Einschätzung basiert auf Heuristiken und kann keine Echtheit garantieren.
</p>
</div>
`;
}
if (!form) return;
form.addEventListener("submit", (e) => {
e.preventDefault();
clearScError();
if (resultBox) resultBox.classList.add("hidden");
const payload = {
manufacturer: manufacturerInput ? manufacturerInput.value.trim() : "",
vid: vidInput ? vidInput.value.trim() : "",
pid: pidInput ? pidInput.value.trim() : "",
serial: serialInput ? serialInput.value.trim() : ""
};
if (!payload.serial) {
showScError("Bitte gib eine Seriennummer ein.");
return;
}
fetch(apiBaseUrl.replace(/\/+$/, "") + "/quickcheck", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
})
.then(res => {
if (!res.ok) {
throw new Error("Server returned status " + res.status);
}
return res.json();
})
.then(data => {
if (!data || !data.success) {
throw new Error((data && data.error) || "Unerwartete Antwort vom Server.");
}
renderScResult(data);
})
.catch(err => {
showScError("Fehler bei der Prüfung: " + err.message);
});
});
}
// --- Initialzustand -----------------------------------------------------
setStatus("Bereit. Wähle zuerst deinen USB-Stick aus.");
@@ -689,4 +864,7 @@ document.addEventListener("DOMContentLoaded", () => {
setOverallStatus("ok", "Noch kein Test durchgeführt.");
logLine("USB-Browser-Test (fakecheck) geladen. Warte auf Verzeichnisauswahl und Modus.");
updateStartButtonState();
// Serialcheck nur initialisieren, wenn das Partial vorhanden ist
initSerialCheckWidget();
});