1
1
import ipaddr from 'ipaddr.js' ;
2
2
3
- import { RequestDetails , ProxyDetails , ProxyInfoMap } from '@/helpers/socksProxy/socksProxy.types' ;
3
+ import {
4
+ RequestDetails ,
5
+ ProxyDetails ,
6
+ ProxyInfoMap ,
7
+ ProxyInfo ,
8
+ } from '@/helpers/socksProxy/socksProxy.types' ;
4
9
import { checkDomain } from '@/helpers/domain' ;
5
10
import { getRandomSessionProxy } from '@/helpers/socksProxy/getRandomSessionProxy' ;
11
+ import { getActiveTabDetails } from '@/helpers/tabs' ;
6
12
7
13
// TODO decide what how to handle fallback proxy (if proxy is invalid, it will fallback to Firefox proxy if configured)
8
14
// https://bugzilla.mozilla.org/show_bug.cgi?id=1750561
@@ -16,60 +22,72 @@ export const handleProxyRequest = async (details: browser.proxy._OnRequestDetail
16
22
const { hostProxies } = await browser . storage . local . get ( 'hostProxies' ) ;
17
23
const { hostProxiesDetails } = await browser . storage . local . get ( 'hostProxiesDetails' ) ;
18
24
19
- const globalConfigParsed = JSON . parse ( globalProxy ) ;
20
- const randomProxyModeParsed = JSON . parse ( randomProxyMode ) ;
25
+ const globalConfigParsed : ProxyInfo = JSON . parse ( globalProxy ) ;
26
+ const randomProxyModeParsed : boolean = JSON . parse ( randomProxyMode ) ;
21
27
const globalProxyDetailsParsed : ProxyDetails = JSON . parse ( globalProxyDetails ) ;
22
28
const excludedHostsParsed : string [ ] = JSON . parse ( excludedHosts ) ;
23
29
const hostProxiesParsed : ProxyInfoMap = JSON . parse ( hostProxies ) ;
24
30
const hostProxiesDetailsParsed : Record < string , ProxyDetails > = JSON . parse ( hostProxiesDetails ) ;
25
31
26
32
const currentHost = getCurrentHost ( details ) ;
27
33
const { hasSubdomain, domain, subDomain } = checkDomain ( currentHost ) ;
34
+ const currentDomain = hasSubdomain ? subDomain : domain ;
28
35
29
- // Block speculative requests, since we can't identify their origins
36
+ const isDomainExcluded = excludedHostsParsed . includes ( currentDomain ) ;
37
+ const isDomainProxied = Object . hasOwn ( hostProxiesParsed , currentDomain ) ;
38
+ const isDomainProxydEnabled = ! ! hostProxiesDetailsParsed [ currentDomain ] ?. socksEnabled ;
39
+ const isGlobalProxyEnabled = globalProxyDetailsParsed . socksEnabled ;
40
+
41
+ // 1. Block speculative requests, since we can't identify their origins
30
42
if ( details . type === 'speculative' ) {
31
43
return { cancel : true } ;
32
44
}
33
45
34
- // Skip proxy for local/reserved IPs
46
+ // 2. Skip proxy for local/reserved IPs
35
47
if ( isLocalOrReservedIP ( currentHost ) ) {
36
48
return { type : 'direct' } ;
37
49
}
38
50
39
- // 0. If random proxy is enabled, get a random proxy per domain
40
- if ( randomProxyModeParsed ) {
41
- const randomProxy = await getRandomSessionProxy ( domain ) ;
42
- return randomProxy ;
51
+ // 3. When the request if a conncheck/DNS check originating from the extension,
52
+ // we want to use the same proxy as the active tab, to get a consistent conncheck result
53
+ const isExtensionRequest = details . documentUrl ?. startsWith ( 'moz-extension://' ) ;
54
+ const isConnCheck = details . url ?. endsWith ( 'am.i.mullvad.net/json' ) ;
55
+ const isDNSCheck = details . url ?. endsWith ( 'dnsleak.am.i.mullvad.net/' ) ;
56
+
57
+ const isExtConnCheck = isExtensionRequest && ( isConnCheck || isDNSCheck ) ;
58
+
59
+ if ( isExtConnCheck ) {
60
+ return getProxyForExtensionConnectionCheck (
61
+ isGlobalProxyEnabled ,
62
+ globalConfigParsed ,
63
+ randomProxyModeParsed ,
64
+ excludedHostsParsed ,
65
+ hostProxiesParsed ,
66
+ hostProxiesDetailsParsed ,
67
+ ) ;
43
68
}
44
69
45
- // 1. Check subdomain level
46
- if ( hasSubdomain ) {
47
- if ( excludedHostsParsed . includes ( subDomain ) ) {
48
- return { type : 'direct' } ;
49
- }
50
-
51
- if (
52
- Object . hasOwn ( hostProxiesParsed , subDomain ) &&
53
- hostProxiesDetailsParsed [ currentHost ] . socksEnabled
54
- ) {
55
- return hostProxiesParsed [ subDomain ] ;
56
- }
70
+ // 4. Check for random proxy mode
71
+ // For now, overrides all other proxy settings
72
+ if ( randomProxyModeParsed ) {
73
+ return getRandomSessionProxy ( domain ) ;
57
74
}
58
75
59
- // 2 . Check domain level
60
- if ( excludedHostsParsed . includes ( domain ) ) {
76
+ // 5 . Check domain/subdomain level
77
+ if ( isDomainExcluded ) {
61
78
return { type : 'direct' } ;
62
79
}
63
- if ( Object . hasOwn ( hostProxiesParsed , domain ) && hostProxiesDetailsParsed [ domain ] . socksEnabled ) {
64
- return hostProxiesParsed [ domain ] ;
80
+
81
+ if ( isDomainProxied && isDomainProxydEnabled ) {
82
+ return hostProxiesParsed [ currentDomain ] ;
65
83
}
66
84
67
- // 3 . Check global proxy
68
- if ( globalProxyDetailsParsed . socksEnabled ) {
85
+ // 6 . Check global proxy
86
+ if ( isGlobalProxyEnabled ) {
69
87
return globalConfigParsed ;
70
88
}
71
89
72
- // 4 . Default: no proxy
90
+ // 7 . Default: no proxy
73
91
return { type : 'direct' } ;
74
92
} catch ( error ) {
75
93
console . log ( error ) ;
@@ -117,3 +135,47 @@ export const isLocalOrReservedIP = (hostname: string) => {
117
135
return false ;
118
136
}
119
137
} ;
138
+
139
+ const getProxyForExtensionConnectionCheck = async (
140
+ isGlobalProxyEnabled : boolean ,
141
+ globalConfigParsed : ProxyInfo ,
142
+ randomProxyModeParsed : boolean ,
143
+ excludedHostsParsed : string [ ] ,
144
+ hostProxiesParsed : ProxyInfoMap ,
145
+ hostProxiesDetailsParsed : Record < string , ProxyDetails > ,
146
+ ) => {
147
+ const { isAboutPage, host } = await getActiveTabDetails ( ) ;
148
+ const { domain, hasSubdomain, subDomain } = checkDomain ( host ) ;
149
+ const tabDomain = hasSubdomain ? subDomain : domain ;
150
+
151
+ const isTabDomainExcluded = excludedHostsParsed . includes ( tabDomain ) ;
152
+ const isTabDomainProxied = Object . hasOwn ( hostProxiesParsed , tabDomain ) ;
153
+ const isTabProxyEnabled = ! ! hostProxiesDetailsParsed [ tabDomain ] ?. socksEnabled ;
154
+
155
+ // a) If the current tab is an about page, we only need to check for a global proxy
156
+ if ( isAboutPage ) {
157
+ return isGlobalProxyEnabled ? globalConfigParsed : { type : 'direct' } ;
158
+ }
159
+
160
+ // b) If random proxy mode is enabled, we need to check for the current tab's proxy
161
+ if ( randomProxyModeParsed ) {
162
+ return getRandomSessionProxy ( tabDomain ) ;
163
+ }
164
+
165
+ // c) If current tab domain is excluded, connection is direct
166
+ if ( isTabDomainExcluded ) {
167
+ return { type : 'direct' } ;
168
+ }
169
+
170
+ // d) If current tab is proxied, we need to check for the current tab's proxy
171
+ if ( isTabDomainProxied && isTabProxyEnabled ) {
172
+ return hostProxiesParsed [ tabDomain ] ;
173
+ }
174
+
175
+ // e) If global proxy is enabled
176
+ if ( isGlobalProxyEnabled ) {
177
+ return globalConfigParsed ;
178
+ }
179
+
180
+ return { type : 'direct' } ;
181
+ } ;
0 commit comments