1
1
import * 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
+
2
7
import { OVERRIDES_DIR } from './interceptors/terminal/terminal-env-overrides' ;
3
8
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 ( ) ;
5
24
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
+ } ) ;
8
44
9
45
interface WebExtensionConfig { // Should match config in the WebExtension itself
10
46
mockRtc : {
@@ -17,9 +53,11 @@ const getConfigKey = (proxyPort: number) =>
17
53
`127_0_0_1.${ proxyPort } ` ; // Filename-safe proxy address
18
54
19
55
const getConfigPath = ( proxyPort : number ) =>
20
- path . join ( WEBEXTENSION_CONFIG_PATH , getConfigKey ( proxyPort ) ) ;
56
+ path . join ( WEBEXTENSION_INSTALL ! . configPath , getConfigKey ( proxyPort ) ) ;
21
57
22
58
export function clearWebExtensionConfig ( httpProxyPort : number ) {
59
+ if ( ! WEBEXTENSION_INSTALL ) return ;
60
+
23
61
return deleteFile ( getConfigPath ( httpProxyPort ) )
24
62
. catch ( ( ) => { } ) ; // We ignore errors - nothing we can do, not very important.
25
63
}
@@ -30,6 +68,8 @@ export async function updateWebExtensionConfig(
30
68
webRTCEnabled : boolean
31
69
) {
32
70
if ( webRTCEnabled ) {
71
+ await ensureWebExtensionInstalled ( ) ;
72
+
33
73
const adminBaseUrl = `http://internal.httptoolkit.localhost:45456/session/${ sessionId } ` ;
34
74
await writeConfig ( httpProxyPort , {
35
75
mockRtc : {
@@ -38,11 +78,14 @@ export async function updateWebExtensionConfig(
38
78
}
39
79
} ) ;
40
80
} 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
+ }
42
86
}
43
87
}
44
88
45
89
async function writeConfig ( proxyPort : number , config : WebExtensionConfig ) {
46
- await mkDir ( WEBEXTENSION_CONFIG_PATH ) . catch ( ( ) => { } ) ; // Make sure the config dir exists
47
90
return writeFile ( getConfigPath ( proxyPort ) , JSON . stringify ( config ) ) ;
48
91
}
0 commit comments