Skip to content

Commit

Permalink
Merge pull request #350 from ramajd/features/proxy-support
Browse files Browse the repository at this point in the history
Features/proxy support
  • Loading branch information
casperstorm authored Apr 26, 2024
2 parents ccb79f0 + 733a24b commit cad4c7b
Show file tree
Hide file tree
Showing 17 changed files with 229 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Added:
- User information added to context menu
- Support for IRCv3 CAP NEW and CAP DEL subcommands
- Enable support for IRCv3 `multi-prefix`
- Added support for `socks5` proxy configuration (see [proxy configuration](https://halloy.squidowl.org/configuration/proxy.html))

Changed:

Expand Down
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [Font](configuration/font.md)
- [Keyboard](configuration/keyboard.md)
- [Notifications](configuration/notifications.md)
- [Proxy](configuration/proxy.md)
- [Scale factor](configuration/scale-factor.md)
- [Servers](configuration/servers.md)
- [Sidebar](configuration/sidebar.md)
Expand Down
20 changes: 20 additions & 0 deletions book/src/configuration/proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Proxy

## `[proxy]` Section

Example

```toml
[proxy]
type = "socks5"
host = "<string>"
port = <integer>
```

| Key | Description | Default |
| :--------- | :------------------------------------------------ | :---------- |
| `type` | Proxy type. Only `socks5` is currently supported. | `""` |
| `host` | Proxy host to connect to | `""` |
| `port` | Proxy port to connect on | `""` |
| `username` | Proxy username, optional | `""` |
| `password` | Proxy password, optional | `""` |
6 changes: 6 additions & 0 deletions data/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub use self::channel::Channel;
pub use self::file_transfer::FileTransfer;
pub use self::keys::Keyboard;
pub use self::notification::{Notification, Notifications};
pub use self::proxy::Proxy;
pub use self::server::Server;
pub use self::sidebar::Sidebar;
use crate::environment::config_dir;
Expand All @@ -22,6 +23,7 @@ pub mod channel;
pub mod file_transfer;
mod keys;
pub mod notification;
pub mod proxy;
pub mod server;
pub mod sidebar;

Expand All @@ -32,6 +34,7 @@ const DEFAULT_THEME_FILE_NAME: &str = "ferra.toml";
pub struct Config {
pub themes: Themes,
pub servers: ServerMap,
pub proxy: Option<Proxy>,
pub font: Font,
pub scale_factor: ScaleFactor,
pub buffer: Buffer,
Expand Down Expand Up @@ -117,6 +120,7 @@ impl Config {
#[serde(default)]
pub theme: String,
pub servers: ServerMap,
pub proxy: Option<Proxy>,
#[serde(default)]
pub font: Font,
#[serde(default)]
Expand All @@ -142,6 +146,7 @@ impl Config {
theme,
mut servers,
font,
proxy,
scale_factor,
buffer,
sidebar,
Expand All @@ -159,6 +164,7 @@ impl Config {
themes,
servers,
font,
proxy,
scale_factor,
buffer,
sidebar,
Expand Down
30 changes: 30 additions & 0 deletions data/src/config/proxy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use serde::Deserialize;

#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Kind {
Socks5,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Proxy {
#[serde(rename = "type")]
pub kind: Kind,
pub host: String,
pub port: u16,
pub username: Option<String>,
pub password: Option<String>,
}

impl From<Proxy> for irc::connection::Proxy {
fn from(proxy: Proxy) -> irc::connection::Proxy {
match proxy.kind {
Kind::Socks5 => irc::connection::Proxy::Socks5 {
host: proxy.host,
port: proxy.port,
username: proxy.username,
password: proxy.password,
},
}
}
}
15 changes: 11 additions & 4 deletions data/src/config/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::time::Duration;
use irc::connection;
use serde::{Deserialize, Deserializer};

use crate::config;

#[derive(Debug, Clone, Default, Deserialize)]
pub struct Server {
/// The client's nickname.
Expand Down Expand Up @@ -87,7 +89,7 @@ pub struct Server {
}

impl Server {
pub fn connection(&self) -> connection::Config {
pub fn connection(&self, proxy: Option<config::Proxy>) -> connection::Config {
let security = if self.use_tls {
connection::Security::Secured {
accept_invalid_certs: self.dangerously_accept_invalid_certs,
Expand All @@ -103,6 +105,7 @@ impl Server {
server: &self.server,
port: self.port,
security,
proxy: proxy.map(From::from),
}
}
}
Expand All @@ -123,7 +126,7 @@ pub enum Sasl {
/// Account password,
password: Option<String>,
/// Account password file
password_file: Option<String>
password_file: Option<String>,
},
External {
/// The path to PEM encoded X509 user certificate for external auth
Expand All @@ -143,10 +146,14 @@ impl Sasl {

pub fn param(&self) -> String {
match self {
Sasl::Plain { username, password, .. } => {
Sasl::Plain {
username, password, ..
} => {
use base64::engine::Engine;

let password = password.as_ref().expect("SASL password must exist at this point!");
let password = password
.as_ref()
.expect("SASL password must exist at this point!");

base64::engine::general_purpose::STANDARD
.encode(format!("{username}\x00{username}\x00{password}"))
Expand Down
20 changes: 16 additions & 4 deletions data/src/file_transfer/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl Manager {
})
}

pub fn send(&mut self, request: SendRequest) -> Option<Event> {
pub fn send(&mut self, request: SendRequest, proxy: Option<config::Proxy>) -> Option<Event> {
let SendRequest {
to,
path,
Expand Down Expand Up @@ -117,7 +117,11 @@ impl Manager {
};

let task = Task::send(id, path, filename, to, reverse, server_handle);
let (handle, stream) = task.spawn(self.server(), Duration::from_secs(self.config.timeout));
let (handle, stream) = task.spawn(
self.server(),
Duration::from_secs(self.config.timeout),
proxy,
);

self.items.insert(
id,
Expand All @@ -130,7 +134,11 @@ impl Manager {
Some(Event::NewTransfer(file_transfer, stream.boxed()))
}

pub fn receive(&mut self, request: ReceiveRequest) -> Option<Event> {
pub fn receive(
&mut self,
request: ReceiveRequest,
proxy: Option<&config::Proxy>,
) -> Option<Event> {
let ReceiveRequest {
from,
dcc_send,
Expand Down Expand Up @@ -184,7 +192,11 @@ impl Manager {
};

let task = Task::receive(id, dcc_send, from, server_handle);
let (handle, stream) = task.spawn(self.server(), Duration::from_secs(self.config.timeout));
let (handle, stream) = task.spawn(
self.server(),
Duration::from_secs(self.config.timeout),
proxy.cloned(),
);

self.items.insert(
id,
Expand Down
9 changes: 8 additions & 1 deletion data/src/file_transfer/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use tokio::{
use tokio_stream::StreamExt;

use super::Id;
use crate::{dcc, server, user::Nick};
use crate::{config, dcc, server, user::Nick};

/// 16 KiB
pub const BUFFER_SIZE: usize = 16 * 1024;
Expand Down Expand Up @@ -109,6 +109,7 @@ impl Task {
self,
server: Option<Server>,
timeout: Duration,
proxy: Option<config::Proxy>,
) -> (Handle, impl Stream<Item = Update>) {
let (action_sender, action_receiver) = mpsc::channel(1);
let (update_sender, update_receiver) = mpsc::channel(100);
Expand All @@ -132,6 +133,7 @@ impl Task {
update_sender,
server,
timeout,
proxy,
)
.await
{
Expand All @@ -157,6 +159,7 @@ impl Task {
update_sender,
server,
timeout,
proxy,
)
.await
{
Expand Down Expand Up @@ -214,6 +217,7 @@ async fn receive(
mut update: Sender<Update>,
server: Option<Server>,
timeout: Duration,
proxy: Option<config::Proxy>,
) -> Result<(), Error> {
// Wait for approval
let Some(Action::Approve { save_to }) = action.next().await else {
Expand Down Expand Up @@ -281,6 +285,7 @@ async fn receive(
server: &host.to_string(),
port: port.get(),
security: connection::Security::Unsecured,
proxy: proxy.map(From::from),
},
BytesCodec::new(),
)
Expand Down Expand Up @@ -356,6 +361,7 @@ async fn send(
mut update: Sender<Update>,
server: Option<Server>,
timeout: Duration,
proxy: Option<config::Proxy>,
) -> Result<(), Error> {
let mut file = File::open(path).await?;
let size = file.metadata().await?.len();
Expand Down Expand Up @@ -394,6 +400,7 @@ async fn send(
server: &host.to_string(),
port: port.get(),
security: connection::Security::Unsecured,
proxy: proxy.map(From::from),
},
BytesCodec::new(),
)
Expand Down
10 changes: 7 additions & 3 deletions data/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use irc::proto;
use serde::{Deserialize, Serialize};

use crate::config;
use crate::config::Error;
use crate::config::server::Sasl;
use crate::config::Error;

pub type Handle = Sender<proto::Message>;

Expand Down Expand Up @@ -66,14 +66,18 @@ impl Map {
for (_, config) in self.0.iter_mut() {
if let Some(pass_file) = &config.password_file {
if config.password.is_some() {
return Err(Error::Parse("Only one of password and password_file can be set.".to_string()));
return Err(Error::Parse(
"Only one of password and password_file can be set.".to_string(),
));
}
let pass = fs::read_to_string(pass_file)?;
config.password = Some(pass);
}
if let Some(nick_pass_file) = &config.nick_password_file {
if config.nick_password.is_some() {
return Err(Error::Parse("Only one of nick_password and nick_password_file can be set.".to_string()));
return Err(Error::Parse(
"Only one of nick_password and nick_password_file can be set.".to_string(),
));
}
let nick_pass = fs::read_to_string(nick_pass_file)?;
config.nick_password = Some(nick_pass);
Expand Down
11 changes: 8 additions & 3 deletions data/src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ struct Stream {
receiver: mpsc::Receiver<proto::Message>,
}

pub async fn run(server: server::Entry, mut sender: mpsc::Sender<Update>) -> Never {
pub async fn run(
server: server::Entry,
proxy: Option<config::Proxy>,
mut sender: mpsc::Sender<Update>,
) -> Never {
let server::Entry { server, config } = server;

let reconnect_delay = Duration::from_secs(config.reconnect_delay);
Expand Down Expand Up @@ -96,7 +100,7 @@ pub async fn run(server: server::Entry, mut sender: mpsc::Sender<Update>) -> Nev
}
}

match connect(server.clone(), config.clone()).await {
match connect(server.clone(), config.clone(), proxy.clone()).await {
Ok((stream, client)) => {
log::info!("[{server}] connected");

Expand Down Expand Up @@ -253,8 +257,9 @@ pub async fn run(server: server::Entry, mut sender: mpsc::Sender<Update>) -> Nev
async fn connect(
server: Server,
config: config::Server,
proxy: Option<config::Proxy>,
) -> Result<(Stream, Client), connection::Error> {
let connection = Connection::new(config.connection(), irc::Codec).await?;
let connection = Connection::new(config.connection(proxy), irc::Codec).await?;

let (sender, receiver) = mpsc::channel(100);

Expand Down
1 change: 1 addition & 0 deletions irc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"

[dependencies]
bytes = "1.4.0"
fast-socks5 = "0.9.6"
futures = "0.3.28"
thiserror = "1.0.30"
tokio = { version = "1.29", features = ["net", "full"] }
Expand Down
Loading

0 comments on commit cad4c7b

Please sign in to comment.