fix
All checks were successful
/ upload (release) Successful in 21s

This commit is contained in:
pavel 2026-02-24 21:58:25 +01:00
commit 1ec1ba0028
4 changed files with 192 additions and 30 deletions

View file

@ -110,15 +110,53 @@ const el = {
// --- API Helpers ---
async function api(path, options = {}) {
const res = await fetch(path, {
const headers = {
"content-type": "application/json",
...(options.headers || {}),
};
const token = localStorage.getItem("chattz_token");
if (token) {
headers["Authorization"] = `Bearer ${token}`;
}
let res = await fetch(path, {
...options,
headers: {
"content-type": "application/json",
...(options.headers || {}),
},
credentials: "same-origin",
headers,
});
// Handle 401 Unauthorized via Refresh Token
if (res.status === 401 && !path.includes('/auth/refresh')) {
const refreshToken = localStorage.getItem("chattz_refresh_token");
if (refreshToken) {
try {
const refreshRes = await fetch('/auth/refresh', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken })
});
if (refreshRes.ok) {
const newTokens = await refreshRes.json();
localStorage.setItem("chattz_token", newTokens.access_token);
localStorage.setItem("chattz_refresh_token", newTokens.refresh_token);
// Retry original request with new token
headers["Authorization"] = `Bearer ${newTokens.access_token}`;
res = await fetch(path, { ...options, headers });
} else {
// Both tokens invalid/expired
throw new Error("Refresh token expired or invalid");
}
} catch (err) {
localStorage.removeItem("chattz_token");
localStorage.removeItem("chattz_refresh_token");
location.href = "/auth/login";
throw new Error("Session expired, please log in again");
}
}
}
if (!res.ok) {
let detail = "request failed";
try {
@ -523,7 +561,11 @@ function startVoicePresencePolling() {
function initChatWs() {
if (state.chatWs) state.chatWs.close();
const protocol = location.protocol === "https:" ? "wss:" : "ws:";
const wsUrl = `${protocol}//${location.host}/ws`;
let wsUrl = `${protocol}//${location.host}/ws`;
const token = localStorage.getItem("chattz_token");
if (token) {
wsUrl += (wsUrl.includes('?') ? '&' : '?') + `token=${token}`;
}
const ws = new WebSocket(wsUrl);
state.chatWs = ws;
@ -567,7 +609,12 @@ function initChatWs() {
function getVoiceWsUrl(channelId) {
const proto = location.protocol === "https:" ? "wss" : "ws";
return `${proto}://${location.host}/channels/${channelId}/voice/ws`;
let urlStr = `${proto}://${location.host}/channels/${channelId}/voice/ws`;
const token = localStorage.getItem("chattz_token");
if (token) {
urlStr += (urlStr.includes('?') ? '&' : '?') + `token=${token}`;
}
return urlStr;
}
function shouldInitiateOffer(peerId) {
@ -1159,9 +1206,14 @@ async function init() {
try {
const searchParams = new URLSearchParams(location.search);
const jwtToken = searchParams.get("token");
if (jwtToken) {
localStorage.setItem("chattz_token", jwtToken);
const refreshToken = searchParams.get("refresh_token");
if (jwtToken || refreshToken) {
if (jwtToken) localStorage.setItem("chattz_token", jwtToken);
if (refreshToken) localStorage.setItem("chattz_refresh_token", refreshToken);
searchParams.delete("token");
searchParams.delete("refresh_token");
const nextQuery = searchParams.toString();
const nextUrl = `${location.pathname}${nextQuery ? `?${nextQuery}` : ""}`;
history.replaceState(null, "", nextUrl);
@ -1175,6 +1227,7 @@ async function init() {
el.logoutBtn.onclick = async () => {
await leaveVoice();
localStorage.removeItem("chattz_token");
localStorage.removeItem("chattz_refresh_token");
try { await api("/auth/logout", { method: "POST" }); } catch (e) { }
location.reload();
};