11import * as path from 'path' ;
2+ import * as os from 'os' ;
3+
4+ import { deleteFile , mkDir , writeFile , copyRecursive , deleteFolder } from "./util/fs" ;
5+ import { addShutdownHandler } from './shutdown' ;
6+
27import { OVERRIDES_DIR } from './interceptors/terminal/terminal-env-overrides' ;
38
4- import { deleteFile , mkDir , writeFile } from "./util/fs" ;
9+ const WEBEXTENSION_BASE_PATH = path . join ( OVERRIDES_DIR , 'webextension' ) ;
10+
11+ // We copy the WebExtension to a temp directory the first time it's activated, so that we can
12+ // modify the config folder within to easily inject config into the extension. Without this,
13+ // the extension is usually in the app install directory, which is often not user-writable.
14+ // We only make one copy for all sessions, but we later inject independent per-session
15+ // config files, so they can behave independently.
16+ export let WEBEXTENSION_INSTALL : {
17+ path : string ;
18+ configPath : string ;
19+ } | undefined ;
20+ async function ensureWebExtensionInstalled ( ) {
21+ if ( WEBEXTENSION_INSTALL ) return ; // No-op after the first install
22+ else {
23+ const tmpDir = os . tmpdir ( ) ;
524
6- export const WEBEXTENSION_PATH = path . join ( OVERRIDES_DIR , 'webextension' ) ;
7- const WEBEXTENSION_CONFIG_PATH = path . join ( WEBEXTENSION_PATH , 'config' ) ;
25+ const webExtensionPath = path . join ( tmpDir , 'httptoolkit-webextension' ) ;
26+ const configPath = path . join ( webExtensionPath , 'config' ) ;
27+
28+ await copyRecursive ( WEBEXTENSION_BASE_PATH , webExtensionPath ) ;
29+ await mkDir ( configPath ) ;
30+
31+ WEBEXTENSION_INSTALL = { path : webExtensionPath , configPath } ;
32+ console . log ( `Webextension installed at ${ WEBEXTENSION_INSTALL . path } ` ) ;
33+ }
34+ }
35+
36+ // On shutdown, we delete the webextension install again.
37+ addShutdownHandler ( async ( ) => {
38+ if ( WEBEXTENSION_INSTALL ) {
39+ console . log ( `Uninstalling webextension from ${ WEBEXTENSION_INSTALL . path } ` ) ;
40+ await deleteFolder ( WEBEXTENSION_INSTALL . path ) ;
41+ WEBEXTENSION_INSTALL = undefined ;
42+ }
43+ } ) ;
844
945interface WebExtensionConfig { // Should match config in the WebExtension itself
1046 mockRtc : {
@@ -17,9 +53,11 @@ const getConfigKey = (proxyPort: number) =>
1753 `127_0_0_1.${ proxyPort } ` ; // Filename-safe proxy address
1854
1955const getConfigPath = ( proxyPort : number ) =>
20- path . join ( WEBEXTENSION_CONFIG_PATH , getConfigKey ( proxyPort ) ) ;
56+ path . join ( WEBEXTENSION_INSTALL ! . configPath , getConfigKey ( proxyPort ) ) ;
2157
2258export function clearWebExtensionConfig ( httpProxyPort : number ) {
59+ if ( ! WEBEXTENSION_INSTALL ) return ;
60+
2361 return deleteFile ( getConfigPath ( httpProxyPort ) )
2462 . catch ( ( ) => { } ) ; // We ignore errors - nothing we can do, not very important.
2563}
@@ -30,6 +68,8 @@ export async function updateWebExtensionConfig(
3068 webRTCEnabled : boolean
3169) {
3270 if ( webRTCEnabled ) {
71+ await ensureWebExtensionInstalled ( ) ;
72+
3373 const adminBaseUrl = `http://internal.httptoolkit.localhost:45456/session/${ sessionId } ` ;
3474 await writeConfig ( httpProxyPort , {
3575 mockRtc : {
@@ -38,11 +78,14 @@ export async function updateWebExtensionConfig(
3878 }
3979 } ) ;
4080 } else {
41- await writeConfig ( httpProxyPort , { mockRtc : false } ) ;
81+ if ( WEBEXTENSION_INSTALL ) {
82+ // If the extension is set up, but this specific session has it disabled, we
83+ // make the config explicitly disable it, just to be clear:
84+ await writeConfig ( httpProxyPort , { mockRtc : false } ) ;
85+ }
4286 }
4387}
4488
4589async function writeConfig ( proxyPort : number , config : WebExtensionConfig ) {
46- await mkDir ( WEBEXTENSION_CONFIG_PATH ) . catch ( ( ) => { } ) ; // Make sure the config dir exists
4790 return writeFile ( getConfigPath ( proxyPort ) , JSON . stringify ( config ) ) ;
4891}
0 commit comments