v1.8.0 #429

Merged
LukeGus merged 198 commits from dev-1.8.0 into main 2025-11-05 16:36:16 +00:00
4 changed files with 80 additions and 22 deletions
Showing only changes of commit 4b078821c3 - Show all commits

View File

@@ -2358,8 +2358,9 @@ router.delete("/sessions/:sessionId", authenticateJWT, async (req, res) => {
operation: "session_revoke",
sessionId,
revokedBy: userId,
sessionUserId: session.userId,
});
res.json({ message: "Session revoked successfully" });
res.json({ success: true, message: "Session revoked successfully" });
} else {
res.status(500).json({ error: "Failed to revoke session" });
}

View File

@@ -267,6 +267,11 @@ class AuthManager {
.limit(1);
if (sessionRecords.length === 0) {
databaseLogger.warn("Session not found during JWT verification", {
operation: "jwt_verify_session_not_found",
sessionId: payload.sessionId,
userId: payload.userId,
});
return null;
}
} catch (dbError) {
@@ -278,6 +283,7 @@ class AuthManager {
sessionId: payload.sessionId,
},
);
return null;
}
}
return payload;
@@ -299,6 +305,22 @@ class AuthManager {
try {
await db.delete(sessions).where(eq(sessions.id, sessionId));
try {
const { saveMemoryDatabaseToFile } = await import(
"../database/db/index.js"
);
await saveMemoryDatabaseToFile();
} catch (saveError) {
databaseLogger.error(
"Failed to save database after session revocation",
saveError,
{
operation: "session_revoke_db_save_failed",
sessionId,
},
);
}
return true;
} catch (error) {
databaseLogger.error("Failed to delete session", error, {
@@ -336,6 +358,22 @@ class AuthManager {
await db.delete(sessions).where(eq(sessions.userId, userId));
}
try {
const { saveMemoryDatabaseToFile } = await import(
"../database/db/index.js"
);
await saveMemoryDatabaseToFile();
} catch (saveError) {
databaseLogger.error(
"Failed to save database after revoking all user sessions",
saveError,
{
operation: "user_sessions_revoke_db_save_failed",
userId,
},
);
}
return deletedCount;
} catch (error) {
databaseLogger.error("Failed to delete user sessions", error, {
@@ -440,6 +478,11 @@ class AuthManager {
.limit(1);
if (sessionRecords.length === 0) {
databaseLogger.warn("Session not found in middleware", {
operation: "middleware_session_not_found",
sessionId: payload.sessionId,
userId: payload.userId,
});
return res.status(401).json({
error: "Session not found",
code: "SESSION_NOT_FOUND",
@@ -479,10 +522,11 @@ class AuthManager {
});
});
} catch (error) {
databaseLogger.error("Session check failed", error, {
operation: "session_check_failed",
databaseLogger.error("Session check failed in middleware", error, {
operation: "middleware_session_check_failed",
sessionId: payload.sessionId,
});
return res.status(500).json({ error: "Session check failed" });
}
}

View File

@@ -12,6 +12,10 @@ import { Auth } from "@/ui/mobile/authentication/Auth.tsx";
import { useTranslation } from "react-i18next";
import { Toaster } from "@/components/ui/sonner.tsx";
function isReactNativeWebView(): boolean {
return typeof window !== "undefined" && !!(window as any).ReactNativeWebView;
}
const AppContent: FC = () => {
const { t } = useTranslation();
const { tabs, currentTab, getTab } = useTabs();
@@ -114,7 +118,7 @@ const AppContent: FC = () => {
);
}
if (!isAuthenticated) {
if (!isAuthenticated || isReactNativeWebView()) {
return (
<div className="h-screen w-screen flex items-center justify-center bg-dark-bg p-4">
<Auth

View File

@@ -239,7 +239,6 @@ export function Auth({
const [meRes] = await Promise.all([getUserInfo()]);
setLoggedIn(true);
setIsAdmin(!!meRes.is_admin);
setUsername(meRes.username || null);
setUserId(meRes.userId || null);
@@ -252,6 +251,7 @@ export function Auth({
return;
}
setLoggedIn(true);
onAuthSuccess({
isAdmin: !!meRes.is_admin,
username: meRes.username || null,
@@ -411,7 +411,6 @@ export function Auth({
localStorage.setItem("jwt", res.token);
}
setLoggedIn(true);
setIsAdmin(!!res.is_admin);
setUsername(res.username || null);
setUserId(res.userId || null);
@@ -425,6 +424,7 @@ export function Auth({
return;
}
setLoggedIn(true);
onAuthSuccess({
isAdmin: !!res.is_admin,
username: res.username || null,
@@ -506,7 +506,6 @@ export function Auth({
getUserInfo()
.then((meRes) => {
setLoggedIn(true);
setIsAdmin(!!meRes.is_admin);
setUsername(meRes.username || null);
setUserId(meRes.userId || null);
@@ -524,6 +523,7 @@ export function Auth({
return;
}
setLoggedIn(true);
onAuthSuccess({
isAdmin: !!meRes.is_admin,
username: meRes.username || null,
@@ -578,21 +578,14 @@ export function Auth({
</svg>
);
return (
<div
className={`w-full max-w-md flex flex-col bg-dark-bg overflow-y-auto my-2 ${className || ""}`}
style={{ maxHeight: "calc(100vh - 1rem)" }}
{...props}
>
{isReactNativeWebView() && !mobileAuthSuccess && (
<Alert className="mb-4 border-blue-500 bg-blue-500/10">
<Smartphone className="h-4 w-4" />
<AlertTitle>{t("auth.mobileApp")}</AlertTitle>
<AlertDescription>{t("auth.loggingInToMobileApp")}</AlertDescription>
</Alert>
)}
{isReactNativeWebView() && mobileAuthSuccess && (
<div className="flex flex-col items-center justify-center h-64 gap-4">
if (isReactNativeWebView() && mobileAuthSuccess) {
return (
<div
className={`w-full max-w-md flex flex-col bg-dark-bg overflow-y-auto my-2 ${className || ""}`}
style={{ maxHeight: "calc(100vh - 1rem)" }}
{...props}
>
<div className="flex flex-col items-center justify-center min-h-[400px] gap-4 px-4">
<div className="w-16 h-16 rounded-full bg-green-500/20 flex items-center justify-center">
<svg
className="w-10 h-10 text-green-500"
@@ -617,6 +610,22 @@ export function Auth({
</p>
</div>
</div>
</div>
);
}
return (
<div
className={`w-full max-w-md flex flex-col bg-dark-bg overflow-y-auto my-2 ${className || ""}`}
style={{ maxHeight: "calc(100vh - 1rem)" }}
{...props}
>
{isReactNativeWebView() && !mobileAuthSuccess && (
<Alert className="mb-4 border-blue-500 bg-blue-500/10">
<Smartphone className="h-4 w-4" />
<AlertTitle>{t("auth.mobileApp")}</AlertTitle>
<AlertDescription>{t("auth.loggingInToMobileApp")}</AlertDescription>
</Alert>
)}
{!mobileAuthSuccess && error && (
<Alert variant="destructive" className="mb-4">