@@ -4,6 +4,7 @@ import { observable, action, computed } from 'mobx';
4
4
import { observer , inject } from "mobx-react" ;
5
5
6
6
import { styled } from '../../styles' ;
7
+ import { isWindows } from '../../util/ui' ;
7
8
import { WarningIcon , Icon } from '../../icons' ;
8
9
9
10
import { isValidPortConfiguration , ProxyStore } from '../../model/proxy-store' ;
@@ -12,7 +13,8 @@ import {
12
13
serverVersion ,
13
14
versionSatisfies ,
14
15
INITIAL_HTTP2_RANGE ,
15
- TLS_PASSTHROUGH_SUPPORTED
16
+ TLS_PASSTHROUGH_SUPPORTED ,
17
+ KEY_LOG_FILE_SUPPORTED
16
18
} from '../../services/service-versions' ;
17
19
18
20
import { inputValidation } from '../component-utils' ;
@@ -23,6 +25,7 @@ import {
23
25
} from '../common/card' ;
24
26
import { ContentLabel } from '../common/text-content' ;
25
27
import { Select , TextInput } from '../common/inputs' ;
28
+ import { IconButton } from '../common/icon-button' ;
26
29
import {
27
30
SettingsButton ,
28
31
SettingsExplanation ,
@@ -85,8 +88,29 @@ const Http2Select = styled(Select)`
85
88
padding: 3px;
86
89
` ;
87
90
91
+ const TlsKeyLogContainer = styled . div `
92
+ margin: 10px 0;
93
+ display: flex;
94
+ flex-direction: column;
95
+ position: relative;
96
+ ` ;
97
+
98
+ const InputClearButton = styled ( IconButton ) `
99
+ position: absolute;
100
+ top: 1px;
101
+ right: 2px;
102
+ ` ;
103
+
88
104
const hostnameValidation = inputValidation ( isValidHostname , "Should be a valid hostname" ) ;
89
105
106
+ const isAbsoluteWindowsPath = ( path : string ) => / ^ ( [ a - z A - Z ] : [ \\ \/ ] | [ \\ \/ ] ) ( (?: [ ^ < > : " \/ \\ | ? * ] + ) [ \\ \/ ] ? ) * $ / . test ( path ) ;
107
+ const isAbsolutePosixPath = ( path : string ) => / ^ \/ (?: [ ^ / ] + \/ ? ) * $ / . test ( path ) ;
108
+
109
+ const pathValidation = inputValidation (
110
+ isWindows ? isAbsoluteWindowsPath : isAbsolutePosixPath ,
111
+ "Should be a valid absolute file path"
112
+ ) ;
113
+
90
114
@inject ( 'proxyStore' )
91
115
@observer
92
116
export class ProxySettingsCard extends React . Component <
@@ -160,6 +184,26 @@ export class ProxySettingsCard extends React.Component<
160
184
tlsPassthroughConfig . splice ( hostnameIndex , 1 ) ;
161
185
}
162
186
187
+ @observable
188
+ tlsKeyFileInput : string = this . props . proxyStore ! . keyLogFilePath || '' ;
189
+
190
+ @action . bound
191
+ setTlsKeyFilePath ( { target } : React . ChangeEvent < HTMLInputElement > ) {
192
+ this . tlsKeyFileInput = target . value ;
193
+
194
+ if ( ! this . tlsKeyFileInput . trim ( ) ) {
195
+ this . props . proxyStore ! . keyLogFilePath = undefined ;
196
+ } else if ( pathValidation ( target ) ) {
197
+ this . props . proxyStore ! . keyLogFilePath = this . tlsKeyFileInput . trim ( ) ;
198
+ }
199
+ }
200
+
201
+ @action . bound
202
+ clearTlsKeyFilePath ( ) {
203
+ this . tlsKeyFileInput = '' ;
204
+ this . props . proxyStore ! . keyLogFilePath = undefined ;
205
+ }
206
+
163
207
render ( ) {
164
208
const { proxyStore, ...cardProps } = this . props ;
165
209
const {
@@ -169,7 +213,10 @@ export class ProxySettingsCard extends React.Component<
169
213
http2CurrentlyEnabled,
170
214
171
215
tlsPassthroughConfig,
172
- currentTlsPassthroughConfig
216
+ currentTlsPassthroughConfig,
217
+
218
+ keyLogFilePath,
219
+ currentKeyLogFilePath
173
220
} = proxyStore ! ;
174
221
175
222
return < CollapsibleCard { ...cardProps } >
@@ -184,7 +231,8 @@ export class ProxySettingsCard extends React.Component<
184
231
visible = {
185
232
( this . isCurrentPortConfigValid && ! this . isCurrentPortInRange ) ||
186
233
http2Enabled !== http2CurrentlyEnabled ||
187
- ! _ . isEqual ( tlsPassthroughConfig , currentTlsPassthroughConfig )
234
+ ! _ . isEqual ( tlsPassthroughConfig , currentTlsPassthroughConfig ) ||
235
+ keyLogFilePath !== currentKeyLogFilePath
188
236
}
189
237
/>
190
238
@@ -234,7 +282,7 @@ export class ProxySettingsCard extends React.Component<
234
282
versionSatisfies ( serverVersion . value , TLS_PASSTHROUGH_SUPPORTED ) && < >
235
283
< SettingsSubheading >
236
284
TLS Passthrough { ! _ . isEqual ( tlsPassthroughConfig , currentTlsPassthroughConfig ) &&
237
- < UnsavedIcon />
285
+ < UnsavedIcon title = "Restart app to apply changes" />
238
286
}
239
287
</ SettingsSubheading >
240
288
@@ -259,7 +307,7 @@ export class ProxySettingsCard extends React.Component<
259
307
versionSatisfies ( serverVersion . value , INITIAL_HTTP2_RANGE ) && < >
260
308
< SettingsSubheading >
261
309
HTTP/2 Support { http2Enabled !== http2CurrentlyEnabled &&
262
- < UnsavedIcon />
310
+ < UnsavedIcon title = "Restart app to apply changes" />
263
311
}
264
312
</ SettingsSubheading >
265
313
@@ -278,6 +326,41 @@ export class ProxySettingsCard extends React.Component<
278
326
</ Http2Select >
279
327
</ >
280
328
}
329
+
330
+ {
331
+ versionSatisfies ( serverVersion . value , KEY_LOG_FILE_SUPPORTED ) && < >
332
+ < SettingsSubheading >
333
+ TLS Key Log File { keyLogFilePath !== currentKeyLogFilePath &&
334
+ < UnsavedIcon title = "Restart app to apply changes" />
335
+ }
336
+ </ SettingsSubheading >
337
+
338
+ < TlsKeyLogContainer >
339
+ < TextInput
340
+ placeholder = {
341
+ navigator . platform . startsWith ( 'Win' )
342
+ ? 'C:\\tls-keys.log'
343
+ : '/tmp/tls-keys.log'
344
+ }
345
+ value = { this . tlsKeyFileInput }
346
+ onChange = { this . setTlsKeyFilePath }
347
+ />
348
+ { ! ! keyLogFilePath && < >
349
+ < InputClearButton
350
+ title = "Unset TLS key file"
351
+ icon = { [ 'fas' , 'times' ] }
352
+ onClick = { this . clearTlsKeyFilePath }
353
+ />
354
+ </ > }
355
+ </ TlsKeyLogContainer >
356
+
357
+ < SettingsExplanation >
358
+ If set, TLS keys for all client & server traffic will be logged to this file ,
359
+ allowing inspection of raw TLS packet contents & details in low - level packet
360
+ inspection tools like Wireshark .
361
+ </ SettingsExplanation >
362
+ </ >
363
+ }
281
364
</ CollapsibleCard >
282
365
}
283
366
0 commit comments