Browse Source

Add server session ID for restart detection + Kickems skill name

- 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 <noreply@anthropic.com>
master
HikeMap User 1 month ago
parent
commit
48af0501d4
  1. 1
      database.js
  2. 32
      index.html
  3. 15
      server.js

1
database.js

@ -1452,6 +1452,7 @@ class HikeMapDB {
// Seed Trail Runner class skill names // Seed Trail Runner class skill names
const trailRunnerSkillNames = [ 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: '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: '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' }, { skillId: 'heal', classId: 'trail_runner', customName: 'Gel Pack', customDescription: 'Quick energy gel restores your stamina' },

32
index.html

@ -6499,7 +6499,8 @@
if (currentUser && currentUser.id) { if (currentUser && currentUser.id) {
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: 'auth', type: 'auth',
authUserId: currentUser.id
authUserId: currentUser.id,
serverSessionId: sessionStorage.getItem('serverSessionId')
})); }));
} }
@ -6522,6 +6523,32 @@
switch (data.type) { switch (data.type) {
case 'init': case 'init':
userId = data.userId; 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 // Add existing users
if (data.users) { if (data.users) {
data.users.forEach(user => { data.users.forEach(user => {
@ -10204,7 +10231,8 @@
if (ws && ws.readyState === WebSocket.OPEN && currentUser && currentUser.id) { if (ws && ws.readyState === WebSocket.OPEN && currentUser && currentUser.id) {
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: 'auth', type: 'auth',
authUserId: currentUser.id
authUserId: currentUser.id,
serverSessionId: sessionStorage.getItem('serverSessionId')
})); }));
console.log('Registered auth user', currentUser.id, 'with WebSocket'); console.log('Registered auth user', currentUser.id, 'with WebSocket');
} }

15
server.js

@ -48,6 +48,10 @@ const app = express();
const server = http.createServer(app); const server = http.createServer(app);
const wss = new WebSocket.Server({ server }); 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 // Middleware to parse JSON and raw body for KML
app.use(express.json()); app.use(express.json());
app.use(express.text({ type: 'application/xml', limit: '10mb' })); app.use(express.text({ type: 'application/xml', limit: '10mb' }));
@ -2137,6 +2141,7 @@ wss.on('connection', (ws) => {
const initMsg = { const initMsg = {
type: 'init', type: 'init',
userId: userId, userId: userId,
serverSessionId: serverSessionId, // For detecting server restarts
users: Array.from(users.entries()) users: Array.from(users.entries())
.filter(([id, data]) => data.visible !== false) // Only send visible users .filter(([id, data]) => data.visible !== false) // Only send visible users
.map(([id, data]) => ({ .map(([id, data]) => ({
@ -2163,6 +2168,16 @@ wss.on('connection', (ws) => {
const data = JSON.parse(message); const data = JSON.parse(message);
if (data.type === 'auth') { 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 // Register authenticated user's WebSocket connection
if (data.authUserId) { if (data.authUserId) {
// Check if this user already has an active connection (old tab) // Check if this user already has an active connection (old tab)

Loading…
Cancel
Save