@@ -6,9 +6,11 @@ import { APP_ROOT } from '../constants';
66import { HtkConfig } from '../config' ;
77import { logError } from '../error-tracking' ;
88
9- import { getAvailableBrowsers , launchBrowser , BrowserInstance } from '../browsers' ;
109import { delay } from '../util/promise' ;
1110import { isErrorLike } from '../util/error' ;
11+ import { isSnap , getSnapConfigPath } from '../util/snap' ;
12+
13+ import { launchBrowser , BrowserInstance , getBrowserDetails } from '../browsers' ;
1214import { readFile , canAccess , deleteFolder } from '../util/fs' ;
1315import { windowsKill , spawnToResult } from '../util/process-management' ;
1416import { MessageServer } from '../message-server' ;
@@ -73,23 +75,20 @@ export class FreshFirefox implements Interceptor {
7375
7476 constructor ( private config : HtkConfig ) { }
7577
76- private readonly firefoxProfilePath = path . join ( this . config . configPath , 'firefox-profile' ) ;
77-
7878 isActive ( proxyPort : number | string ) {
7979 return browsers [ proxyPort ] != null && ! ! browsers [ proxyPort ] . pid ;
8080 }
8181
8282 async isActivable ( ) {
83- const availableBrowsers = await getAvailableBrowsers ( this . config . configPath ) ;
84-
85- const firefoxBrowser = _ . find ( availableBrowsers , { name : 'firefox' } ) ;
83+ const firefoxBrowser = await getBrowserDetails ( this . config . configPath , 'firefox' ) ;
8684
8785 return ! ! firefoxBrowser && // Must have Firefox installed
8886 parseInt ( firefoxBrowser . version . split ( '.' ) [ 0 ] , 0 ) >= 58 && // Must use cert9.db
8987 await getCertutilCommand ( ) . then ( ( ) => true ) . catch ( ( ) => false ) // Must have certutil available
9088 }
9189
9290 async startFirefox (
91+ profilePath : string ,
9392 initialServer : MessageServer | CertCheckServer ,
9493 proxyPort ?: number ,
9594 existingPrefs = { }
@@ -98,7 +97,7 @@ export class FreshFirefox implements Interceptor {
9897
9998 const browser = await launchBrowser ( initialUrl , {
10099 browser : 'firefox' ,
101- profile : this . firefoxProfilePath ,
100+ profile : profilePath ,
102101 proxy : proxyPort ? `127.0.0.1:${ proxyPort } ` : undefined ,
103102 prefs : _ . assign (
104103 existingPrefs ,
@@ -184,7 +183,7 @@ export class FreshFirefox implements Interceptor {
184183 }
185184
186185 // Create the profile. We need to run FF to do its setup, then close it & edit more ourselves.
187- async setupFirefoxProfile ( ) {
186+ async setupFirefoxProfile ( profilePath : string ) {
188187 const messageServer = new MessageServer (
189188 this . config ,
190189 `HTTP Toolkit is preparing a Firefox profile, please wait...`
@@ -193,15 +192,15 @@ export class FreshFirefox implements Interceptor {
193192
194193 let messageShown : Promise < void > | true = messageServer . waitForSuccess ( ) . catch ( logError ) ;
195194
196- profileSetupBrowser = await this . startFirefox ( messageServer ) ;
195+ profileSetupBrowser = await this . startFirefox ( profilePath , messageServer ) ;
197196 profileSetupBrowser . process . once ( 'close' , ( exitCode ) => {
198197 console . log ( "Profile setup Firefox closed" ) ;
199198 messageServer . stop ( ) ;
200199 profileSetupBrowser = undefined ;
201200
202201 if ( messageShown !== true ) {
203202 logError ( `Firefox profile setup failed with code ${ exitCode } ` ) ;
204- deleteFolder ( this . firefoxProfilePath ) . catch ( console . warn ) ;
203+ deleteFolder ( profilePath ) . catch ( console . warn ) ;
205204 }
206205 } ) ;
207206
@@ -222,7 +221,7 @@ export class FreshFirefox implements Interceptor {
222221 const certUtilResult = await spawnToResult (
223222 certutil . command , [
224223 '-A' ,
225- '-d' , `sql:${ this . firefoxProfilePath } ` ,
224+ '-d' , `sql:${ profilePath } ` ,
226225 '-t' , 'C,,' ,
227226 '-i' , this . config . https . certPath ,
228227 '-n' , 'HTTP Toolkit'
@@ -240,7 +239,14 @@ export class FreshFirefox implements Interceptor {
240239 async activate ( proxyPort : number ) {
241240 if ( this . isActive ( proxyPort ) || ! ! profileSetupBrowser ) return ;
242241
243- const firefoxPrefsFile = path . join ( this . firefoxProfilePath , 'prefs.js' ) ;
242+ const browserDetails = await getBrowserDetails ( this . config . configPath , 'firefox' ) ;
243+ if ( ! browserDetails ) throw new Error ( 'Firefox could not be detected' ) ;
244+
245+ const profilePath = await isSnap ( browserDetails . command )
246+ ? path . join ( getSnapConfigPath ( 'firefox' ) , 'profile' )
247+ : path . join ( this . config . configPath , 'firefox-profile' ) ;
248+
249+ const firefoxPrefsFile = path . join ( profilePath , 'prefs.js' ) ;
244250
245251 let existingPrefs : _ . Dictionary < any > = { } ;
246252
@@ -250,7 +256,7 @@ export class FreshFirefox implements Interceptor {
250256 This helps avoid initial Firefox profile setup request noise, and tidies up some awkward UX where
251257 firefox likes to open extra welcome windows/tabs on first run.
252258 */
253- await this . setupFirefoxProfile ( ) ;
259+ await this . setupFirefoxProfile ( profilePath ) ;
254260 }
255261
256262 // We need to preserve & reuse any existing preferences, to avoid issues
@@ -272,7 +278,7 @@ export class FreshFirefox implements Interceptor {
272278 const certCheckServer = new CertCheckServer ( this . config ) ;
273279 await certCheckServer . start ( "https://amiusing.httptoolkit.tech" ) ;
274280
275- const browser = await this . startFirefox ( certCheckServer , proxyPort , existingPrefs ) ;
281+ const browser = await this . startFirefox ( profilePath , certCheckServer , proxyPort , existingPrefs ) ;
276282
277283 let certCheckSuccessful : boolean | undefined ;
278284 certCheckServer . waitForSuccess ( ) . then ( ( ) => {
@@ -300,7 +306,7 @@ export class FreshFirefox implements Interceptor {
300306 ? "failed"
301307 : "did not complete"
302308 } with FF exit code ${ exitCode } `) ;
303- deleteFolder ( this . firefoxProfilePath ) . catch ( console . warn ) ;
309+ deleteFolder ( profilePath ) . catch ( console . warn ) ;
304310 }
305311 } ) ;
306312
0 commit comments