feat: role-aware presence bar, WebSocket logging fixes
- findAdminByKey returns role from admins.json (defaults to 'admin') - JWT includes config-defined role instead of hardcoded 'admin' - PresenceBar split into "who's here?" (page admins) and "connected" (bot/utility services with icon+color badges) - Bot/utility roles appear in presence on all pages when connected - usePresence hook uses refs to avoid WS reconnect on navigation - WS auth log prints admin name instead of generic 'admin' - WS connection log reads X-Forwarded-For for real client IP - AuthContext stores adminRole from login response - Uncomment admins.json Docker volume mount, add SELinux :z flags Made-with: Cursor
This commit is contained in:
@@ -26,13 +26,17 @@ class WebSocketManager {
|
||||
* Handle new WebSocket connection
|
||||
*/
|
||||
handleConnection(ws, req) {
|
||||
console.log('[WebSocket] New connection from', req.socket.remoteAddress);
|
||||
const clientIp = req.headers['x-forwarded-for']?.split(',')[0]?.trim()
|
||||
|| req.headers['x-real-ip']
|
||||
|| req.socket.remoteAddress;
|
||||
console.log('[WebSocket] New connection from', clientIp);
|
||||
|
||||
// Initialize client info
|
||||
const clientInfo = {
|
||||
authenticated: false,
|
||||
userId: null,
|
||||
adminName: null,
|
||||
role: null,
|
||||
currentPage: null,
|
||||
subscribedSessions: new Set(),
|
||||
lastPing: Date.now()
|
||||
@@ -130,6 +134,7 @@ class WebSocketManager {
|
||||
clientInfo.authenticated = true;
|
||||
clientInfo.userId = decoded.role;
|
||||
clientInfo.adminName = decoded.name || null;
|
||||
clientInfo.role = decoded.role || 'admin';
|
||||
|
||||
if (!decoded.name) {
|
||||
this.sendError(ws, 'Token missing admin identity, please re-login', 'auth_error');
|
||||
@@ -141,7 +146,8 @@ class WebSocketManager {
|
||||
message: 'Authenticated successfully'
|
||||
});
|
||||
|
||||
console.log('[WebSocket] Client authenticated:', clientInfo.userId);
|
||||
console.log('[WebSocket] Client authenticated:', clientInfo.adminName);
|
||||
this.broadcastPresence();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[WebSocket] Authentication failed:', err.message);
|
||||
@@ -299,7 +305,7 @@ class WebSocketManager {
|
||||
});
|
||||
|
||||
this.clients.delete(ws);
|
||||
console.log('[WebSocket] Client disconnected and cleaned up');
|
||||
console.log('[WebSocket] Client disconnected:', clientInfo.adminName || 'unauthenticated');
|
||||
this.broadcastPresence();
|
||||
}
|
||||
}
|
||||
@@ -307,8 +313,12 @@ class WebSocketManager {
|
||||
broadcastPresence() {
|
||||
const admins = [];
|
||||
this.clients.forEach((info) => {
|
||||
if (info.authenticated && info.adminName && info.currentPage) {
|
||||
admins.push({ name: info.adminName, page: info.currentPage });
|
||||
if (!info.authenticated || !info.adminName) return;
|
||||
const role = info.role || 'admin';
|
||||
if (role === 'bot' || role === 'utility') {
|
||||
admins.push({ name: info.adminName, role, page: null });
|
||||
} else if (info.currentPage) {
|
||||
admins.push({ name: info.adminName, role, page: info.currentPage });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user