oh gott was mach ich nur

This commit is contained in:
2025-11-25 03:21:52 +01:00
parent b8471bff3e
commit 888ab3dfa7
21 changed files with 2664 additions and 794 deletions

View File

@@ -1,25 +1,178 @@
// /public/assets/js/fakecheck.js
// /public/assets/js/fakecheck/fakecheck.serial.js
(function() {
const base = "/assets/js/fakecheck/";
(function () {
if (!window.usbcheck) return;
const scripts = [
base + "core.js?v=1",
base + "fakecheck.browser.js?v=1",
base + "fakecheck.serial.js?v=1"
];
const {
cfg,
t,
tFmt,
log: logLine
} = window.usbcheck;
function loadScript(src) {
return new Promise((resolve, reject) => {
const s = document.createElement("script");
s.src = src;
s.async = false; // Reihenfolge sicherstellen
s.onload = resolve;
s.onerror = () => reject(new Error("Konnte " + src + " nicht laden"));
document.head.appendChild(s);
});
const rootSc = document.getElementById("serialcheck-root");
if (!rootSc) return; // Partial nicht eingebunden → nichts tun
// Elemente
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");
const apiUrl = cfg.apiBase.replace(/\/+$/, "") + "/quickcheck";
// -------------------------------------------------------
// Fehleranzeige
// -------------------------------------------------------
function showScError(msgKey, fallback, vars = {}) {
if (!errorBox) return;
const msg = tFmt(msgKey, fallback, vars);
errorBox.textContent = msg;
errorBox.classList.remove("hidden");
if (resultBox) resultBox.classList.add("hidden");
}
scripts.reduce((p, src) => p.then(() => loadScript(src)), Promise.resolve())
.catch(err => console.error("Fakecheck Loader Fehler:", err));
function clearScError() {
if (!errorBox) return;
errorBox.classList.add("hidden");
errorBox.textContent = "";
}
// -------------------------------------------------------
// Ergebnis rendern
// -------------------------------------------------------
function renderScResult(data) {
if (!resultBox) return;
clearScError();
resultBox.classList.remove("hidden");
const rating = data.rating || "unknown";
const input = data.input || {};
const vendorInfo = data.vendor_detected || {};
const serialInfo = data.serial_analysis || {};
const consistency = data.consistency || {};
// Rating → Label + Beschreibung
const ratingLabel = t(`serial.rating.${rating}.label`, rating);
const ratingDesc = t(`serial.rating.${rating}.desc`, "");
// Auffälligkeiten
const issues = serialInfo.issues || [];
const issuesHtml = 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]">${t("serial.issues_none", "Keine besonderen Auffälligkeiten.")}</span>`;
// Vendor
const vendorLine = vendorInfo.found
? tFmt("serial.vendor_detected", "{vendor} (VID {vid})", {
vendor: vendorInfo.vendor,
vid: vendorInfo.vid
})
: vendorInfo.vid
? tFmt("serial.vendor_unknown", "Unbekannter Hersteller für VID {vid}", { vid: vendorInfo.vid })
: t("serial.vendor_none", "Keine Vendor-ID angegeben");
// Konsistenz-Notizen
const notes = consistency.notes || [];
const notesHtml = notes.length
? '<ul class="list-disc list-inside mt-1 text-[11px]">' +
notes.map(n => `<li>${n}</li>`).join("") +
'</ul>'
: "";
// HTML einsetzen
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" : ""}
">
${t("serial.rating_label", "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">${t("serial.heading_input", "Eingabedaten")}</h3>
<dl class="text-[11px] space-y-1 text-slate-600 dark:text-slate-300">
<div><dt class="font-medium">${t("serial.input.manufacturer", "Hersteller (Angabe):")}</dt><dd>${input.manufacturer || '<span class="text-slate-400">' + t("serial.none", "keine Angabe") + '</span>'}</dd></div>
<div><dt class="font-medium">${t("serial.input.vidpid", "VID/PID:")}</dt><dd>${(input.vid || "") + " / " + (input.pid || "")}</dd></div>
<div><dt class="font-medium">${t("serial.input.vendor_detected", "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">${t("serial.heading_analysis", "Seriennummer-Analyse")}</h3>
<dl class="text-[11px] space-y-1 text-slate-600 dark:text-slate-300">
<div><dt class="font-medium">${t("serial.analysis.serial", "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">${t("serial.analysis.length", "Länge:")}</dt><dd>${serialInfo.length || 0} ${t("serial.chars", "Zeichen")}</dd></div>
<div><dt class="font-medium">${t("serial.analysis.category", "Kategorie:")}</dt><dd>${serialInfo.category || "-"}</dd></div>
<div><dt class="font-medium">${t("serial.analysis.score", "Score:")}</dt><dd>${typeof serialInfo.score === "number" ? serialInfo.score : "-"} / 100</dd></div>
<div><dt class="font-medium">${t("serial.analysis.issues", "Auffälligkeiten:")}</dt><dd>${issuesHtml}</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">${t("serial.heading_consistency", "Hersteller-Konsistenz")}</h3>
${notesHtml}
<p class="mt-2 text-[10px] text-slate-500">
${t("serial.disclaimer", "Diese Einschätzung basiert auf Heuristiken und kann keine Echtheit garantieren.")}
</p>
</div>
`;
}
// -------------------------------------------------------
// Submit-Handler
// -------------------------------------------------------
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("serial.error.no_serial", "Bitte gib eine Seriennummer ein.");
return;
}
fetch(apiUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
})
.then(res => {
if (!res.ok) {
throw new Error("HTTP " + res.status);
}
return res.json();
})
.then(data => {
if (!data || !data.success) {
throw new Error((data && data.error) || t("serial.error.unknown", "Unerwartete Antwort vom Server."));
}
renderScResult(data);
})
.catch(err => {
showScError("serial.error.api", "Fehler bei der Prüfung: {msg}", { msg: err.message });
});
});
})();