Refactor: Comprehensive Security and Architecture Audit

This commit is contained in:
Timo
2026-04-22 09:49:23 +02:00
parent ffbd80881a
commit 37ead94f76
4 changed files with 65 additions and 23 deletions
+29 -6
View File
@@ -11,6 +11,13 @@ let currentTabId = null;
let currentTabTitle = null; // New: for Smart Matching
let logs = [];
let history = []; // New: for Action History
// Restore state from session storage
chrome.storage.session.get(['logs', 'history'], (data) => {
if (data.logs) logs = data.logs;
if (data.history) history = data.history;
});
let reconnectTimer = null;
let reconnectStartTime = null; // New: track when reconnection started
let reconnectFailed = false; // New: true if we hit the 5-min cap
@@ -51,6 +58,7 @@ function addLog(message, type = 'info') {
};
logs.unshift(log);
if (logs.length > 50) logs.pop();
chrome.storage.session.set({ logs });
chrome.runtime.sendMessage({ type: 'LOG_UPDATE', log }).catch(() => {});
}
@@ -84,8 +92,9 @@ async function connect() {
// Strict WSS Enforcement
const urlObj = new URL(finalUrl);
const isLocal = urlObj.hostname === 'localhost' || urlObj.hostname === '127.0.0.1';
if (!isLocal && urlObj.protocol === 'ws:') {
finalUrl = finalUrl.replace('ws://', 'wss://');
if (urlObj.protocol !== 'wss:' && !isLocal) {
urlObj.protocol = 'wss:';
finalUrl = urlObj.toString();
addLog('Security: Upgraded to wss:// for remote host.', 'warn');
}
}
@@ -253,6 +262,7 @@ function addToHistory(action, senderId) {
};
history.unshift(historyEntry);
if (history.length > 20) history.pop();
chrome.storage.session.set({ history });
chrome.runtime.sendMessage({ type: 'HISTORY_UPDATE', history }).catch(() => {});
}
@@ -304,9 +314,9 @@ function handleServerEvent(event, data) {
if (isForceSyncInitiator) {
forceSyncAcks.add(data.senderId);
addLog(`Received ACK from ${data.senderId} (${forceSyncAcks.size})`, 'info');
// Check if all peers responded (minus ourselves)
// Check if all peers responded
const peerCount = currentRoom ? currentRoom.peers.length : 1;
if (forceSyncAcks.size >= peerCount - 1) {
if (forceSyncAcks.size >= peerCount) {
executeForceSync();
}
}
@@ -390,7 +400,7 @@ async function routeToContent(action, payload) {
}
// --- Keep-Alive Mechanism ---
chrome.alarms.create('keepAlive', { periodInMinutes: 0.25 }); // every 15s
chrome.alarms.create('keepAlive', { periodInMinutes: 1 }); // every 1m
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'keepAlive') {
// console.log('SW KeepAlive Heartbeat');
@@ -448,6 +458,10 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
isForceSyncInitiator = true;
forceSyncAcks.clear();
addLog('Initiating Force Sync...', 'info');
// Route to our own content script so we pause and seek
routeToContent(EVENTS.FORCE_SYNC_PREPARE, message.payload);
// Timeout if not everyone ACKs
forceSyncTimeout = setTimeout(() => {
if (isForceSyncInitiator) {
@@ -459,7 +473,16 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
addToHistory(message.action, 'You');
emit(message.action, { ...message.payload, peerId });
} else if (message.type === 'FORCE_SYNC_ACK') {
emit(EVENTS.FORCE_SYNC_ACK, { peerId });
if (isForceSyncInitiator) {
forceSyncAcks.add(peerId);
addLog(`Local ACK received (${forceSyncAcks.size})`, 'info');
const peerCount = currentRoom ? currentRoom.peers.length : 1;
if (forceSyncAcks.size >= peerCount) {
executeForceSync();
}
} else {
emit(EVENTS.FORCE_SYNC_ACK, { peerId });
}
} else if (message.type === 'HEARTBEAT') {
if (sender.tab) {
currentTabId = sender.tab.id;
+7 -9
View File
@@ -29,8 +29,7 @@
if (isYouTube) {
const ytButton = document.querySelector('.ytp-play-button');
if (ytButton) {
const title = ytButton.getAttribute('aria-label') || '';
const isCurrentlyPlaying = title.toLowerCase().includes('pause');
const isCurrentlyPlaying = !video.paused;
if ((action === 'play' && !isCurrentlyPlaying) || (action === 'pause' && isCurrentlyPlaying)) {
ytButton.click();
}
@@ -42,9 +41,7 @@
if (isTwitch) {
const twitchButton = document.querySelector('[data-a-target="player-play-pause-button"]');
if (twitchButton) {
const label = twitchButton.getAttribute('aria-label')?.toLowerCase() || '';
// Check for common localized labels (pause, stoppen, arrête)
const isCurrentlyPlaying = label.includes('pause') || label.includes('stoppen') || label.includes('arrête');
const isCurrentlyPlaying = !video.paused;
if ((action === 'play' && !isCurrentlyPlaying) || (action === 'pause' && isCurrentlyPlaying)) {
twitchButton.click();
}
@@ -145,16 +142,17 @@
}
// SPA Navigation Handler (MutationObserver)
let mutationTimeout = null;
let lastMutate = 0;
const observer = new MutationObserver(() => {
if (mutationTimeout) clearTimeout(mutationTimeout);
mutationTimeout = setTimeout(() => {
const now = Date.now();
if (now - lastMutate >= 1000) {
lastMutate = now;
const video = findVideo();
if (video && !video.dataset.koalaAttached) {
console.log('KoalaSync: New video detected via navigation.');
setupListeners();
}
}, 1000); // 1s debounce
}
});
observer.observe(document.body, { childList: true, subtree: true });
+28 -8
View File
@@ -404,15 +404,35 @@ elements.forceSyncBtn.addEventListener('click', async () => {
const settings = await chrome.storage.sync.get(['targetTabId']);
if (!settings.targetTabId) return;
chrome.tabs.sendMessage(parseInt(settings.targetTabId), { action: 'get_current_time' }, (response) => {
if (response && response.currentTime !== undefined) {
const time = parseFloat(response.currentTime);
chrome.runtime.sendMessage({
type: 'CONTENT_EVENT',
action: EVENTS.FORCE_SYNC_PREPARE,
payload: { targetTime: time }
const tabId = parseInt(settings.targetTabId);
const sendForceSync = (time) => {
chrome.runtime.sendMessage({
type: 'CONTENT_EVENT',
action: EVENTS.FORCE_SYNC_PREPARE,
payload: { targetTime: parseFloat(time) }
});
};
chrome.tabs.sendMessage(tabId, { action: 'get_current_time' }, (response) => {
if (chrome.runtime.lastError || !response || response.currentTime === undefined) {
chrome.scripting.executeScript({
target: { tabId },
files: ['content.js']
}).then(() => {
setTimeout(() => {
chrome.tabs.sendMessage(tabId, { action: 'get_current_time' }, (retryResponse) => {
if (retryResponse && retryResponse.currentTime !== undefined) {
sendForceSync(retryResponse.currentTime);
}
});
}, 500);
}).catch(() => {
showError('Could not connect to video tab.');
});
return;
}
sendForceSync(response.currentTime);
});
});
@@ -450,7 +470,7 @@ async function refreshLogs() {
if (logs) {
elements.logList.innerHTML = logs.map(log => `
<div class="log-entry log-${log.type}">
[${log.timestamp.split('T')[1].split('.')[0]}] ${log.message}
[${log.timestamp.split('T')[1].split('.')[0]}] ${escapeHtml(log.message)}
</div>
`).join('');
}
+1
View File
@@ -138,6 +138,7 @@ io.on('connection', (socket) => {
log('CONN', `New connection: ${socket.id} from ${clientIp}`);
socket.on(EVENTS.JOIN_ROOM, async ({ roomId, password, peerId, protocolVersion }) => {
if (typeof roomId !== 'string') return;
try {
// Protocol check
if (protocolVersion !== '1.0.0') {