mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-07-27 20:39:10 +00:00
Fix: Service Worker persistence, Ping-Pong failsafe, URL parsing, and server rate limit DoS
This commit is contained in:
+14
-1
@@ -280,6 +280,10 @@ function emit(event, data) {
|
||||
socket.send(msg);
|
||||
} else {
|
||||
eventQueue.push({ event, data });
|
||||
if (eventQueue.length > 50) {
|
||||
eventQueue.shift();
|
||||
addLog('Event queue cap reached, dropping oldest event', 'warn');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +437,16 @@ async function routeToContent(action, payload) {
|
||||
}
|
||||
|
||||
// --- Keep-Alive Mechanism ---
|
||||
chrome.alarms.clearAll();
|
||||
chrome.alarms.create('keepAlive', { periodInMinutes: 1 });
|
||||
chrome.alarms.onAlarm.addListener((alarm) => {
|
||||
if (alarm.name === 'keepAlive') {
|
||||
chrome.storage.session.get('keepAlive', () => {});
|
||||
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||
connect();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
// Calling a chrome API keeps the SW alive in MV3 (Chrome 110+)
|
||||
chrome.storage.session.get('keepAlive', () => {});
|
||||
|
||||
+22
-8
@@ -8,6 +8,17 @@
|
||||
window.koalaSyncInjected = true;
|
||||
|
||||
let lastTargetState = null;
|
||||
let targetStateTimeout = null;
|
||||
|
||||
function setTargetState(state) {
|
||||
lastTargetState = state;
|
||||
if (targetStateTimeout) clearTimeout(targetStateTimeout);
|
||||
if (state !== null) {
|
||||
targetStateTimeout = setTimeout(() => {
|
||||
lastTargetState = null;
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Helper: find the best video element on the page ---
|
||||
function findVideo() {
|
||||
@@ -30,7 +41,7 @@
|
||||
if (ytButton) {
|
||||
const isCurrentlyPlaying = !video.paused;
|
||||
if ((action === 'play' && !isCurrentlyPlaying) || (action === 'pause' && isCurrentlyPlaying)) {
|
||||
lastTargetState = action === 'play' ? 'playing' : 'paused';
|
||||
setTargetState(action === 'play' ? 'playing' : 'paused');
|
||||
ytButton.click();
|
||||
}
|
||||
if (action === 'seek') video.currentTime = data.targetTime;
|
||||
@@ -43,7 +54,7 @@
|
||||
if (twitchButton) {
|
||||
const isCurrentlyPlaying = !video.paused;
|
||||
if ((action === 'play' && !isCurrentlyPlaying) || (action === 'pause' && isCurrentlyPlaying)) {
|
||||
lastTargetState = action === 'play' ? 'playing' : 'paused';
|
||||
setTargetState(action === 'play' ? 'playing' : 'paused');
|
||||
twitchButton.click();
|
||||
}
|
||||
if (action === 'seek') video.currentTime = data.targetTime;
|
||||
@@ -53,10 +64,13 @@
|
||||
|
||||
// Fallback for native HTML5
|
||||
if (action === 'play') {
|
||||
lastTargetState = 'playing';
|
||||
video.play().catch(() => {});
|
||||
setTargetState('playing');
|
||||
video.play().catch((e) => {
|
||||
console.warn('KoalaSync playback prevented:', e);
|
||||
setTargetState(null);
|
||||
});
|
||||
} else if (action === 'pause') {
|
||||
lastTargetState = 'paused';
|
||||
setTargetState('paused');
|
||||
video.pause();
|
||||
} else if (action === 'seek') {
|
||||
video.currentTime = data.targetTime;
|
||||
@@ -110,7 +124,7 @@
|
||||
if (!payload || payload.targetTime === undefined) return;
|
||||
const video = findVideo();
|
||||
if (video) {
|
||||
lastTargetState = 'paused';
|
||||
setTargetState('paused');
|
||||
video.pause();
|
||||
video.currentTime = payload.targetTime;
|
||||
pollSeekReady(payload.targetTime).then(() => {
|
||||
@@ -131,11 +145,11 @@
|
||||
const eventState = action === 'play' ? 'playing' : (action === 'pause' ? 'paused' : null);
|
||||
|
||||
if (eventState && lastTargetState === eventState) {
|
||||
lastTargetState = null; // Consume the match
|
||||
setTargetState(null); // Consume the match
|
||||
return; // Ignore event caused by our programmatic action
|
||||
}
|
||||
if (action !== 'seek') {
|
||||
lastTargetState = null; // Reset on mismatch
|
||||
setTargetState(null); // Reset on mismatch
|
||||
}
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
|
||||
+7
-1
@@ -268,7 +268,13 @@ function checkInviteLink() {
|
||||
let serverUrl = '';
|
||||
|
||||
// Smart Link: Parse Server Config if present
|
||||
if (parts.length >= 3 && (parts[parts.length - 2] === '0' || parts[parts.length - 2] === '1')) {
|
||||
const last = parts[parts.length - 1];
|
||||
const secondToLast = parts[parts.length - 2];
|
||||
const decodedLast = decodeURIComponent(last || '');
|
||||
const isCustom = secondToLast === '1' && (decodedLast.startsWith('ws://') || decodedLast.startsWith('wss://'));
|
||||
const isOfficial = secondToLast === '0' && last === '';
|
||||
|
||||
if (parts.length >= 3 && (isCustom || isOfficial)) {
|
||||
serverUrl = decodeURIComponent(parts.pop());
|
||||
useCustomServer = parts.pop() === '1';
|
||||
}
|
||||
|
||||
@@ -148,6 +148,11 @@ io.on('connection', (socket) => {
|
||||
log('CONN', `New connection: ${socket.id} from ${clientIp}`);
|
||||
|
||||
socket.on(EVENTS.JOIN_ROOM, async (payload) => {
|
||||
if (!checkEventRate(socket.id)) {
|
||||
log('SECURITY', `Event rate limit exceeded for socket (JOIN): ${socket.id}`);
|
||||
socket.disconnect(true);
|
||||
return;
|
||||
}
|
||||
if (!payload || typeof payload.roomId !== 'string') return;
|
||||
const { roomId, password, peerId, protocolVersion } = payload;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user