add nginx auth http

Seto committed Oct 14, 2025 at 11:59 UTC a4522363a93280251bef33374a25a8c90ff9d4e8
7 files changed +109 -8
Cargo.lock
+13
@@ -47,6 +47,12 @@ dependencies = [
47 "windows-link",
48 ]
49
50 +[[package]]
51 +name = "base64"
52 +version = "0.21.7"
53 +source = "registry+https://github.com/rust-lang/crates.io-index"
54 +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
55 +
56 [[package]]
57 name = "bitflags"
58 version = "2.9.4"
@@ -313,6 +319,13 @@ dependencies = [
319 "tempfile",
320 ]
321
322 +[[package]]
323 +name = "nginx_auth_http"
324 +version = "0.1.0"
325 +dependencies = [
326 + "base64",
327 +]
328 +
329 [[package]]
330 name = "nu-ansi-term"
331 version = "0.50.3"
Cargo.toml
+3
@@ -1,3 +1,6 @@
1 +[workspace]
2 +members = ["./crates/*"]
3 +
4 [package]
5 name = "smbcloud-mail"
6 version = "1.0.0"
crates/.keep
crates/nginx-auth-http/Cargo.toml new
+7
@@ -0,0 +1,7 @@
1 +[package]
2 +name = "nginx_auth_http"
3 +version = "0.1.0"
4 +edition = "2021"
5 +
6 +[dependencies]
7 +base64 = "0.21"
crates/nginx-auth-http/src/main.rs new
+77
@@ -0,0 +1,77 @@
1 +use base64::{engine::general_purpose, Engine as _};
2 +use std::collections::HashMap;
3 +use std::io::prelude::*;
4 +use std::net::{TcpListener, TcpStream};
5 +
6 +struct AuthServer {
7 + users: HashMap<String, String>,
8 +}
9 +
10 +impl AuthServer {
11 + fn new() -> Self {
12 + let mut users = HashMap::new();
13 + users.insert("admin".to_string(), "your_admin_password".to_string());
14 + users.insert("user".to_string(), "your_user_password".to_string());
15 +
16 + AuthServer { users }
17 + }
18 +
19 + fn handle_request(&self, mut stream: TcpStream) {
20 + let mut buffer = [0; 1024];
21 + stream.read(&mut buffer).unwrap();
22 +
23 + let request = String::from_utf8_lossy(&buffer[..]);
24 + let lines: Vec<&str> = request.lines().collect();
25 +
26 + // Find Authorization header
27 + let auth_header = lines
28 + .iter()
29 + .find(|line| line.to_lowercase().starts_with("authorization:"))
30 + .map(|line| line.split_once(": ").unwrap_or(("", "")).1);
31 +
32 + let response = if let Some(auth) = auth_header {
33 + if auth.starts_with("Basic ") {
34 + match self.validate_credentials(&auth[6..]) {
35 + true => "HTTP/1.1 200 OK\r\n\r\n",
36 + false => "HTTP/1.1 401 Unauthorized\r\n\r\n",
37 + }
38 + } else {
39 + "HTTP/1.1 401 Unauthorized\r\n\r\n"
40 + }
41 + } else {
42 + "HTTP/1.1 401 Unauthorized\r\n\r\n"
43 + };
44 +
45 + stream.write_all(response.as_bytes()).unwrap();
46 + stream.flush().unwrap();
47 + }
48 +
49 + fn validate_credentials(&self, encoded_creds: &str) -> bool {
50 + if let Ok(decoded) = general_purpose::STANDARD.decode(encoded_creds) {
51 + if let Ok(creds_str) = String::from_utf8(decoded) {
52 + if let Some((username, password)) = creds_str.split_once(':') {
53 + return self.users.get(username).map_or(false, |p| p == password);
54 + }
55 + }
56 + }
57 + false
58 + }
59 +}
60 +
61 +fn main() {
62 + let auth_server = AuthServer::new();
63 + let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
64 +
65 + println!("Auth server running on port 8080");
66 +
67 + for stream in listener.incoming() {
68 + match stream {
69 + Ok(stream) => {
70 + auth_server.handle_request(stream);
71 + }
72 + Err(e) => {
73 + println!("Error: {}", e);
74 + }
75 + }
76 + }
77 +}
docs/nginx/config.conf
+3 -8
@@ -2,6 +2,7 @@ worker_processes auto;
2
3 mail {
4 server_name smtp.thestablefoundation.org;
5 + auth_http localhost:8080;
6
7 proxy_pass_error_message on;
8
@@ -14,19 +15,13 @@ mail {
15 ssl_session_timeout 10m;
16
17 server {
17 - listen 25;
18 + listen 2525;
19 protocol smtp;
20 smtp_auth login plain cram-md5;
21 }
22
23 server {
23 - listen 110;
24 - protocol pop3;
25 - pop3_auth plain apop cram-md5;
26 - }
27 -
28 - server {
29 - listen 143;
24 + listen 1143;
25 protocol imap;
26 }
27 }
docs/scripts/send-email.py
+6
@@ -6,6 +6,9 @@ from email.mime.text import MIMEText
6
7 smtp_server = "localhost"
8 smtp_port = 2525
9 +smtp_username = "your_username" # Add your SMTP username here
10 +smtp_password = "your_password" # Add your SMTP password here
11 +
12 from_email = "you@example.com"
13 to_email = "to@example.com"
14 subject = "Test Email"
@@ -37,6 +40,9 @@ with open(file_path, "rb") as attachment:
40 try:
41 with smtplib.SMTP(smtp_server, smtp_port) as server:
42 _ = server.starttls()
43 + _ = server.login(
44 + smtp_username, smtp_password
45 + ) # Add this line for authentication
46 _ = server.sendmail(from_email, to_email, message.as_string())
47 print("Email sent successfully")
48 except Exception as e: