fix(extension): harden title privacy edge cases

This commit is contained in:
Timo
2026-06-29 13:43:10 +02:00
parent 4f1335242c
commit e555906553
16 changed files with 99 additions and 68 deletions
+20 -2
View File
@@ -391,6 +391,19 @@ function withTitlePrivacy(payload, settings, keys) {
return applyTitlePrivacyToPayload(payload, settings?.titlePrivacyMode, keys);
}
function emitEpisodeLobbyForCurrentPrivacy() {
if (!episodeLobby || episodeLobby.initiatorPeerId !== peerId) return;
getSettings().then(settings => {
if (!episodeLobby || episodeLobby.initiatorPeerId !== peerId) return;
const expectedTitle = sanitizeSharedTitle(episodeLobby.expectedTitle, settings.titlePrivacyMode);
if (expectedTitle) {
emit(EVENTS.EPISODE_LOBBY, { peerId, expectedTitle });
}
}).catch(err => {
addLog('Episode lobby privacy error: ' + err.message, 'error');
});
}
// Privacy + correctness: only onboardingComplete and dismissedHints belong in
// storage.sync. Everything else is per-device local storage. This actively
// removes legacy keys that older versions wrote to sync (and that would
@@ -1256,7 +1269,7 @@ function handleServerEvent(event, data) {
}
if (episodeLobby && episodeLobby.initiatorPeerId === peerId) {
emit(EVENTS.EPISODE_LOBBY, { peerId, expectedTitle: episodeLobby.expectedTitle });
emitEpisodeLobbyForCurrentPrivacy();
}
}
} else if (data.status === 'left') {
@@ -1637,7 +1650,6 @@ chrome.alarms.onAlarm.addListener(async (alarm) => {
status: 'heartbeat',
username: settings.username,
tabTitle: sharedTitles.tabTitle,
mediaTitle: sharedTitles.mediaTitle,
desynced: hcmDesynced
});
}
@@ -2330,6 +2342,12 @@ async function handleAsyncMessage(message, sender, sendResponse) {
sendResponse({ status: 'ok' });
} else if (message.type === 'TITLE_PRIVACY_CHANGED') {
const settings = await getSettings();
if (episodeLobby && episodeLobby.initiatorPeerId === peerId) {
const nextLobbyTitle = sanitizeSharedTitle(episodeLobby.expectedTitle, settings.titlePrivacyMode);
if (!nextLobbyTitle || nextLobbyTitle !== episodeLobby.expectedTitle) {
cancelEpisodeLobby('Title privacy changed');
}
}
if (currentRoom && settings.titlePrivacyMode === 'hidden') {
const sharedTitles = getSharedTitleFields(settings);
emit(EVENTS.PEER_STATUS, {
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Reiniciar tutorial",
"BTN_RESTART_TOUR_TOOLTIP": "Reiniciar el tutorial de inicio",
"HINT_SELECT_VIDEO": "¡Selecciona tu video aquí!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "T?tulos compartidos",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Elige c?mo se comparten los t?tulos de pesta?a y multimedia con la sala. El modo oculto borra los t?tulos del servidor y desactiva la creaci?n de salas de episodio desde tu cliente.",
"OPTION_TITLE_PRIVACY_FULL": "T?tulos completos",
"OPTION_TITLE_PRIVACY_EPISODE": "Solo episodio",
"OPTION_TITLE_PRIVACY_HIDDEN": "Ocultos"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Redémarrer le tutoriel",
"BTN_RESTART_TOUR_TOOLTIP": "Recommencer le tutoriel d'intégration",
"HINT_SELECT_VIDEO": "Sélectionnez votre vidéo ici !",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "Titres partag?s",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choisissez comment les titres des onglets et des m?dias sont partag?s avec le salon. Le mode masqu? efface les titres du serveur et d?sactive la cr?ation de salons d??pisode depuis votre client.",
"OPTION_TITLE_PRIVACY_FULL": "Titres complets",
"OPTION_TITLE_PRIVACY_EPISODE": "?pisode seulement",
"OPTION_TITLE_PRIVACY_HIDDEN": "Masqu?s"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Riavvia Tutorial",
"BTN_RESTART_TOUR_TOOLTIP": "Riavvia il tutorial introduttivo",
"HINT_SELECT_VIDEO": "Scegli il tuo video qui!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "Titoli condivisi",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Scegli come condividere con la stanza i titoli delle schede e dei contenuti multimediali. La modalit? nascosta cancella i titoli sul server e disattiva la creazione di lobby episodio dal tuo client.",
"OPTION_TITLE_PRIVACY_FULL": "Titoli completi",
"OPTION_TITLE_PRIVACY_EPISODE": "Solo episodio",
"OPTION_TITLE_PRIVACY_HIDDEN": "Nascosti"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "チュートリアルを再起動",
"BTN_RESTART_TOUR_TOOLTIP": "オンボーディングチュートリアルを再起動する",
"HINT_SELECT_VIDEO": "ここで動画を選択してください!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "??????",
"LABEL_TITLE_PRIVACY_TOOLTIP": "???????????????????????????????????????????????????????????????????????????????????",
"OPTION_TITLE_PRIVACY_FULL": "???????",
"OPTION_TITLE_PRIVACY_EPISODE": "???????",
"OPTION_TITLE_PRIVACY_HIDDEN": "???"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "튜토리얼 다시 시작",
"BTN_RESTART_TOUR_TOOLTIP": "온보딩 튜토리얼을 다시 시작합니다",
"HINT_SELECT_VIDEO": "여기에서 비디오를 선택하세요!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "?? ??",
"LABEL_TITLE_PRIVACY_TOOLTIP": "? ??? ??? ??? ?? ??? ???? ?????. ?? ??? ??? ??? ??? ? ??????? ???? ??? ??? ??? ???.",
"OPTION_TITLE_PRIVACY_FULL": "?? ??",
"OPTION_TITLE_PRIVACY_EPISODE": "?????",
"OPTION_TITLE_PRIVACY_HIDDEN": "??"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Tutorial opnieuw starten",
"BTN_RESTART_TOUR_TOOLTIP": "Start de introductie-tutorial opnieuw",
"HINT_SELECT_VIDEO": "Selecteer hier je video!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "Gedeelde titels",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Kies hoe tab- en mediatitels met de kamer worden gedeeld. Verborgen modus wist titels op de server en schakelt het maken van afleveringslobby?s vanaf jouw client uit.",
"OPTION_TITLE_PRIVACY_FULL": "Volledige titels",
"OPTION_TITLE_PRIVACY_EPISODE": "Alleen aflevering",
"OPTION_TITLE_PRIVACY_HIDDEN": "Verborgen"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Uruchom samouczek ponownie",
"BTN_RESTART_TOUR_TOOLTIP": "Uruchom ponownie samouczek powitalny",
"HINT_SELECT_VIDEO": "Wybierz swoje wideo tutaj!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "Udost?pniane tytu?y",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Wybierz, jak tytu?y kart i multimedi?w s? udost?pniane w pokoju. Tryb ukryty czy?ci tytu?y na serwerze i wy??cza tworzenie poczekalni odcinka z tego klienta.",
"OPTION_TITLE_PRIVACY_FULL": "Pe?ne tytu?y",
"OPTION_TITLE_PRIVACY_EPISODE": "Tylko odcinek",
"OPTION_TITLE_PRIVACY_HIDDEN": "Ukryte"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Reiniciar tutorial",
"BTN_RESTART_TOUR_TOOLTIP": "Reiniciar o tutorial de introdução",
"HINT_SELECT_VIDEO": "Selecione seu vídeo aqui!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "T?tulos compartilhados",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Escolha como os t?tulos da aba e da m?dia s?o compartilhados com a sala. O modo oculto limpa os t?tulos no servidor e desativa a cria??o de lobby de epis?dio pelo seu cliente.",
"OPTION_TITLE_PRIVACY_FULL": "T?tulos completos",
"OPTION_TITLE_PRIVACY_EPISODE": "S? epis?dio",
"OPTION_TITLE_PRIVACY_HIDDEN": "Ocultos"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Reiniciar Tutorial",
"BTN_RESTART_TOUR_TOOLTIP": "Reiniciar o tutorial introdutório",
"HINT_SELECT_VIDEO": "Selecione o seu vídeo aqui!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "T?tulos partilhados",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Escolhe como os t?tulos do separador e do conte?do multim?dia s?o partilhados com a sala. O modo oculto limpa os t?tulos no servidor e desativa a cria??o de salas de epis?dio pelo teu cliente.",
"OPTION_TITLE_PRIVACY_FULL": "T?tulos completos",
"OPTION_TITLE_PRIVACY_EPISODE": "S? epis?dio",
"OPTION_TITLE_PRIVACY_HIDDEN": "Ocultos"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Перезапустить обучение",
"BTN_RESTART_TOUR_TOOLTIP": "Запустить приветственное руководство заново",
"HINT_SELECT_VIDEO": "Выберите ваше видео здесь!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "????? ????????",
"LABEL_TITLE_PRIVACY_TOOLTIP": "????????, ??? ???????? ??????? ? ????? ?????????? ? ???????. ??????? ????? ??????? ???????? ?? ??????? ? ????????? ???????? ????? ???????? ? ?????? ???????.",
"OPTION_TITLE_PRIVACY_FULL": "?????? ????????",
"OPTION_TITLE_PRIVACY_EPISODE": "?????? ??????",
"OPTION_TITLE_PRIVACY_HIDDEN": "??????"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Eğitimi Yeniden Başlat",
"BTN_RESTART_TOUR_TOOLTIP": "Tanıtım eğitimini yeniden başlat",
"HINT_SELECT_VIDEO": "Videonuzu buradan seçin!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "Payla??lan ba?l?klar",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Sekme ve medya ba?l?klar?n?n odayla nas?l payla??laca??n? se?in. Gizli mod sunucudaki ba?l?klar? temizler ve istemcinizden b?l?m lobisi olu?turmay? devre d??? b?rak?r.",
"OPTION_TITLE_PRIVACY_FULL": "Tam ba?l?klar",
"OPTION_TITLE_PRIVACY_EPISODE": "Sadece b?l?m",
"OPTION_TITLE_PRIVACY_HIDDEN": "Gizli"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "Перезапустіть підручник",
"BTN_RESTART_TOUR_TOOLTIP": "Перезапустіть навчальний посібник із адаптації",
"HINT_SELECT_VIDEO": "Виберіть своє відео тут!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "??????? ?????",
"LABEL_TITLE_PRIVACY_TOOLTIP": "????????, ?? ????? ??????? ? ????? ??????????? ?? ???????. ?????????? ????? ?????? ????? ?? ??????? ? ??????? ????????? ???? ???????? ?? ?????? ???????.",
"OPTION_TITLE_PRIVACY_FULL": "????? ?????",
"OPTION_TITLE_PRIVACY_EPISODE": "???? ??????",
"OPTION_TITLE_PRIVACY_HIDDEN": "?????????"
}
+5 -5
View File
@@ -230,9 +230,9 @@
"BTN_RESTART_TOUR": "重启教程",
"BTN_RESTART_TOUR_TOOLTIP": "重新启动入门教程",
"HINT_SELECT_VIDEO": "在这里选择您的视频!",
"LABEL_TITLE_PRIVACY": "Shared Titles",
"LABEL_TITLE_PRIVACY_TOOLTIP": "Choose how tab and media titles are shared with the room. Hidden mode clears titles on the server and disables creating episode lobbies from your client.",
"OPTION_TITLE_PRIVACY_FULL": "Full titles",
"OPTION_TITLE_PRIVACY_EPISODE": "Episode only",
"OPTION_TITLE_PRIVACY_HIDDEN": "Hidden"
"LABEL_TITLE_PRIVACY": "????",
"LABEL_TITLE_PRIVACY_TOOLTIP": "??????????????????????????????????????????????????",
"OPTION_TITLE_PRIVACY_FULL": "????",
"OPTION_TITLE_PRIVACY_EPISODE": "???",
"OPTION_TITLE_PRIVACY_HIDDEN": "??"
}
+2 -1
View File
@@ -89,6 +89,7 @@ let pendingConnectionErrorMsg = null;
let roomListRefreshTimer = null;
let roomListRefreshInterval = null;
const ROOM_LIST_REFRESH_COOLDOWN_MS = 11000;
const TITLE_PRIVACY_MODES = ['full', 'episode', 'hidden'];
const FEATURE_HINTS = [
{
key: 'audio_processing',
@@ -210,7 +211,7 @@ async function init() {
elements.username.value = username;
if (elements.filterNoise) elements.filterNoise.checked = localData.filterNoise !== false;
if (elements.autoSyncNextEpisode) elements.autoSyncNextEpisode.checked = localData.autoSyncNextEpisode !== false;
if (elements.titlePrivacyMode) elements.titlePrivacyMode.value = localData.titlePrivacyMode || 'full';
if (elements.titlePrivacyMode) elements.titlePrivacyMode.value = TITLE_PRIVACY_MODES.includes(localData.titlePrivacyMode) ? localData.titlePrivacyMode : 'full';
if (elements.forceSyncMode) elements.forceSyncMode.value = localData.forceSyncMode || 'jump-to-others';
if (elements.browserNotifications) elements.browserNotifications.checked = localData.browserNotifications === true;
if (elements.autoCopyInvite) elements.autoCopyInvite.checked = localData.autoCopyInvite !== false;
+12
View File
@@ -34,6 +34,18 @@ assert.deepEqual(
}
);
assert.deepEqual(
applyTitlePrivacyToPayload({
tabTitle: 'Private Jellyfin - S01E04',
status: 'heartbeat'
}, 'episode'),
{
tabTitle: 'S01E04',
status: 'heartbeat'
},
'privacy filtering must not add absent title keys'
);
assert.deepEqual(
applyTitlePrivacyToPayload({
tabTitle: 'Private Tab',