Skip to content
This repository was archived by the owner on Jul 6, 2024. It is now read-only.

Commit ef0d22a

Browse files
committed
feat: Proxy Support
Add support to specify an https or socks5 proxy for the network requests.
1 parent dc5a732 commit ef0d22a

File tree

3 files changed

+63
-5
lines changed

3 files changed

+63
-5
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "proton-api-rs"
33
authors = ["Leander Beernaert <lbb-dev@pm.me>"]
4-
version = "0.1.4"
4+
version = "0.2.0"
55
edition = "2021"
66
license = "AGPL-3.0-only"
77
description = "Unofficial implemention of proton REST API in rust"
@@ -28,7 +28,7 @@ log = "0.4"
2828
[dependencies.reqwest]
2929
version = "0.11"
3030
default-features = false
31-
features = ["json", "deflate", "stream", "cookies", "multipart", "rustls","rustls-tls"]
31+
features = ["json", "deflate", "stream", "cookies", "multipart", "rustls","rustls-tls", "socks"]
3232

3333
[target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
3434
tokio = {version ="1", features = ["full"]}

src/client/client_builder.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use crate::client::types::{
33
FIDO2Auth, TFAAuth, TFAStatus, UserAuth,
44
};
55
use crate::client::{HttpClientBuilder, X_PM_UID_HEADER};
6-
use crate::domain::UserUid;
6+
use crate::domain::{SecretString, UserUid};
77
use crate::{impl_error_conversion, Client, RequestError};
88
use go_srp::SRPAuth;
9+
use secrecy::ExposeSecret;
910
use std::time::Duration;
1011
use thiserror::Error;
1112

@@ -47,6 +48,43 @@ impl Default for ClientBuilder {
4748
}
4849
}
4950

51+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
52+
pub enum ProxyProtocol {
53+
Https,
54+
Socks5,
55+
}
56+
57+
#[derive(Debug, Clone)]
58+
pub struct ProxyAuth {
59+
pub username: String,
60+
pub password: SecretString,
61+
}
62+
63+
#[derive(Debug, Clone)]
64+
pub struct Proxy {
65+
pub protocol: ProxyProtocol,
66+
pub auth: Option<ProxyAuth>,
67+
pub url: String,
68+
pub port: u16,
69+
}
70+
71+
impl Proxy {
72+
pub fn as_url(&self) -> String {
73+
let protocol = match self.protocol {
74+
ProxyProtocol::Https => "https",
75+
ProxyProtocol::Socks5 => "socks5",
76+
};
77+
78+
let auth = if let Some(auth) = &self.auth {
79+
format!("{}:{}", auth.username, auth.password.expose_secret())
80+
} else {
81+
String::new()
82+
};
83+
84+
format!("{protocol}://{auth}@{}:{}", self.url, self.port)
85+
}
86+
}
87+
5088
impl ClientBuilder {
5189
pub fn new() -> Self {
5290
Self(Default::default())
@@ -77,6 +115,12 @@ impl ClientBuilder {
77115
self
78116
}
79117

118+
/// Set the proxy for this client. By default no proxy is used
119+
pub fn with_proxy(mut self, proxy: Proxy) -> Self {
120+
self.0 = self.0.with_proxy(proxy);
121+
self
122+
}
123+
80124
/// Login into a proton account and start a new session.
81125
/// Note: At the moment we only support TOTP 2FA, `LoginError::Unsupported2FA` will returned
82126
/// if anther 2FA method is enabled.

src/client/http_client/reqwest_client.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::client::{DEFAULT_APP_VERSION, DEFAULT_HOST_URL, X_PM_APP_VERSION_HEADER};
2-
use crate::{APIError, HttpClientError, RequestError};
2+
use crate::{APIError, HttpClientError, Proxy, RequestError};
33
use serde::de::DeserializeOwned;
44
use serde::{Deserialize, Serialize};
55
use std::time::Duration;
@@ -18,6 +18,7 @@ pub struct HttpClientBuilder {
1818
base_url: String,
1919
request_timeout: Duration,
2020
user_agent: String,
21+
proxy_url: Option<Proxy>,
2122
}
2223

2324
impl Default for HttpClientBuilder {
@@ -33,6 +34,7 @@ impl HttpClientBuilder {
3334
user_agent: "NoClient/0.1.0".to_string(),
3435
base_url: DEFAULT_HOST_URL.to_string(),
3536
request_timeout: Duration::from_secs(5),
37+
proxy_url: None,
3638
}
3739
}
3840

@@ -61,6 +63,12 @@ impl HttpClientBuilder {
6163
self
6264
}
6365

66+
/// Specify proxy URL for the builder.
67+
pub fn with_proxy(mut self, proxy: Proxy) -> Self {
68+
self.proxy_url = Some(proxy);
69+
self
70+
}
71+
6472
/// Constructs the http client
6573
pub fn build(self) -> Result<HttpClient, HttpClientError> {
6674
HttpClient::new(self)
@@ -76,10 +84,16 @@ impl HttpClient {
7684
.map_err(|e| HttpClientError::Other(anyhow::format_err!(e)))?,
7785
);
7886

79-
let builder = reqwest::ClientBuilder::new();
87+
let mut builder = reqwest::ClientBuilder::new();
8088
#[cfg(not(target_arch = "wasm32"))]
8189
let builder = {
8290
use reqwest::tls::Version;
91+
92+
if let Some(proxy) = http_builder.proxy_url {
93+
let proxy = reqwest::Proxy::all(proxy.as_url())?;
94+
builder = builder.proxy(proxy);
95+
}
96+
8397
builder
8498
.min_tls_version(Version::TLS_1_2)
8599
.https_only(true)

0 commit comments

Comments
 (0)