fixed rooms with passwd

This commit is contained in:
2026-01-05 02:10:18 +01:00
parent e2345aa20a
commit a9fc4b0ece
4 changed files with 84 additions and 132 deletions

View File

@@ -42,8 +42,7 @@ async function handleWebSocketConnection(connection: any, req: any) {
const token = req.query.token; const token = req.query.token;
const guestName = req.query.guestName; const guestName = req.query.guestName;
const password = req.query.password; const password = req.query.password;
const clientIP = getClientIP(req);
const clientIP = getClientIP(req); // NUEVO
let userId: string; let userId: string;
let username: string; let username: string;
@@ -52,46 +51,21 @@ async function handleWebSocketConnection(connection: any, req: any) {
let realUserId: any; let realUserId: any;
const room = roomService.getRoom(roomId); const room = roomService.getRoom(roomId);
// 1. Validaciones básicas de existencia y Ban
if (!room) { if (!room) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'Room not found' }));
type: 'error',
message: 'Room not found'
}));
socket.close(); socket.close();
return; return;
} }
if (roomService.isIPBanned(roomId, clientIP)) { if (roomService.isIPBanned(roomId, clientIP)) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'You have been banned from this room' }));
type: 'error',
message: 'You have been banned from this room'
}));
socket.close(); socket.close();
return; return;
} }
if (!room) { // 2. MOVIDO ARRIBA: Autenticar usuario PRIMERO para saber quién es
socket.send(JSON.stringify({
type: 'error',
message: 'Room not found'
}));
socket.close();
return;
}
// Verificar contraseña si existe
if (room.password) {
if (!password || !roomService.verifyRoomPassword(roomId, password)) {
socket.send(JSON.stringify({
type: 'error',
message: 'Invalid password'
}));
socket.close();
return;
}
}
// Autenticar usuario o crear invitado
if (token) { if (token) {
try { try {
const decoded: any = jwt.verify(token, process.env.JWT_SECRET!); const decoded: any = jwt.verify(token, process.env.JWT_SECRET!);
@@ -107,50 +81,41 @@ async function handleWebSocketConnection(connection: any, req: any) {
throw new Error('User not found'); throw new Error('User not found');
} }
} catch (err) { } catch (err) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'Invalid token' }));
type: 'error',
message: 'Invalid token'
}));
socket.close(); socket.close();
return; return;
} }
} else if (guestName && guestName.trim()) { } else if (guestName && guestName.trim()) {
// ... (Lógica de Guest se mantiene igual) ...
const nameToCheck = guestName.trim(); const nameToCheck = guestName.trim();
const isNameTaken = Array.from(room.users.values()).some( const isNameTaken = Array.from(room.users.values()).some(
u => u.username.toLowerCase() === nameToCheck.toLowerCase() u => u.username.toLowerCase() === nameToCheck.toLowerCase()
); );
if (isNameTaken) { if (isNameTaken) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'Username is already taken' }));
type: 'error',
message: 'Username is already taken'
}));
socket.close(); socket.close();
return; return;
} }
userId = `guest_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; userId = `guest_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
username = nameToCheck; username = nameToCheck;
isGuest = true; isGuest = true;
} else { } else {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'Authentication required' }));
type: 'error',
message: 'Authentication required'
}));
socket.close(); socket.close();
return; return;
} }
// 3. Determinar si es Host
const isHost = room.host.userId === realUserId || room.host.id === userId; const isHost = room.host.userId === realUserId || room.host.id === userId;
console.log('WebSocket Connection:', { // 4. MOVIDO ABAJO: Validar contraseña SOLO SI NO ES HOST
userId, if (room.password && !isHost) {
realUserId, if (!password || !roomService.verifyRoomPassword(roomId, password)) {
roomHostId: room.host.id, socket.send(JSON.stringify({ type: 'error', message: 'Invalid password' }));
roomHostUserId: room.host.userId, socket.close();
isHost return;
}); }
}
const userInRoom = { const userInRoom = {
id: userId, id: userId,

View File

@@ -15,6 +15,7 @@ const RoomsApp = (function() {
let modalTotalEpisodes = 0; let modalTotalEpisodes = 0;
const MODAL_EPS_PER_PAGE = 50; const MODAL_EPS_PER_PAGE = 50;
let currentQueue = []; let currentQueue = [];
let shouldReconnect = true;
let configState = { let configState = {
extension: null, extension: null,
@@ -160,6 +161,7 @@ const RoomsApp = (function() {
function handleInitialEntry(roomInfo) { function handleInitialEntry(roomInfo) {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
const passwordGroup = document.getElementById('password-group'); const passwordGroup = document.getElementById('password-group');
const guestNameInput = document.getElementById('guest-name-input');
const hostInfoDiv = document.getElementById('join-host-info'); const hostInfoDiv = document.getElementById('join-host-info');
const hostAvatar = document.getElementById('join-host-avatar'); const hostAvatar = document.getElementById('join-host-avatar');
@@ -176,24 +178,31 @@ const RoomsApp = (function() {
passwordGroup.dataset.required = roomInfo.hasPassword ? 'true' : 'false'; passwordGroup.dataset.required = roomInfo.hasPassword ? 'true' : 'false';
} }
if (token && guestNameInput) {
const parentGroup = guestNameInput.closest('.form-group') || guestNameInput;
parentGroup.style.display = 'none';
} else if (guestNameInput) {
const parentGroup = guestNameInput.closest('.form-group') || guestNameInput;
parentGroup.style.display = 'block';
}
window.__roomPublicUrl = roomInfo.publicUrl || null; window.__roomPublicUrl = roomInfo.publicUrl || null;
window.__roomExposed = roomInfo.exposed || false; window.__roomExposed = roomInfo.exposed || false;
console.log('Room info loaded:', {
exposed: window.__roomExposed,
publicUrl: window.__roomPublicUrl
});
if (token) { if (token) {
connectToRoom(currentRoomId); connectToRoom(currentRoomId);
} else { } else {
console.log('Guest user, showing modal...');
if (elements.joinRoomModal) { if (elements.joinRoomModal) {
elements.joinRoomModal.classList.add('show'); elements.joinRoomModal.classList.add('show');
const nameInput = document.getElementById('guest-name-input');
if (nameInput) { if (roomInfo.hasPassword) {
nameInput.value = ''; setTimeout(() => {
setTimeout(() => nameInput.focus(), 100); const passInput = document.getElementById('join-password-input');
if(passInput) passInput.focus();
}, 100);
} else {
setTimeout(() => {
if(guestNameInput) guestNameInput.focus();
}, 100);
} }
} }
} }
@@ -983,6 +992,7 @@ const RoomsApp = (function() {
closeModal(); closeModal();
}); });
function connectToRoom(roomId, guestName, password) { function connectToRoom(roomId, guestName, password) {
shouldReconnect = true;
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
const isTunnel = window.location.hostname.includes('trycloudflare.com'); const isTunnel = window.location.hostname.includes('trycloudflare.com');
@@ -1034,7 +1044,7 @@ const RoomsApp = (function() {
ws.onclose = (event) => { ws.onclose = (event) => {
console.log('WebSocket Disconnected:', event.code, event.reason); console.log('WebSocket Disconnected:', event.code, event.reason);
if (!shouldReconnect) return;
if (window.AnimePlayer && typeof window.AnimePlayer.setWebSocket === 'function') { if (window.AnimePlayer && typeof window.AnimePlayer.setWebSocket === 'function') {
window.AnimePlayer.setWebSocket(null); window.AnimePlayer.setWebSocket(null);
} }
@@ -1115,6 +1125,7 @@ const RoomsApp = (function() {
function handleWebSocketMessage(data) { function handleWebSocketMessage(data) {
switch (data.type) { switch (data.type) {
case 'error': case 'error':
shouldReconnect = false;
handleConnectionError(data.message); handleConnectionError(data.message);
break; break;

View File

@@ -42,8 +42,7 @@ async function handleWebSocketConnection(connection: any, req: any) {
const token = req.query.token; const token = req.query.token;
const guestName = req.query.guestName; const guestName = req.query.guestName;
const password = req.query.password; const password = req.query.password;
const clientIP = getClientIP(req);
const clientIP = getClientIP(req); // NUEVO
let userId: string; let userId: string;
let username: string; let username: string;
@@ -52,46 +51,21 @@ async function handleWebSocketConnection(connection: any, req: any) {
let realUserId: any; let realUserId: any;
const room = roomService.getRoom(roomId); const room = roomService.getRoom(roomId);
// 1. Validaciones básicas de existencia y Ban
if (!room) { if (!room) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'Room not found' }));
type: 'error',
message: 'Room not found'
}));
socket.close(); socket.close();
return; return;
} }
if (roomService.isIPBanned(roomId, clientIP)) { if (roomService.isIPBanned(roomId, clientIP)) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'You have been banned from this room' }));
type: 'error',
message: 'You have been banned from this room'
}));
socket.close(); socket.close();
return; return;
} }
if (!room) { // 2. MOVIDO ARRIBA: Autenticar usuario PRIMERO para saber quién es
socket.send(JSON.stringify({
type: 'error',
message: 'Room not found'
}));
socket.close();
return;
}
// Verificar contraseña si existe
if (room.password) {
if (!password || !roomService.verifyRoomPassword(roomId, password)) {
socket.send(JSON.stringify({
type: 'error',
message: 'Invalid password'
}));
socket.close();
return;
}
}
// Autenticar usuario o crear invitado
if (token) { if (token) {
try { try {
const decoded: any = jwt.verify(token, process.env.JWT_SECRET!); const decoded: any = jwt.verify(token, process.env.JWT_SECRET!);
@@ -107,50 +81,41 @@ async function handleWebSocketConnection(connection: any, req: any) {
throw new Error('User not found'); throw new Error('User not found');
} }
} catch (err) { } catch (err) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'Invalid token' }));
type: 'error',
message: 'Invalid token'
}));
socket.close(); socket.close();
return; return;
} }
} else if (guestName && guestName.trim()) { } else if (guestName && guestName.trim()) {
// ... (Lógica de Guest se mantiene igual) ...
const nameToCheck = guestName.trim(); const nameToCheck = guestName.trim();
const isNameTaken = Array.from(room.users.values()).some( const isNameTaken = Array.from(room.users.values()).some(
u => u.username.toLowerCase() === nameToCheck.toLowerCase() u => u.username.toLowerCase() === nameToCheck.toLowerCase()
); );
if (isNameTaken) { if (isNameTaken) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'Username is already taken' }));
type: 'error',
message: 'Username is already taken'
}));
socket.close(); socket.close();
return; return;
} }
userId = `guest_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; userId = `guest_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
username = nameToCheck; username = nameToCheck;
isGuest = true; isGuest = true;
} else { } else {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ type: 'error', message: 'Authentication required' }));
type: 'error',
message: 'Authentication required'
}));
socket.close(); socket.close();
return; return;
} }
// 3. Determinar si es Host
const isHost = room.host.userId === realUserId || room.host.id === userId; const isHost = room.host.userId === realUserId || room.host.id === userId;
console.log('WebSocket Connection:', { // 4. MOVIDO ABAJO: Validar contraseña SOLO SI NO ES HOST
userId, if (room.password && !isHost) {
realUserId, if (!password || !roomService.verifyRoomPassword(roomId, password)) {
roomHostId: room.host.id, socket.send(JSON.stringify({ type: 'error', message: 'Invalid password' }));
roomHostUserId: room.host.userId, socket.close();
isHost return;
}); }
}
const userInRoom = { const userInRoom = {
id: userId, id: userId,

View File

@@ -15,6 +15,7 @@ const RoomsApp = (function() {
let modalTotalEpisodes = 0; let modalTotalEpisodes = 0;
const MODAL_EPS_PER_PAGE = 50; const MODAL_EPS_PER_PAGE = 50;
let currentQueue = []; let currentQueue = [];
let shouldReconnect = true;
let configState = { let configState = {
extension: null, extension: null,
@@ -160,6 +161,7 @@ const RoomsApp = (function() {
function handleInitialEntry(roomInfo) { function handleInitialEntry(roomInfo) {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
const passwordGroup = document.getElementById('password-group'); const passwordGroup = document.getElementById('password-group');
const guestNameInput = document.getElementById('guest-name-input');
const hostInfoDiv = document.getElementById('join-host-info'); const hostInfoDiv = document.getElementById('join-host-info');
const hostAvatar = document.getElementById('join-host-avatar'); const hostAvatar = document.getElementById('join-host-avatar');
@@ -176,24 +178,31 @@ const RoomsApp = (function() {
passwordGroup.dataset.required = roomInfo.hasPassword ? 'true' : 'false'; passwordGroup.dataset.required = roomInfo.hasPassword ? 'true' : 'false';
} }
if (token && guestNameInput) {
const parentGroup = guestNameInput.closest('.form-group') || guestNameInput;
parentGroup.style.display = 'none';
} else if (guestNameInput) {
const parentGroup = guestNameInput.closest('.form-group') || guestNameInput;
parentGroup.style.display = 'block';
}
window.__roomPublicUrl = roomInfo.publicUrl || null; window.__roomPublicUrl = roomInfo.publicUrl || null;
window.__roomExposed = roomInfo.exposed || false; window.__roomExposed = roomInfo.exposed || false;
console.log('Room info loaded:', {
exposed: window.__roomExposed,
publicUrl: window.__roomPublicUrl
});
if (token) { if (token) {
connectToRoom(currentRoomId); connectToRoom(currentRoomId);
} else { } else {
console.log('Guest user, showing modal...');
if (elements.joinRoomModal) { if (elements.joinRoomModal) {
elements.joinRoomModal.classList.add('show'); elements.joinRoomModal.classList.add('show');
const nameInput = document.getElementById('guest-name-input');
if (nameInput) { if (roomInfo.hasPassword) {
nameInput.value = ''; setTimeout(() => {
setTimeout(() => nameInput.focus(), 100); const passInput = document.getElementById('join-password-input');
if(passInput) passInput.focus();
}, 100);
} else {
setTimeout(() => {
if(guestNameInput) guestNameInput.focus();
}, 100);
} }
} }
} }
@@ -983,6 +992,7 @@ const RoomsApp = (function() {
closeModal(); closeModal();
}); });
function connectToRoom(roomId, guestName, password) { function connectToRoom(roomId, guestName, password) {
shouldReconnect = true;
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
const isTunnel = window.location.hostname.includes('trycloudflare.com'); const isTunnel = window.location.hostname.includes('trycloudflare.com');
@@ -1034,7 +1044,7 @@ const RoomsApp = (function() {
ws.onclose = (event) => { ws.onclose = (event) => {
console.log('WebSocket Disconnected:', event.code, event.reason); console.log('WebSocket Disconnected:', event.code, event.reason);
if (!shouldReconnect) return;
if (window.AnimePlayer && typeof window.AnimePlayer.setWebSocket === 'function') { if (window.AnimePlayer && typeof window.AnimePlayer.setWebSocket === 'function') {
window.AnimePlayer.setWebSocket(null); window.AnimePlayer.setWebSocket(null);
} }
@@ -1115,6 +1125,7 @@ const RoomsApp = (function() {
function handleWebSocketMessage(data) { function handleWebSocketMessage(data) {
switch (data.type) { switch (data.type) {
case 'error': case 'error':
shouldReconnect = false;
handleConnectionError(data.message); handleConnectionError(data.message);
break; break;