mirror of
				https://github.com/dani-garcia/vaultwarden.git
				synced 2025-10-31 13:51:14 +00:00 
			
		
		
		
	Merge pull request #1587 from RealOrangeOne/request-proxy
Allow outbound requests to go via a proxy
This commit is contained in:
		
				commit
				
					
						4bb0d7bc05
					
				
			
		
					 7 changed files with 73 additions and 24 deletions
				
			
		
							
								
								
									
										39
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										39
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -563,6 +563,12 @@ version = "0.15.0" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "either" | ||||
| version = "1.6.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "encoding_rs" | ||||
| version = "0.8.28" | ||||
|  | @ -2213,6 +2219,7 @@ dependencies = [ | |||
|  "serde_urlencoded", | ||||
|  "tokio", | ||||
|  "tokio-native-tls", | ||||
|  "tokio-socks", | ||||
|  "tokio-util", | ||||
|  "url 2.2.1", | ||||
|  "wasm-bindgen", | ||||
|  | @ -2767,6 +2774,26 @@ dependencies = [ | |||
|  "utf-8", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "thiserror" | ||||
| version = "1.0.24" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" | ||||
| dependencies = [ | ||||
|  "thiserror-impl", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "thiserror-impl" | ||||
| version = "1.0.24" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.24", | ||||
|  "quote 1.0.9", | ||||
|  "syn 1.0.65", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "threadpool" | ||||
| version = "1.8.1" | ||||
|  | @ -2865,6 +2892,18 @@ dependencies = [ | |||
|  "tokio", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "tokio-socks" | ||||
| version = "0.5.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" | ||||
| dependencies = [ | ||||
|  "either", | ||||
|  "futures-util", | ||||
|  "thiserror", | ||||
|  "tokio", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "tokio-util" | ||||
| version = "0.6.5" | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ rocket = { version = "0.5.0-dev", features = ["tls"], default-features = false } | |||
| rocket_contrib = "0.5.0-dev" | ||||
| 
 | ||||
| # HTTP client | ||||
| reqwest = { version = "0.11.2", features = ["blocking", "json", "gzip", "brotli"] } | ||||
| reqwest = { version = "0.11.2", features = ["blocking", "json", "gzip", "brotli", "socks"] } | ||||
| 
 | ||||
| # multipart/form-data support | ||||
| multipart = { version = "0.17.1", features = ["server"], default-features = false } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ use serde::de::DeserializeOwned; | |||
| use serde_json::Value; | ||||
| use std::{env, time::Duration}; | ||||
| 
 | ||||
| use reqwest::{blocking::Client, header::USER_AGENT}; | ||||
| 
 | ||||
| use rocket::{ | ||||
|     http::{Cookie, Cookies, SameSite}, | ||||
|     request::{self, FlashMessage, Form, FromRequest, Outcome, Request}, | ||||
|  | @ -19,7 +19,7 @@ use crate::{ | |||
|     db::{backup_database, get_sql_server_version, models::*, DbConn, DbConnType}, | ||||
|     error::{Error, MapResult}, | ||||
|     mail, | ||||
|     util::{format_naive_datetime_local, get_display_size, is_running_in_docker}, | ||||
|     util::{format_naive_datetime_local, get_display_size, is_running_in_docker, get_reqwest_client}, | ||||
|     CONFIG, | ||||
| }; | ||||
| 
 | ||||
|  | @ -469,24 +469,22 @@ struct GitCommit { | |||
| } | ||||
| 
 | ||||
| fn get_github_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> { | ||||
|     let github_api = Client::builder().build()?; | ||||
|     let github_api = get_reqwest_client(); | ||||
| 
 | ||||
|     Ok(github_api | ||||
|         .get(url) | ||||
|         .timeout(Duration::from_secs(10)) | ||||
|         .header(USER_AGENT, "Bitwarden_RS") | ||||
|         .send()? | ||||
|         .error_for_status()? | ||||
|         .json::<T>()?) | ||||
| } | ||||
| 
 | ||||
| fn has_http_access() -> bool { | ||||
|     let http_access = Client::builder().build().unwrap(); | ||||
|     let http_access = get_reqwest_client(); | ||||
| 
 | ||||
|     match http_access | ||||
|         .head("https://github.com/dani-garcia/bitwarden_rs") | ||||
|         .timeout(Duration::from_secs(10)) | ||||
|         .header(USER_AGENT, "Bitwarden_RS") | ||||
|         .send() | ||||
|     { | ||||
|         Ok(r) => r.status().is_success(), | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ use crate::{ | |||
|     auth::Headers, | ||||
|     db::DbConn, | ||||
|     error::Error, | ||||
|     util::get_reqwest_client, | ||||
| }; | ||||
| 
 | ||||
| #[put("/devices/identifier/<uuid>/clear-token")] | ||||
|  | @ -147,20 +148,16 @@ fn put_eq_domains(data: JsonUpcase<EquivDomainData>, headers: Headers, conn: DbC | |||
| 
 | ||||
| #[get("/hibp/breach?<username>")] | ||||
| fn hibp_breach(username: String) -> JsonResult { | ||||
|     let user_agent = "Bitwarden_RS"; | ||||
|     let url = format!( | ||||
|         "https://haveibeenpwned.com/api/v3/breachedaccount/{}?truncateResponse=false&includeUnverified=false", | ||||
|         username | ||||
|     ); | ||||
| 
 | ||||
|     use reqwest::{blocking::Client, header::USER_AGENT}; | ||||
| 
 | ||||
|     if let Some(api_key) = crate::CONFIG.hibp_api_key() { | ||||
|         let hibp_client = Client::builder().build()?; | ||||
|         let hibp_client = get_reqwest_client(); | ||||
| 
 | ||||
|         let res = hibp_client | ||||
|             .get(&url) | ||||
|             .header(USER_AGENT, user_agent) | ||||
|             .header("hibp-api-key", api_key) | ||||
|             .send()?; | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ use crate::{ | |||
|         DbConn, | ||||
|     }, | ||||
|     error::MapResult, | ||||
|     util::get_reqwest_client, | ||||
|     CONFIG, | ||||
| }; | ||||
| 
 | ||||
|  | @ -185,9 +186,7 @@ fn activate_duo_put(data: JsonUpcase<EnableDuoData>, headers: Headers, conn: DbC | |||
| } | ||||
| 
 | ||||
| fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> EmptyResult { | ||||
|     const AGENT: &str = "bitwarden_rs:Duo/1.0 (Rust)"; | ||||
| 
 | ||||
|     use reqwest::{blocking::Client, header::*, Method}; | ||||
|     use reqwest::{header, Method}; | ||||
|     use std::str::FromStr; | ||||
| 
 | ||||
|     // https://duo.com/docs/authapi#api-details
 | ||||
|  | @ -199,11 +198,12 @@ fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> Em | |||
| 
 | ||||
|     let m = Method::from_str(method).unwrap_or_default(); | ||||
| 
 | ||||
|     Client::new() | ||||
|         .request(m, &url) | ||||
|     let client = get_reqwest_client(); | ||||
| 
 | ||||
|     client.request(m, &url) | ||||
|         .basic_auth(username, Some(password)) | ||||
|         .header(USER_AGENT, AGENT) | ||||
|         .header(DATE, date) | ||||
|         .header(header::USER_AGENT, "bitwarden_rs:Duo/1.0 (Rust)") | ||||
|         .header(header::DATE, date) | ||||
|         .send()? | ||||
|         .error_for_status()?; | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ use regex::Regex; | |||
| use reqwest::{blocking::Client, blocking::Response, header, Url}; | ||||
| use rocket::{http::ContentType, http::Cookie, response::Content, Route}; | ||||
| 
 | ||||
| use crate::{error::Error, util::Cached, CONFIG}; | ||||
| use crate::{error::Error, util::{Cached, get_reqwest_client_builder}, CONFIG}; | ||||
| 
 | ||||
| pub fn routes() -> Vec<Route> { | ||||
|     routes![icon] | ||||
|  | @ -28,11 +28,11 @@ static CLIENT: Lazy<Client> = Lazy::new(|| { | |||
|     default_headers.insert(header::ACCEPT, header::HeaderValue::from_static("text/html,application/xhtml+xml,application/xml; q=0.9,image/webp,image/apng,*/*;q=0.8")); | ||||
| 
 | ||||
|     // Reuse the client between requests
 | ||||
|     Client::builder() | ||||
|     get_reqwest_client_builder() | ||||
|         .timeout(Duration::from_secs(CONFIG.icon_download_timeout())) | ||||
|         .default_headers(default_headers) | ||||
|         .build() | ||||
|         .unwrap() | ||||
|         .expect("Failed to build icon client") | ||||
| }); | ||||
| 
 | ||||
| // Build Regex only once since this takes a lot of time.
 | ||||
|  |  | |||
							
								
								
									
										19
									
								
								src/util.rs
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								src/util.rs
									
										
									
									
									
								
							|  | @ -478,7 +478,6 @@ pub fn retry<F, T, E>(func: F, max_tries: u32) -> Result<T, E> | |||
| where | ||||
|     F: Fn() -> Result<T, E>, | ||||
| { | ||||
|     use std::{thread::sleep, time::Duration}; | ||||
|     let mut tries = 0; | ||||
| 
 | ||||
|     loop { | ||||
|  | @ -497,12 +496,13 @@ where | |||
|     } | ||||
| } | ||||
| 
 | ||||
| use std::{thread::sleep, time::Duration}; | ||||
| 
 | ||||
| pub fn retry_db<F, T, E>(func: F, max_tries: u32) -> Result<T, E> | ||||
| where | ||||
|     F: Fn() -> Result<T, E>, | ||||
|     E: std::error::Error, | ||||
| { | ||||
|     use std::{thread::sleep, time::Duration}; | ||||
|     let mut tries = 0; | ||||
| 
 | ||||
|     loop { | ||||
|  | @ -522,3 +522,18 @@ where | |||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| use reqwest::{blocking::{Client, ClientBuilder}, header}; | ||||
| 
 | ||||
| pub fn get_reqwest_client() -> Client { | ||||
|     get_reqwest_client_builder().build().expect("Failed to build client") | ||||
| } | ||||
| 
 | ||||
| pub fn get_reqwest_client_builder() -> ClientBuilder { | ||||
|     let mut headers = header::HeaderMap::new(); | ||||
|     headers.insert(header::USER_AGENT, header::HeaderValue::from_static("Bitwarden_RS")); | ||||
|     Client::builder() | ||||
|         .default_headers(headers) | ||||
|         .timeout(Duration::from_secs(10)) | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue