mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-15 21:03:47 +00:00
fix: auth failed electron
This commit is contained in:
@@ -24,39 +24,6 @@ const activeSessions = new Map<string, SSHSession>();
|
|||||||
const wss = new WebSocketServer({
|
const wss = new WebSocketServer({
|
||||||
host: "0.0.0.0",
|
host: "0.0.0.0",
|
||||||
port: 30009,
|
port: 30009,
|
||||||
verifyClient: async (info) => {
|
|
||||||
try {
|
|
||||||
let token: string | undefined;
|
|
||||||
|
|
||||||
const cookieHeader = info.req.headers.cookie;
|
|
||||||
if (cookieHeader) {
|
|
||||||
const match = cookieHeader.match(/(?:^|;\s*)jwt=([^;]+)/);
|
|
||||||
if (match) token = decodeURIComponent(match[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
const authHeader = info.req.headers.authorization;
|
|
||||||
if (authHeader?.startsWith("Bearer ")) {
|
|
||||||
token = authHeader.slice("Bearer ".length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const authManager = AuthManager.getInstance();
|
|
||||||
const decoded = await authManager.verifyJWTToken(token);
|
|
||||||
|
|
||||||
if (!decoded || !decoded.userId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function detectShell(
|
async function detectShell(
|
||||||
|
|||||||
@@ -434,52 +434,6 @@ async function createJumpHostChain(
|
|||||||
|
|
||||||
const wss = new WebSocketServer({
|
const wss = new WebSocketServer({
|
||||||
port: 30002,
|
port: 30002,
|
||||||
verifyClient: async (info) => {
|
|
||||||
try {
|
|
||||||
let token: string | undefined;
|
|
||||||
|
|
||||||
const cookieHeader = info.req.headers.cookie;
|
|
||||||
if (cookieHeader) {
|
|
||||||
const match = cookieHeader.match(/(?:^|;\s*)jwt=([^;]+)/);
|
|
||||||
if (match) token = decodeURIComponent(match[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
const authHeader = info.req.headers.authorization;
|
|
||||||
if (authHeader?.startsWith("Bearer ")) {
|
|
||||||
token = authHeader.slice("Bearer ".length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payload = await authManager.verifyJWTToken(token);
|
|
||||||
|
|
||||||
if (!payload) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (payload.pendingTOTP) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const existingConnections = userConnections.get(payload.userId);
|
|
||||||
|
|
||||||
if (existingConnections && existingConnections.size >= 10) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
sshLogger.error("WebSocket authentication error", error, {
|
|
||||||
operation: "websocket_auth_error",
|
|
||||||
ip: info.req.socket.remoteAddress,
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
wss.on("connection", async (ws: WebSocket, req) => {
|
wss.on("connection", async (ws: WebSocket, req) => {
|
||||||
|
|||||||
+13
-2
@@ -8,7 +8,7 @@ import "./ui/i18n/i18n";
|
|||||||
import { isElectron } from "@/lib/electron";
|
import { isElectron } from "@/lib/electron";
|
||||||
import { Toaster } from "@/components/sonner";
|
import { Toaster } from "@/components/sonner";
|
||||||
import { Auth, getStoredAuth, clearStoredAuth } from "@/auth/Auth";
|
import { Auth, getStoredAuth, clearStoredAuth } from "@/auth/Auth";
|
||||||
import { getUserInfo, appReadyPromise } from "@/main-axios";
|
import { getUserInfo, getCurrentToken, appReadyPromise } from "@/main-axios";
|
||||||
import { applyAccentColor, applyFontSize } from "@/lib/theme";
|
import { applyAccentColor, applyFontSize } from "@/lib/theme";
|
||||||
import type { FontSizeId } from "@/types/ui-types";
|
import type { FontSizeId } from "@/types/ui-types";
|
||||||
import { useServiceWorker } from "@/hooks/use-service-worker";
|
import { useServiceWorker } from "@/hooks/use-service-worker";
|
||||||
@@ -130,11 +130,22 @@ function App() {
|
|||||||
|
|
||||||
// Verify stored session against the server before rendering AppShell.
|
// Verify stored session against the server before rendering AppShell.
|
||||||
// Wait for API instances to be initialized with correct embedded/server config first.
|
// Wait for API instances to be initialized with correct embedded/server config first.
|
||||||
|
// In Electron, also repopulate localStorage["jwt"] so WebSocket connections can auth
|
||||||
|
// after a session restore (the token is only written to localStorage during a fresh login).
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (phase !== "verifying") return;
|
if (phase !== "verifying") return;
|
||||||
appReadyPromise
|
appReadyPromise
|
||||||
.then(() => getUserInfo())
|
.then(() => getUserInfo())
|
||||||
.then(() => setPhase("idle-app"))
|
.then(() => {
|
||||||
|
if (isElectron()) {
|
||||||
|
getCurrentToken()
|
||||||
|
.then((token) => {
|
||||||
|
if (token) localStorage.setItem("jwt", token);
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
setPhase("idle-app");
|
||||||
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
clearStoredAuth();
|
clearStoredAuth();
|
||||||
setPhase("idle-auth");
|
setPhase("idle-auth");
|
||||||
|
|||||||
Reference in New Issue
Block a user