From 48af0501d497af0320167ba90478777905177d36 Mon Sep 17 00:00:00 2001 From: HikeMap User Date: Mon, 5 Jan 2026 10:17:22 -0600 Subject: [PATCH] Add server session ID for restart detection + Kickems skill name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Generate unique server session ID on startup - Client detects session ID mismatch on reconnect and forces re-login - Add "Kickems" as Trail Runner's custom name for basic_attack skill 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- database.js | 1 + index.html | 32 ++++++++++++++++++++++++++++++-- server.js | 15 +++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/database.js b/database.js index 0b1c734..757ab3d 100644 --- a/database.js +++ b/database.js @@ -1452,6 +1452,7 @@ class HikeMapDB { // Seed Trail Runner class skill names const trailRunnerSkillNames = [ + { skillId: 'basic_attack', classId: 'trail_runner', customName: 'Kickems', customDescription: 'A swift kick from your trusty trail shoes!' }, { skillId: 'double_attack', classId: 'trail_runner', customName: 'Brand New Hokas', customDescription: 'Break in those fresh kicks with two quick strikes!' }, { skillId: 'power_strike', classId: 'trail_runner', customName: 'Downhill Sprint', customDescription: 'Use gravity to deliver a devastating blow!' }, { skillId: 'heal', classId: 'trail_runner', customName: 'Gel Pack', customDescription: 'Quick energy gel restores your stamina' }, diff --git a/index.html b/index.html index 800fb64..567df9b 100644 --- a/index.html +++ b/index.html @@ -6499,7 +6499,8 @@ if (currentUser && currentUser.id) { ws.send(JSON.stringify({ type: 'auth', - authUserId: currentUser.id + authUserId: currentUser.id, + serverSessionId: sessionStorage.getItem('serverSessionId') })); } @@ -6522,6 +6523,32 @@ switch (data.type) { case 'init': userId = data.userId; + // Check if server restarted (session ID changed) + const storedSessionId = sessionStorage.getItem('serverSessionId'); + if (storedSessionId && data.serverSessionId && storedSessionId !== data.serverSessionId) { + console.log('[WS] Server restarted - session ID mismatch, forcing re-login'); + // Clear auth and show login + localStorage.removeItem('accessToken'); + localStorage.removeItem('currentUser'); + currentUser = null; + playerStats = null; + statsLoadedFromServer = false; + document.getElementById('rpgHud').style.display = 'none'; + document.getElementById('deathOverlay').style.display = 'none'; + stopMonsterSpawning(); + if (homeBaseMarker) { + map.removeLayer(homeBaseMarker); + homeBaseMarker = null; + } + sessionStorage.setItem('serverSessionId', data.serverSessionId); + document.getElementById('authModal').style.display = 'flex'; + updateStatus('Server restarted - please log in again', 'info'); + break; + } + // Store server session ID for future checks + if (data.serverSessionId) { + sessionStorage.setItem('serverSessionId', data.serverSessionId); + } // Add existing users if (data.users) { data.users.forEach(user => { @@ -10204,7 +10231,8 @@ if (ws && ws.readyState === WebSocket.OPEN && currentUser && currentUser.id) { ws.send(JSON.stringify({ type: 'auth', - authUserId: currentUser.id + authUserId: currentUser.id, + serverSessionId: sessionStorage.getItem('serverSessionId') })); console.log('Registered auth user', currentUser.id, 'with WebSocket'); } diff --git a/server.js b/server.js index 4765c8a..abd28ec 100644 --- a/server.js +++ b/server.js @@ -48,6 +48,10 @@ const app = express(); const server = http.createServer(app); const wss = new WebSocket.Server({ server }); +// Server session ID - changes on each restart, used to force client re-auth +const serverSessionId = require('crypto').randomBytes(16).toString('hex'); +console.log(`Server session ID: ${serverSessionId.substring(0, 8)}...`); + // Middleware to parse JSON and raw body for KML app.use(express.json()); app.use(express.text({ type: 'application/xml', limit: '10mb' })); @@ -2137,6 +2141,7 @@ wss.on('connection', (ws) => { const initMsg = { type: 'init', userId: userId, + serverSessionId: serverSessionId, // For detecting server restarts users: Array.from(users.entries()) .filter(([id, data]) => data.visible !== false) // Only send visible users .map(([id, data]) => ({ @@ -2163,6 +2168,16 @@ wss.on('connection', (ws) => { const data = JSON.parse(message); if (data.type === 'auth') { + // Check if client has a stale session (server restarted) + if (data.serverSessionId && data.serverSessionId !== serverSessionId) { + console.log(`[SESSION] User ${data.authUserId} has stale session ID, forcing logout`); + ws.send(JSON.stringify({ + type: 'force_logout', + reason: 'Server restarted - please log in again' + })); + return; + } + // Register authenticated user's WebSocket connection if (data.authUserId) { // Check if this user already has an active connection (old tab)