Add proxy bypass setting and rewrite proxy logic

This commit is contained in:
Gregory Schier
2025-06-09 14:29:12 -07:00
parent 648a1ac53c
commit be0a8fc27a
4 changed files with 74 additions and 26 deletions

View File

@@ -7,7 +7,7 @@ use http::{HeaderMap, HeaderName, HeaderValue};
use log::{debug, error, warn}; use log::{debug, error, warn};
use mime_guess::Mime; use mime_guess::Mime;
use reqwest::redirect::Policy; use reqwest::redirect::Policy;
use reqwest::{Method, Response}; use reqwest::{Method, NoProxy, Response};
use reqwest::{Proxy, Url, multipart}; use reqwest::{Proxy, Url, multipart};
use serde_json::Value; use serde_json::Value;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@@ -120,25 +120,39 @@ pub async fn send_http_request<R: Runtime>(
https, https,
auth, auth,
disabled, disabled,
bypass,
}) if !disabled => { }) if !disabled => {
debug!("Using proxy http={http} https={https}"); debug!("Using proxy http={http} https={https} bypass={bypass}");
let mut proxy = Proxy::custom(move |url| { if !http.is_empty() {
let http = if http.is_empty() { None } else { Some(http.to_owned()) }; match Proxy::http(http) {
let https = if https.is_empty() { None } else { Some(https.to_owned()) }; Ok(mut proxy) => {
let proxy_url = match (url.scheme(), http, https) { if let Some(ProxySettingAuth { user, password }) = auth.clone() {
("http", Some(proxy_url), _) => Some(proxy_url), debug!("Using http proxy auth");
("https", _, Some(proxy_url)) => Some(proxy_url), proxy = proxy.basic_auth(user.as_str(), password.as_str());
_ => None, }
proxy = proxy.no_proxy(NoProxy::from_string(&bypass));
client_builder = client_builder.proxy(proxy);
}
Err(e) => {
warn!("Failed to apply http proxy {e:?}");
}
};
}
if !https.is_empty() {
match Proxy::https(https) {
Ok(mut proxy) => {
if let Some(ProxySettingAuth { user, password }) = auth {
debug!("Using https proxy auth");
proxy = proxy.basic_auth(user.as_str(), password.as_str());
}
proxy = proxy.no_proxy(NoProxy::from_string(&bypass));
client_builder = client_builder.proxy(proxy);
}
Err(e) => {
warn!("Failed to apply https proxy {e:?}");
}
}; };
proxy_url
});
if let Some(ProxySettingAuth { user, password }) = auth {
debug!("Using proxy auth");
proxy = proxy.basic_auth(user.as_str(), password.as_str());
} }
client_builder = client_builder.proxy(proxy);
} }
_ => {} // Nothing to do for this one, as it is the default _ => {} // Nothing to do for this one, as it is the default
} }

View File

@@ -58,7 +58,7 @@ export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt
export type PluginKeyValue = { model: "plugin_key_value", createdAt: string, updatedAt: string, pluginName: string, key: string, value: string, }; export type PluginKeyValue = { model: "plugin_key_value", createdAt: string, updatedAt: string, pluginName: string, key: string, value: string, };
export type ProxySetting = { "type": "enabled", disabled: boolean, http: string, https: string, auth: ProxySettingAuth | null, } | { "type": "disabled" }; export type ProxySetting = { "type": "enabled", disabled: boolean, http: string, https: string, auth: ProxySettingAuth | null, bypass: string, } | { "type": "disabled" };
export type ProxySettingAuth = { user: string, password: string, }; export type ProxySettingAuth = { user: string, password: string, };

View File

@@ -31,12 +31,15 @@ macro_rules! impl_model {
#[ts(export, export_to = "gen_models.ts")] #[ts(export, export_to = "gen_models.ts")]
pub enum ProxySetting { pub enum ProxySetting {
Enabled { Enabled {
#[serde(default)]
// This was added after on so give it a default to be able to deserialize older values
disabled: bool,
http: String, http: String,
https: String, https: String,
auth: Option<ProxySettingAuth>, auth: Option<ProxySettingAuth>,
// These were added later, so give them defaults
#[serde(default)]
bypass: String,
#[serde(default)]
disabled: bool,
}, },
Disabled, Disabled,
} }

View File

@@ -30,6 +30,7 @@ export function SettingsProxy() {
http: '', http: '',
https: '', https: '',
auth: { user: '', password: '' }, auth: { user: '', password: '' },
bypass: '',
}, },
}); });
} else { } else {
@@ -53,10 +54,11 @@ export function SettingsProxy() {
const { proxy } = settings; const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : ''; const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : ''; const https = proxy?.type === 'enabled' ? proxy.https : '';
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const auth = proxy?.type === 'enabled' ? proxy.auth : null; const auth = proxy?.type === 'enabled' ? proxy.auth : null;
const disabled = !enabled; const disabled = !enabled;
await patchModel(settings, { await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled }, proxy: { type: 'enabled', http, https, auth, disabled, bypass },
}); });
}} }}
/> />
@@ -73,6 +75,7 @@ export function SettingsProxy() {
onChange={async (http) => { onChange={async (http) => {
const { proxy } = settings; const { proxy } = settings;
const https = proxy?.type === 'enabled' ? proxy.https : ''; const https = proxy?.type === 'enabled' ? proxy.https : '';
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const auth = proxy?.type === 'enabled' ? proxy.auth : null; const auth = proxy?.type === 'enabled' ? proxy.auth : null;
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false; const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
await patchModel(settings, { await patchModel(settings, {
@@ -82,6 +85,7 @@ export function SettingsProxy() {
https, https,
auth, auth,
disabled, disabled,
bypass,
}, },
}); });
}} }}
@@ -98,10 +102,11 @@ export function SettingsProxy() {
onChange={async (https) => { onChange={async (https) => {
const { proxy } = settings; const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : ''; const http = proxy?.type === 'enabled' ? proxy.http : '';
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const auth = proxy?.type === 'enabled' ? proxy.auth : null; const auth = proxy?.type === 'enabled' ? proxy.auth : null;
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false; const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
await patchModel(settings, { await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled }, proxy: { type: 'enabled', http, https, auth, disabled, bypass },
}); });
}} }}
/> />
@@ -115,9 +120,10 @@ export function SettingsProxy() {
const http = proxy?.type === 'enabled' ? proxy.http : ''; const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : ''; const https = proxy?.type === 'enabled' ? proxy.https : '';
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false; const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const auth = enabled ? { user: '', password: '' } : null; const auth = enabled ? { user: '', password: '' } : null;
await patchModel(settings, { await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled }, proxy: { type: 'enabled', http, https, auth, disabled, bypass },
}); });
}} }}
/> />
@@ -135,10 +141,11 @@ export function SettingsProxy() {
const http = proxy?.type === 'enabled' ? proxy.http : ''; const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : ''; const https = proxy?.type === 'enabled' ? proxy.https : '';
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false; const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const password = proxy?.type === 'enabled' ? (proxy.auth?.password ?? '') : ''; const password = proxy?.type === 'enabled' ? (proxy.auth?.password ?? '') : '';
const auth = { user, password }; const auth = { user, password };
await patchModel(settings, { await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled }, proxy: { type: 'enabled', http, https, auth, disabled, bypass },
}); });
}} }}
/> />
@@ -153,15 +160,39 @@ export function SettingsProxy() {
const http = proxy?.type === 'enabled' ? proxy.http : ''; const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : ''; const https = proxy?.type === 'enabled' ? proxy.https : '';
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false; const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const bypass = proxy?.type === 'enabled' ? proxy.bypass : '';
const user = proxy?.type === 'enabled' ? (proxy.auth?.user ?? '') : ''; const user = proxy?.type === 'enabled' ? (proxy.auth?.user ?? '') : '';
const auth = { user, password }; const auth = { user, password };
await patchModel(settings, { await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled }, proxy: { type: 'enabled', http, https, auth, disabled, bypass },
}); });
}} }}
/> />
</HStack> </HStack>
)} )}
{settings.proxy.type === 'enabled' && (
<>
<Separator className="my-6" />
<PlainInput
label="Proxy Bypass"
help="Comma-separated list to bypass the proxy."
defaultValue={settings.proxy.bypass}
placeholder="127.0.0.1, *.example.com, localhost:3000"
onChange={async (bypass) => {
const { proxy } = settings;
const http = proxy?.type === 'enabled' ? proxy.http : '';
const https = proxy?.type === 'enabled' ? proxy.https : '';
const disabled = proxy?.type === 'enabled' ? proxy.disabled : false;
const user = proxy?.type === 'enabled' ? (proxy.auth?.user ?? '') : '';
const password = proxy?.type === 'enabled' ? (proxy.auth?.password ?? '') : '';
const auth = { user, password };
await patchModel(settings, {
proxy: { type: 'enabled', http, https, auth, disabled, bypass },
});
}}
/>
</>
)}
</VStack> </VStack>
)} )}
</VStack> </VStack>