Skip to content

Commit 903a48f

Browse files
authored
Add discovery mechanism (#6)
* initial commit * auto true by default * comment and TODO * check PAC by default after installing * refine proxy status message * minor changes
1 parent 72d9e58 commit 903a48f

File tree

7 files changed

+240
-40
lines changed

7 files changed

+240
-40
lines changed

chrome/background.js

Lines changed: 115 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
// Copyright 2024 ETH Zurich, Ovgu
22
'use strict';
33

4+
const DEFAULT_PROXY_SCHEME = "https"
5+
const DEFAULT_PROXY_HOST = "forward-proxy.scion";
6+
const DEFAULT_PROXY_PORT = "9443";
47

58
const proxyHostResolvePath = "/resolve"
69
const proxyHostResolveParam = "host"
710
const proxyURLResolvePath = "/redirect"
811
const proxyURLResolveParam = "url"
912
const proxyPolicyPath = "/policy"
1013
const proxyErrorPath = "/error"
14+
const proxyHealthCheckPath = "/health"
1115

12-
let proxyScheme = "https";
13-
let proxyHost = "forward-proxy.scion";
14-
let proxyPort = "9443";
16+
let proxyScheme = DEFAULT_PROXY_SCHEME;
17+
let proxyHost = DEFAULT_PROXY_HOST;
18+
let proxyPort = DEFAULT_PROXY_PORT;
1519
let proxyAddress = `${proxyScheme}://${proxyHost}:${proxyPort}`;
1620

1721

@@ -58,26 +62,119 @@ getStorageValue('extension_running').then(extensionRunning => {
5862

5963
/*--- PAC --------------------------------------------------------------------*/
6064

65+
// Load saved configuration at startup
66+
chrome.storage.sync.get({ autoProxyConfig: true }, ({ autoProxyConfig }) => {
67+
if (autoProxyConfig) {
68+
fetchAndApplyScionPAC();
69+
} else {
70+
loadProxySettings();
71+
}
72+
});
73+
6174
function loadProxySettings() {
6275
chrome.storage.sync.get({
63-
proxyScheme: "https",
64-
proxyHost: "forward-proxy.scion",
65-
proxyPort: "9443"
76+
proxyScheme: DEFAULT_PROXY_SCHEME,
77+
proxyHost: DEFAULT_PROXY_HOST,
78+
proxyPort: DEFAULT_PROXY_PORT
6679
}, (items) => {
6780
proxyScheme = items.proxyScheme;
6881
proxyHost = items.proxyHost;
6982
proxyPort = items.proxyPort;
7083
proxyAddress = `${proxyScheme}://${proxyHost}:${proxyPort}`;
7184

72-
// Update the PAC script with new settings
7385
updateProxyConfiguration();
7486
});
75-
}
87+
}
88+
89+
// TODO: we assume correct formate from the server. We may want to
90+
// validate the PAC script, here.
91+
function parseProxyFromPAC(pacScript) {
92+
const httpsProxyMatch = pacScript.match(/HTTPS\s+([^:]+):(\d+)/i);
93+
const httpProxyMatch = pacScript.match(/PROXY\s+([^:]+):(\d+)/i);
94+
95+
if (httpsProxyMatch) {
96+
return {
97+
proxyScheme: "https",
98+
proxyHost: httpsProxyMatch[1],
99+
proxyPort: httpsProxyMatch[2]
100+
};
101+
} else if (httpProxyMatch) {
102+
return {
103+
proxyScheme: "http",
104+
proxyHost: httpProxyMatch[1],
105+
proxyPort: httpProxyMatch[2]
106+
};
107+
}
108+
109+
return null;
110+
}
111+
112+
function fetchAndApplyScionPAC() {
113+
fetch(`http://wpad/wpad_scion.dat`)
114+
.then(response => {
115+
if (!response.ok) {
116+
throw new Error(`Retrieving PAC config; status: ${response.status}`);
117+
}
118+
return response.text();
119+
})
120+
.then(pacScript => {
121+
const proxyConfig = parseProxyFromPAC(pacScript);
122+
123+
if (proxyConfig) {
124+
// As long as we can parse the PAC script, we assume it is correct,
125+
// i.e., we don't check the proxy health here.
126+
proxyScheme = proxyConfig.proxyScheme;
127+
proxyHost = proxyConfig.proxyHost;
128+
proxyPort = proxyConfig.proxyPort;
129+
proxyAddress = `${proxyScheme}://${proxyHost}:${proxyPort}`;
130+
131+
chrome.storage.sync.set({
132+
proxyScheme: proxyScheme,
133+
proxyHost: proxyHost,
134+
proxyPort: proxyPort
135+
}, function() {
136+
console.log("Detected proxy configuration:", proxyAddress);
137+
});
138+
139+
const config = {
140+
mode: "pac_script",
141+
pacScript: {
142+
data: pacScript
143+
}
144+
};
145+
146+
chrome.proxy.settings.set({ value: config, scope: 'regular' }, function() {
147+
console.log("SCION PAC configuration from WPAD applied");
148+
});
149+
} else{
150+
throw new Error("Failed to parse PAC script");
151+
}
152+
153+
})
154+
.catch(error => {
155+
console.warn("Error on WPAD process, falling back to default:", error);
156+
fallbackToDefaults();
157+
});
158+
}
159+
160+
function fallbackToDefaults() {
161+
proxyScheme = DEFAULT_PROXY_SCHEME;
162+
proxyHost = DEFAULT_PROXY_HOST;
163+
proxyPort = DEFAULT_PROXY_PORT;
164+
proxyAddress = `${proxyScheme}://${proxyHost}:${proxyPort}`;
165+
166+
chrome.storage.sync.set({
167+
proxyScheme: proxyScheme,
168+
proxyHost: proxyHost,
169+
proxyPort: proxyPort
170+
}, function() {
171+
console.log("Falling back to default proxy configuration:", proxyAddress);
172+
});
173+
174+
updateProxyConfiguration();
175+
}
76176

77-
// Load saved configuration at startup
78-
loadProxySettings();
79177

80-
/* PAC configuration */
81178
// direct everything to the forward-proxy except if the target is the forward-proxy, then go direct
82179
function updateProxyConfiguration() {
83180
const config = {
@@ -102,6 +199,13 @@ function updateProxyConfiguration() {
102199
});
103200
}
104201

202+
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
203+
if (request.action === "fetchAndApplyScionPAC") {
204+
fetchAndApplyScionPAC();
205+
return true;
206+
}
207+
});
208+
105209
/*--- storage ----------------------------------------------------------------*/
106210

107211
chrome.storage.onChanged.addListener((changes, namespace) => {

chrome/css/tailwind.min.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chrome/options.html

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -454,33 +454,43 @@ <h4 class="text-lg font-bold mb-2">Global strict mode</h4>
454454
<input class="absolute opacity-0" id="tab-single-four" type="radio" name="tabs2">
455455
<label class="block leading-normal cursor-pointer" for="tab-single-four">Proxy Configuration (Advanced)</label>
456456
<div class="tab-content overflow-hidden border-l-2 border-indigo-500 leading-normal">
457+
<div class="mb-4">
458+
<label class="flex items-center">
459+
<input type="checkbox" id="auto-proxy-config" class="mr-2 h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
460+
<span class="text-sm font-medium text-gray-700">Auto configuration</span>
461+
</label>
462+
<p class="text-xs text-gray-500 mt-1">Use WPAD and defualts to automatically detect proxy settings</p>
463+
</div>
464+
457465
<div class="flex justify-end mb-3">
458466
<button id="reset-proxy-defaults" class="px-3 py-1 text-xs text-gray-600 border border-gray-300 rounded-md hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-300">
459467
Set to Default
460468
</button>
461469
</div>
462470

463-
<div class="mb-3">
464-
<label class="block text-sm font-medium text-gray-700 mb-1">Protocol</label>
465-
<select id="proxy-scheme" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
466-
<option value="http">HTTP</option>
467-
<option value="https" selected>HTTPS</option>
468-
</select>
469-
</div>
470-
471-
<div class="mb-3">
472-
<label class="block text-sm font-medium text-gray-700 mb-1">Proxy Host</label>
473-
<input type="text" id="proxy-host" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="forward-proxy.scion">
474-
</div>
475-
476-
<div class="mb-3">
477-
<label class="block text-sm font-medium text-gray-700 mb-1">Port</label>
478-
<input type="text" id="proxy-port" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="9443">
471+
<div id="manual-proxy-settings">
472+
<div class="mb-3">
473+
<label class="block text-sm font-medium text-gray-700 mb-1">Protocol</label>
474+
<select id="proxy-scheme" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
475+
<option value="http">HTTP</option>
476+
<option value="https" selected>HTTPS</option>
477+
</select>
478+
</div>
479+
480+
<div class="mb-3">
481+
<label class="block text-sm font-medium text-gray-700 mb-1">Proxy Host</label>
482+
<input type="text" id="proxy-host" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="forward-proxy.scion">
483+
</div>
484+
485+
<div class="mb-3">
486+
<label class="block text-sm font-medium text-gray-700 mb-1">Port</label>
487+
<input type="text" id="proxy-port" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="9443">
488+
</div>
489+
490+
<button id="save-proxy-settings" class="px-4 py-2 bg-blue-100 text-blue-700 rounded-md hover:bg-blue-200 focus:outline-none focus:ring-2 focus:ring-blue-500">
491+
Save Proxy Settings
492+
</button>
479493
</div>
480-
481-
<button id="save-proxy-settings" class="px-4 py-2 bg-blue-100 text-blue-700 rounded-md hover:bg-blue-200 focus:outline-none focus:ring-2 focus:ring-blue-500">
482-
Save Proxy Settings
483-
</button>
484494
</div>
485495
</div>
486496
</div>

chrome/options.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,23 @@ checkBoxNewDomainStrictMode
231231
}
232232
});
233233

234+
function updateProxyFormState(isAutoConfig) {
235+
const manualControls = document.querySelectorAll('#manual-proxy-settings input, #manual-proxy-settings select, #manual-proxy-settings button, #reset-proxy-defaults');
236+
237+
manualControls.forEach(element => {
238+
element.disabled = isAutoConfig;
239+
if (isAutoConfig) {
240+
element.classList.add('opacity-50', 'cursor-not-allowed');
241+
} else {
242+
element.classList.remove('opacity-50', 'cursor-not-allowed');
243+
}
244+
});
245+
246+
if (isAutoConfig) {
247+
chrome.runtime.sendMessage({ action: "fetchAndApplyScionPAC" });
248+
}
249+
}
250+
234251
// Load saved settings
235252
document.addEventListener('DOMContentLoaded', function() {
236253
chrome.storage.sync.get({
@@ -242,9 +259,18 @@ document.addEventListener('DOMContentLoaded', function() {
242259
proxyHostElement.value = items.proxyHost;
243260
proxyPortElement.value = items.proxyPort;
244261
});
262+
263+
chrome.storage.sync.get({
264+
autoProxyConfig: true
265+
}, function(items) {
266+
document.getElementById('auto-proxy-config').checked = items.autoProxyConfig;
267+
updateProxyFormState(items.autoProxyConfig);
268+
});
245269

246270
document.getElementById('save-proxy-settings').addEventListener('click', saveProxySettings);
247271
document.getElementById('reset-proxy-defaults').addEventListener('click', resetProxyDefaults);
272+
document.getElementById('auto-proxy-config').addEventListener('change', saveAutoProxyConfig);
273+
248274
});
249275

250276
function saveProxySettings() {
@@ -279,4 +305,14 @@ function resetProxyDefaults() {
279305
proxySchemeElement.value = DEFAULT_PROXY_SCHEME;
280306
proxyHostElement.value = DEFAULT_PROXY_HOST;
281307
proxyPortElement.value = DEFAULT_PROXY_PORT;
282-
}
308+
}
309+
310+
function saveAutoProxyConfig() {
311+
const autoConfig = document.getElementById('auto-proxy-config').checked;
312+
313+
chrome.storage.sync.set({
314+
autoProxyConfig: autoConfig
315+
}, function() {
316+
updateProxyFormState(autoConfig);
317+
});
318+
}

chrome/popup.html

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,16 @@ <h3 id="scionsupport" class="text-lg text-left font-bold mb-3 mt-3"></h3>
5050
<hr />
5151

5252
<div class="flex p-1 shadow-sm">
53-
<article id="proxy-check-container" class="text-sm">
54-
<span id="proxy-status-message">Checking proxy status...</span>
55-
<a id="proxy-help-link" href="#" class="text-blue-600 hover:text-blue-800 ml-2 hidden">Need help?</a>
53+
<article id="proxy-check-container" class="text-sm w-full">
54+
<div class="ac">
55+
<input class="ac-input" id="proxy-status-toggle" name="proxy-status-toggle" type="checkbox" />
56+
<label for="proxy-status-toggle" class="ac-label flex items-center" id="proxy-status-label">
57+
<span id="proxy-status-message">Checking proxy status...</span>
58+
<a id="proxy-help-link" href="#" class="text-blue-600 hover:text-blue-800 ml-2 hidden">Need help?</a>
59+
</label>
60+
<article class="ac-text" id="proxy-details-content">
61+
</article>
62+
</div>
5663
</article>
5764
</div>
5865

chrome/popup.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,32 @@ function checkProxyStatus() {
9999

100100
fetch(`${proxyAddress}${proxyHealthCheckPath}`, {
101101
method: "GET",
102-
signal: AbortSignal.timeout(5000)
102+
signal: AbortSignal.timeout(2000)
103103
}).then(response => {
104104
if (response.status === 200) {
105-
proxyStatusMessage.textContent = "Proxy is connected";
105+
proxyStatusMessage.textContent = "Connected to proxy";
106106
proxyStatusMessage.innerHTML += " <span>&#x2705;</span> ";
107+
const proxyDetailsContent = document.getElementById('proxy-details-content');
108+
proxyDetailsContent.textContent = `Proxy at ${proxyAddress}`;
107109
// Hide the help link when everything is working
108110
proxyHelpLink.classList.add('hidden');
109111
} else {
110112
// Show error message for non-200 responses
111-
proxyStatusMessage.textContent = `Proxy connection error: ${response.status}`;
113+
console.warn("Proxy check failed:", response.status);
114+
proxyStatusMessage.textContent = "Failed to connect to proxy";
112115
proxyStatusMessage.innerHTML += " <span>#x274C;</span> ";
116+
const proxyDetailsContent = document.getElementById('proxy-details-content');
117+
proxyDetailsContent.textContent = `Proxy at ${proxyAddress}`;
113118
showProxyHelpLink();
114119
}
115120
}).catch(error => {
116121
// Handle network errors or timeouts
117-
console.error("Proxy check failed:", error);
122+
console.warn("Proxy check failed:", error);
118123
proxyStatusMessage.textContent = "Failed to connect to proxy";
119124
proxyStatusMessage.innerHTML += " <span>&#x274C;</span> ";
120125
showProxyHelpLink();
126+
const proxyDetailsContent = document.getElementById('proxy-details-content');
127+
proxyDetailsContent.textContent = `Proxy at ${proxyAddress}`;
121128
});
122129
}
123130

src/css/tailwind.css

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,4 +215,40 @@ input:checked ~ .dot2 {
215215
transform: rotateX(180deg);
216216
background-color: #6574cd;
217217
color: #f8fafc;
218+
}
219+
220+
/* ===== PROXY DETAILS STYLES ===== */
221+
#proxy-status-label {
222+
padding-left: 0.5em !important;
223+
}
224+
225+
#proxy-status-label:after {
226+
width: 0px !important;
227+
content: unset !important;
228+
}
229+
230+
/* Add a small indicator to show it's expandable */
231+
#proxy-status-message {
232+
position: relative;
233+
cursor: pointer;
234+
}
235+
236+
#proxy-status-message::before {
237+
content: "\25BC"; /* Black down-pointing triangle */
238+
font-size: 8px;
239+
color: #718096;
240+
margin-left: 4px;
241+
vertical-align: middle;
242+
display: inline-block;
243+
}
244+
245+
#proxy-status-toggle:checked ~ .ac-label #proxy-status-message::before {
246+
content: "\25B2"; /* Black up-pointing triangle */
247+
}
248+
249+
#proxy-details-content {
250+
font-size: 0.75rem;
251+
color: #718096;
252+
padding-left: 1rem;
253+
line-height: 1.2;
218254
}

0 commit comments

Comments
 (0)