]> git.r.bdr.sh - rbdr/olden-mail/commitdiff
First approach
authorRuben Beltran del Rio <redacted>
Fri, 24 Jan 2025 19:34:35 +0000 (20:34 +0100)
committerRuben Beltran del Rio <redacted>
Fri, 24 Jan 2025 19:34:35 +0000 (20:34 +0100)
.gitignore [new file with mode: 0644]
Cargo.lock [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
Makefile [new file with mode: 0644]
src/configuration.rs [new file with mode: 0644]
src/main.rs [new file with mode: 0644]
src/proxy.rs [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..ea8c4bf
--- /dev/null
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644 (file)
index 0000000..2a7a129
--- /dev/null
@@ -0,0 +1,365 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "bitflags"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
+
+[[package]]
+name = "cc"
+version = "1.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "errno"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.169"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
+[[package]]
+name = "log"
+version = "0.4.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
+
+[[package]]
+name = "native-tls"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "olden-mail"
+version = "0.1.0"
+dependencies = [
+ "native-tls",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+
+[[package]]
+name = "openssl"
+version = "0.10.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "schannel"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "security-framework"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "syn"
+version = "2.0.96"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "getrandom",
+ "once_cell",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..a7114b2
--- /dev/null
@@ -0,0 +1,7 @@
+[package]
+name = "olden-mail"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+native-tls = "0.2.12"
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..8b3fd7b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,83 @@
+profile := dev
+target = $(shell rustc -vV | grep host | awk '{print $$2}')
+architectures := x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu
+app_name := olden-mail
+
+default: build
+
+set_rust:
+       rustup default stable
+
+prepare:
+       rustup target add $(target)
+
+build: prepare
+       cargo build --profile $(profile) --target $(target)
+
+test:
+       cargo test
+
+coverage:
+       cargo tarpaulin
+
+format:
+       cargo fmt && cargo clippy --fix
+
+lint:
+       cargo fmt -- --check && cargo clippy
+
+release: rpm tar deb
+       @$(eval filename := $(app_name)-$(target)-$(channel))
+
+$(architectures):
+ifneq ($(channel),)
+       $(MAKE) -e channel=$(channel) -e target=$@ release
+else
+       $(MAKE) -e target=$@ build
+endif
+
+deb: build
+ifeq ($(findstring linux,$(target)),linux)
+       @$(eval filename := $(app_name)-$(target)-$(channel))
+       cargo deb --profile $(profile) --target $(target)
+       mv target/$(target)/debian/*.deb $(filename).deb
+       sha256sum $(filename).deb > $(filename).deb.sha256
+       rsync -avz $(filename).deb deploy@conchos.unlimited.pizza:/srv/http/build.r.bdr.sh/$(app_name)
+       rsync -avz $(filename).deb.sha256 deploy@conchos.unlimited.pizza:/srv/http/build.r.bdr.sh/$(app_name)
+endif
+
+rpm: build
+ifeq ($(findstring linux,$(target)),linux)
+       @$(eval filename := $(app_name)-$(target)-$(channel))
+       cargo generate-rpm --profile $(profile) --target $(target)
+       mv target/$(target)/generate-rpm/*.rpm $(filename).rpm
+       sha256sum $(filename).rpm > $(filename).rpm.sha256
+       rsync -avz $(filename).rpm deploy@conchos.unlimited.pizza:/srv/http/build.r.bdr.sh/$(app_name)
+       rsync -avz $(filename).rpm.sha256 deploy@conchos.unlimited.pizza:/srv/http/build.r.bdr.sh/$(app_name)
+endif
+
+tar: build
+       @$(eval filename := $(app_name)-$(target)-$(channel))
+       tar -czvf $(filename).tar.gz -C target/$(target)/$(profile)/ $(app_name)
+       sha256sum $(filename).tar.gz > $(filename).tar.gz.sha256
+       rsync -avz $(filename).tar.gz deploy@conchos.unlimited.pizza:/srv/http/build.r.bdr.sh/$(app_name)
+       rsync -avz $(filename).tar.gz.sha256 deploy@conchos.unlimited.pizza:/srv/http/build.r.bdr.sh/$(app_name)
+
+package: $(architectures)
+
+mac:
+       @$(eval mac_architectures := x86_64-apple-darwin aarch64-apple-darwin)
+ifeq ($(tag),)
+       $(MAKE) -e profile=release -e architectures='$(mac_architectures)' -e channel=unstable package
+else
+       $(MAKE) -e profile=release -e architectures='$(mac_architectures)' -e channel=$(tag) package
+endif
+
+ci: lint coverage
+ifeq ($(GIT_REF),refs/heads/main)
+       $(MAKE) -e profile=release -e channel=unstable package
+else ifneq (,$(findstring refs/tags/,$(GIT_REF)))
+       $(MAKE) -e profile=release -e channel=$(subst refs/tags/,,$(GIT_REF)) package
+endif
+
+.PHONY: default build $(architectures) rpm package prepare set_rust ci release test coverage format
diff --git a/src/configuration.rs b/src/configuration.rs
new file mode 100644 (file)
index 0000000..1437594
--- /dev/null
@@ -0,0 +1,45 @@
+use std::env;
+use std::sync::Arc;
+
+pub struct ProxyConfiguration {
+    pub local_port: u16,
+    pub remote_domain: String,
+    pub remote_port: u16,
+    pub protocol: &'static str,
+}
+
+pub struct Configuration {
+    pub imap_configuration: Arc<ProxyConfiguration>,
+    pub smtp_configuration: Arc<ProxyConfiguration>,
+}
+
+impl Configuration {
+    pub fn new() -> Self {
+        Configuration {
+            imap_configuration: Arc::new(ProxyConfiguration {
+                local_port: env::var("LOCAL_IMAP_PORT")
+                    .expect("LOCAL_IMAP_PORT not set")
+                    .parse()
+                    .expect("Invalid LOCAL_IMAP_PORT"),
+                remote_domain: env::var("REMOTE_IMAP_DOMAIN").expect("REMOTE_IMAP_DOMAIN not set"),
+                remote_port: env::var("REMOTE_IMAP_PORT")
+                    .expect("REMOTE_IMAP_PORT not set")
+                    .parse()
+                    .expect("Invalid REMOTE_IMAP_PORT"),
+                protocol: "IMAP",
+            }),
+            smtp_configuration: Arc::new(ProxyConfiguration {
+                local_port: env::var("LOCAL_SMTP_PORT")
+                    .expect("LOCAL_SMTP_PORT not set")
+                    .parse()
+                    .expect("Invalid LOCAL_SMTP_PORT"),
+                remote_domain: env::var("REMOTE_SMTP_DOMAIN").expect("REMOTE_SMTP_DOMAIN not set"),
+                remote_port: env::var("REMOTE_SMTP_PORT")
+                    .expect("REMOTE_SMTP_PORT not set")
+                    .parse()
+                    .expect("Invalid REMOTE_SMTP_PORT"),
+                protocol: "SMTP",
+            }),
+        }
+    }
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644 (file)
index 0000000..858e460
--- /dev/null
@@ -0,0 +1,15 @@
+mod configuration;
+mod proxy;
+
+use configuration::Configuration;
+use proxy::create_proxy;
+
+fn main() {
+    let configuration = Configuration::new();
+
+    let imap_proxy = create_proxy(configuration.imap_configuration);
+    let smtp_proxy = create_proxy(configuration.smtp_configuration);
+
+    imap_proxy.join().unwrap();
+    smtp_proxy.join().unwrap();
+}
diff --git a/src/proxy.rs b/src/proxy.rs
new file mode 100644 (file)
index 0000000..ce40e6e
--- /dev/null
@@ -0,0 +1,86 @@
+use native_tls::TlsConnector;
+use std::io::{Read, Write};
+use std::net::{TcpListener, TcpStream};
+use std::sync::Arc;
+use std::thread::{spawn, JoinHandle};
+
+use crate::configuration::ProxyConfiguration;
+
+pub fn create_proxy(configuration: Arc<ProxyConfiguration>) -> JoinHandle<()> {
+    let cloned_configuration = Arc::clone(&configuration);
+    spawn(move || {
+        run_proxy(cloned_configuration);
+    })
+}
+
+fn run_proxy(configuration: Arc<ProxyConfiguration>) {
+    let listener = TcpListener::bind(format!("0.0.0.0:{}", configuration.local_port)).unwrap();
+
+    println!("Proxy listening on port {}", configuration.local_port);
+
+    for stream in listener.incoming() {
+        match stream {
+            Ok(stream) => {
+                let cloned_configuration = Arc::clone(&configuration);
+                spawn(move || {
+                    handle_client(stream, cloned_configuration);
+                });
+            }
+            Err(e) => {
+                eprintln!("Failed to accept connection: {}", e);
+            }
+        }
+    }
+}
+
+fn handle_client(mut client_stream: TcpStream, configuration: Arc<ProxyConfiguration>) {
+    let connector = TlsConnector::new().unwrap();
+    let remote_stream = TcpStream::connect(format!(
+        "{}:{}",
+        configuration.remote_domain, configuration.remote_port
+    ))
+    .unwrap();
+    let mut remote_stream = connector
+        .connect(&configuration.remote_domain, remote_stream)
+        .unwrap();
+
+    let mut client_stream_clone = client_stream.try_clone().unwrap();
+    let mut remote_stream_clone = remote_stream.get_ref().try_clone().unwrap();
+
+    let cloned_configuration = Arc::clone(&configuration);
+    spawn(move || {
+        forward_stream(&mut client_stream, &mut remote_stream, cloned_configuration);
+    });
+    forward_stream(
+        &mut remote_stream_clone,
+        &mut client_stream_clone,
+        configuration,
+    );
+}
+
+fn forward_stream<R: Read, W: Write>(
+    from: &mut R,
+    to: &mut W,
+    configuration: Arc<ProxyConfiguration>,
+) {
+    let mut buffer = [0; 4096];
+    loop {
+        match from.read(&mut buffer) {
+            Ok(0) => break, // EOF
+            Ok(n) => {
+                if let Err(e) = to.write_all(&buffer[..n]) {
+                    eprintln!("{} proxy write error: {}", configuration.protocol, e);
+                    break;
+                }
+                if let Err(e) = to.flush() {
+                    eprintln!("{} proxy flush error: {}", configuration.protocol, e);
+                    break;
+                }
+            }
+            Err(e) => {
+                eprintln!("{} proxy read error: {}", configuration.protocol, e);
+                break;
+            }
+        }
+    }
+}