From ae8ae6b91d9c0f31ea02c7e12a3829604e753f8f Mon Sep 17 00:00:00 2001 From: jeanotx32 Date: Wed, 12 Aug 2026 03:30:55 +0200 Subject: [PATCH] fix : Firefox handling 4 --- README.md | 14 ++++++++++---- packages/agent/src/firefox.ts | 30 +++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 352cd40..efafe99 100644 --- a/README.md +++ b/README.md @@ -210,10 +210,16 @@ Sur Ubuntu, `firefox` est un snap, et cela impose deux choses. L'interface `home` d'un snap **exclut délibérément les fichiers et répertoires cachés** — ceux commençant par un point, réputés contenir des données sensibles. Un profil sous -`~/.stream-control/` y est donc inaccessible, et Firefox meurt sans jamais ouvrir son port. -L'agent détecte le paquet snap en suivant la chaîne de liens de la commande -(`/usr/bin/firefox` → `/snap/bin/firefox` → `/usr/bin/snap`) et place alors son profil sous -`~/snap/firefox/common/stream-control-profile`. Un profil explicitement configuré dans un +`~/.stream-control/` y est donc inaccessible, et Firefox meurt sans jamais ouvrir son port — +sans message d'erreur exploitable : la confinement AppArmor bloque au niveau du noyau, pas +dans la sortie du processus. + +L'agent détecte le paquet snap de deux façons, l'une ne suffisant pas partout : en suivant +la chaîne de liens de la commande (`/usr/bin/firefox` → `/snap/bin/firefox` → +`/usr/bin/snap`, la forme la plus courante), et en lisant le contenu d'un éventuel script +d'aiguillage — certaines images Ubuntu placent en `/usr/bin/firefox` un petit script qui +exécute le snap en son sein, sans aucun lien symbolique dans la chaîne. Dans les deux cas, +le profil est placé sous `~/snap/firefox/common/stream-control-profile`. Un profil explicitement configuré dans un répertoire caché est refusé **avant** le lancement, avec l'explication. Par ailleurs, `firefox` n'est ici qu'un lanceur : il passe la main au snap et **sort diff --git a/packages/agent/src/firefox.ts b/packages/agent/src/firefox.ts index 1d2ccd8..711bbe8 100644 --- a/packages/agent/src/firefox.ts +++ b/packages/agent/src/firefox.ts @@ -619,7 +619,35 @@ export function snapSignature(chain: string[]): boolean { /** Vrai si la commande mène à un Firefox empaqueté en snap. */ export function isSnapFirefox(command: string): boolean { const resolved = locate(command); - return resolved !== null && snapSignature(symlinkChain(resolved)); + if (!resolved) return false; + // Deux formes rencontrées en pratique : un lien symbolique jusqu'à + // `/usr/bin/snap` (le cas documenté), ou — sur certaines images Ubuntu — + // `/usr/bin/firefox` en petit script shell qui exécute le snap en son sein, + // sans aucun lien symbolique dans la chaîne. La première vérification ne + // voyait pas la seconde forme. + return snapSignature(symlinkChain(resolved)) || wrapperReferencesSnap(resolved); +} + +/** + * Vrai si un script d'aiguillage mentionne le snap dans son propre texte. + * + * Ne s'applique qu'à un petit script shell (garde du `#!` et d'une taille + * raisonnable) : un exécutable binaire réel ne doit pas être lu comme du + * texte, et une lecture qui échoue n'est qu'un indice de moins, pas une + * preuve d'absence. Un faux positif ici est sans conséquence — il ne fait que + * choisir l'emplacement de profil déjà valable pour un Firefox non confiné — + * donc la détection est volontairement large plutôt que stricte sur le + * libellé exact. + */ +function wrapperReferencesSnap(resolved: string): boolean { + try { + const stat = fs.statSync(resolved); + if (!stat.isFile() || stat.size === 0 || stat.size > 8192) return false; + const content = fs.readFileSync(resolved, 'utf8'); + return content.startsWith('#!') && /\/snap\/|\bsnap run\b/.test(content); + } catch { + return false; + } } /** Chemin de départ suivi de chaque cible de lien, en absolu. */