fix(web): Session-ID pro Nutzer statt globalem web-main
Die feste Session "web-main" gehoerte dem ersten Nutzer (lokal: anonymous) -> SSO-Nutzer bekam "Session gehoert einem anderen Nutzer" (403). Die Web-UI leitet die Session jetzt aus /api/me ab (web-<user_id>); ensureSession() wartet vor dem ersten Turn auf /api/me. Asset-Version v4. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
881a5ac2de
commit
6073ba1133
2 changed files with 41 additions and 22 deletions
|
|
@ -1,6 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
const SESSION_ID = "web-main";
|
||||
const $ = (sel) => document.querySelector(sel);
|
||||
|
||||
const messagesEl = $("#messages");
|
||||
|
|
@ -10,28 +9,46 @@ const formEl = $("#prompt-form");
|
|||
const micBtn = $("#mic");
|
||||
|
||||
let busy = false;
|
||||
// Session-ID pro Nutzer (sonst "gehoert einem anderen Nutzer"-Konflikt). Wird aus
|
||||
// /api/me abgeleitet; bis dahin null -> ensureSession() wartet auf loadMe().
|
||||
let sessionId = null;
|
||||
let mePromise = null;
|
||||
|
||||
// ---------- Identitaet / Menue ----------
|
||||
async function loadMe() {
|
||||
try {
|
||||
const res = await fetch("/api/me", { headers: { Accept: "application/json" } });
|
||||
if (!res.ok) {
|
||||
$("#identity").textContent = "Nicht angemeldet";
|
||||
return;
|
||||
function loadMe() {
|
||||
mePromise = (async () => {
|
||||
try {
|
||||
const res = await fetch("/api/me", { headers: { Accept: "application/json" } });
|
||||
if (!res.ok) {
|
||||
$("#identity").textContent = "Nicht angemeldet";
|
||||
return null;
|
||||
}
|
||||
const me = await res.json();
|
||||
sessionId = "web-" + me.user_id;
|
||||
$("#identity").textContent = "Angemeldet als " + (me.display_name || me.external_id || "Gast");
|
||||
if (me.sso_logout_url) {
|
||||
const logout = $("#logout");
|
||||
logout.href = me.sso_logout_url;
|
||||
logout.classList.remove("hidden");
|
||||
}
|
||||
if (me.is_admin) {
|
||||
$("#admin").classList.remove("hidden");
|
||||
}
|
||||
return me;
|
||||
} catch (e) {
|
||||
$("#identity").textContent = "Verbindung fehlgeschlagen";
|
||||
return null;
|
||||
}
|
||||
const me = await res.json();
|
||||
$("#identity").textContent = "Angemeldet als " + (me.display_name || me.external_id || "Gast");
|
||||
if (me.sso_logout_url) {
|
||||
const logout = $("#logout");
|
||||
logout.href = me.sso_logout_url;
|
||||
logout.classList.remove("hidden");
|
||||
}
|
||||
if (me.is_admin) {
|
||||
$("#admin").classList.remove("hidden");
|
||||
}
|
||||
} catch (e) {
|
||||
$("#identity").textContent = "Verbindung fehlgeschlagen";
|
||||
})();
|
||||
return mePromise;
|
||||
}
|
||||
|
||||
// Stellt sicher, dass eine nutzerspezifische Session-ID feststeht, bevor ein Turn startet.
|
||||
async function ensureSession() {
|
||||
if (!sessionId && mePromise) {
|
||||
try { await mePromise; } catch (e) { /* ignore */ }
|
||||
}
|
||||
if (!sessionId) sessionId = "web-anon";
|
||||
}
|
||||
|
||||
async function loadUsers() {
|
||||
|
|
@ -91,7 +108,7 @@ function playPcm(chunks, sampleRate) {
|
|||
// ---------- WS-Turn (Text und Sprache teilen die Event-Logik) ----------
|
||||
function wsUrl(path) {
|
||||
const proto = location.protocol === "https:" ? "wss" : "ws";
|
||||
return `${proto}://${location.host}${path}?session_id=${encodeURIComponent(SESSION_ID)}`;
|
||||
return `${proto}://${location.host}${path}?session_id=${encodeURIComponent(sessionId)}`;
|
||||
}
|
||||
|
||||
// onopen: (ws) => sendet die Eingabe. Liefert ein Promise, das beim done-Event endet.
|
||||
|
|
@ -148,6 +165,7 @@ function runTurn(path, onopen) {
|
|||
async function sendText(text) {
|
||||
if (busy || !text.trim()) return;
|
||||
busy = true;
|
||||
await ensureSession();
|
||||
addMessage("user", text);
|
||||
statusEl.textContent = "denkt …";
|
||||
await runTurn("/ws/chat", (ws) => {
|
||||
|
|
@ -198,6 +216,7 @@ function stopRecording() {
|
|||
async function sendVoice(bytes) {
|
||||
if (busy) return;
|
||||
busy = true;
|
||||
await ensureSession();
|
||||
statusEl.textContent = "verarbeite Sprache …";
|
||||
await runTurn("/ws/voice", (ws) => {
|
||||
ws.send(JSON.stringify({ type: "start", format: "webm", stream: true, audio_stream: true }));
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Voice Assistant</title>
|
||||
<link rel="stylesheet" href="/style.css?v=3" />
|
||||
<link rel="stylesheet" href="/style.css?v=4" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="layout">
|
||||
|
|
@ -31,6 +31,6 @@
|
|||
<div id="status" class="muted"></div>
|
||||
</main>
|
||||
</div>
|
||||
<script src="/app.js?v=3"></script>
|
||||
<script src="/app.js?v=4"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue