Grotti 2.2.0: Auth, API-Tokens, MCP und Doku-Trennung.
This commit is contained in:
1 parent
b20f8a7779
commit
5a3716b26a
65 files changed
+2212
-198
No files matched your search
+24
-4
@@ -1,4 +1,5 @@
|
||||
const TOKEN = document.querySelector('meta[name="token"]')?.content || "";
|
||||
const TOKEN = ""; // Legacy: Auth über Session-Cookie oder Bearer von außen
|
||||
const CSRF = document.querySelector('meta[name="csrf"]')?.content || "";
|
||||
|
||||
const STATE_LABELS = {
|
||||
printing: "druckt", paused: "pausiert", complete: "fertig", standby: "bereit",
|
||||
@@ -17,17 +18,29 @@ function escapeHtml(value) {
|
||||
async function api(path, options = {}) {
|
||||
const headers = new Headers(options.headers || {});
|
||||
if (TOKEN) headers.set("Authorization", "Bearer " + TOKEN);
|
||||
const method = (options.method || "GET").toUpperCase();
|
||||
if (CSRF && method !== "GET" && method !== "HEAD") {
|
||||
headers.set("X-CSRF-Token", CSRF);
|
||||
}
|
||||
let body = options.body;
|
||||
if (options.json !== undefined) {
|
||||
headers.set("Content-Type", "application/json");
|
||||
body = JSON.stringify(options.json);
|
||||
}
|
||||
const response = await fetch("/api/v1" + path, {
|
||||
method: options.method || "GET",
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
cache: "no-store",
|
||||
credentials: "same-origin",
|
||||
});
|
||||
if (response.status === 401) {
|
||||
const here = location.pathname + location.search;
|
||||
if (!here.startsWith("/login") && !here.startsWith("/setup")) {
|
||||
location.href = "/login?next=" + encodeURIComponent(here);
|
||||
}
|
||||
throw new Error("Anmeldung nötig.");
|
||||
}
|
||||
if (!response.ok) {
|
||||
let message = response.statusText;
|
||||
try {
|
||||
@@ -45,8 +58,8 @@ async function api(path, options = {}) {
|
||||
}
|
||||
|
||||
function withToken(url) {
|
||||
if (!url || !TOKEN) return url;
|
||||
return url + (url.includes("?") ? "&" : "?") + "token=" + encodeURIComponent(TOKEN);
|
||||
// Session-Cookie reicht für same-origin Kameras; kein Token in der URL.
|
||||
return url;
|
||||
}
|
||||
|
||||
function euro(value) {
|
||||
@@ -103,6 +116,13 @@ function chipHtml(state, label, small) {
|
||||
return `<span class="chip ${escapeHtml(state || "")}${small ? " sm" : ""}">${escapeHtml(text)}</span>`;
|
||||
}
|
||||
|
||||
function shownState(printer) {
|
||||
const state = (printer && printer.state) || "offline";
|
||||
const hot = ((printer && printer.nozzle_target) || 0) > 40 || ((printer && printer.bed_target) || 0) > 30;
|
||||
if ((state === "standby" || state === "complete") && hot) return "heating";
|
||||
return state;
|
||||
}
|
||||
|
||||
function stepsHtml(labels, index, compact) {
|
||||
if (!labels || !labels.length) return "";
|
||||
const parts = labels.map((label, i) => {
|
||||
|
||||
Reference in new issue
Block a user