diff --git a/Cargo.lock b/Cargo.lock index 4b73d412..c2d471f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1177,13 +1177,14 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ "console", "shell-words", "tempfile", + "thiserror", "zeroize", ] diff --git a/crates/install/Cargo.toml b/crates/install/Cargo.toml index 51ca6520..f70ef6cc 100644 --- a/crates/install/Cargo.toml +++ b/crates/install/Cargo.toml @@ -15,7 +15,7 @@ reqwest = { version = "0.11", default-features = false, features = ["rustls-tls- rusqlite = { version = "0.29.0", features = ["bundled"] } rpassword = "7.0" indicatif = "0.17.0" -dialoguer = "0.10.4" +dialoguer = "0.11" openssl = { version = "0.10.55", features = ["vendored"] } base64 = "0.21.2" pwhash = "1.0.0" diff --git a/crates/install/src/main.rs b/crates/install/src/main.rs index 829eb9d0..7ba289c6 100644 --- a/crates/install/src/main.rs +++ b/crates/install/src/main.rs @@ -425,7 +425,7 @@ fn main() -> std::io::Result<()> { // Create authentication SQLite database let admin_password = if matches!(directory, Directory::None) { - create_auth_db(&base_path, &domain)?.into() + create_databases(&base_path, &domain)?.into() } else { None }; @@ -575,7 +575,13 @@ fn select(prompt: &str, items: &[&str], default: T) -> std::io::R .items(items) .with_prompt(prompt) .default(default.to_index()) - .interact_on_opt(&Term::stderr())? + .interact_on_opt(&Term::stderr()) + .map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Failed to read input: {}", err), + ) + })? { Ok(T::from_index(index)) } else { @@ -594,6 +600,12 @@ fn input( .default(default.to_string()) .validate_with(validator) .interact_text_on(&Term::stderr()) + .map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Failed to read input: {}", err), + ) + }) } fn dir_create_if_missing(path: &String) -> Result<(), String> { @@ -647,8 +659,9 @@ fn create_directories(path: &Path) -> std::io::Result<()> { Ok(()) } -fn create_auth_db(path: &Path, domain: &str) -> std::io::Result { - let mut path = PathBuf::from(path); +fn create_databases(base_path: &Path, domain: &str) -> std::io::Result { + // Create accounts database + let mut path = PathBuf::from(base_path); path.push("data"); if !path.exists() { fs::create_dir_all(&path)?; @@ -668,9 +681,9 @@ fn create_auth_db(path: &Path, domain: &str) -> std::io::Result { .collect::(); let hashed_secret = sha512_crypt::hash(&secret).unwrap(); for query in [ - "CREATE TABLE IF NOT EXISTS accounts (name TEXT PRIMARY KEY, secret TEXT, description TEXT, type TEXT NOT NULL, quota INTEGER DEFAULT 0, active BOOLEAN DEFAULT 1)".to_string(), - "CREATE TABLE IF NOT EXISTS group_members (name TEXT NOT NULL, member_of TEXT NOT NULL, PRIMARY KEY (name, member_of))".to_string(), - "CREATE TABLE IF NOT EXISTS emails (name TEXT NOT NULL, address TEXT NOT NULL, type TEXT, PRIMARY KEY (name, address))".to_string(), + concat!("CREATE TABLE IF NOT EXISTS accounts (name TEXT PRIMARY KEY, secret TEXT, description TEXT, ","type TEXT NOT NULL, quota INTEGER DEFAULT 0, active BOOLEAN DEFAULT 1)").to_string(), + concat!("CREATE TABLE IF NOT EXISTS group_members (name TEXT NOT NULL, member_of ","TEXT NOT NULL, PRIMARY KEY (name, member_of))").to_string(), + concat!("CREATE TABLE IF NOT EXISTS emails (name TEXT NOT NULL, address TEXT NOT NULL",", type TEXT, PRIMARY KEY (name, address))").to_string(), format!("INSERT OR REPLACE INTO accounts (name, secret, description, type) VALUES ('admin', '{hashed_secret}', 'Postmaster', 'individual')"), format!("INSERT OR REPLACE INTO emails (name, address, type) VALUES ('admin', 'postmaster@{domain}', 'primary')"), "INSERT OR IGNORE INTO group_members (name, member_of) VALUES ('admin', 'superusers')".to_string() @@ -683,6 +696,39 @@ fn create_auth_db(path: &Path, domain: &str) -> std::io::Result { })?; } + // Create Spam database + let path = PathBuf::from(base_path) + .join("data") + .join("spamfilter.sqlite3"); + let conn = Connection::open_with_flags(path, OpenFlags::default()).map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Failed to open database: {}", err), + ) + })?; + for query in [ + concat!( + "CREATE TABLE IF NOT EXISTS bayes_tokens (h1 INTEGER NOT NULL, ", + "h2 INTEGER NOT NULL, ws INTEGER, wh INTEGER, PRIMARY KEY (h1, h2))", + ), + concat!( + "CREATE TABLE IF NOT EXISTS seen_ids (id STRING NOT NULL PRIMARY KEY", + ", ttl DATETIME NOT NULL)", + ), + concat!( + "CREATE TABLE IF NOT EXISTS reputation (token STRING NOT NULL PRIMARY KEY", + ", score FLOAT NOT NULL DEFAULT '0', count INT(11) NOT NULL ", + "DEFAULT '0', ttl DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP)", + ), + ] { + conn.execute(query, []).map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Failed to create database: {}", err), + ) + })?; + } + Ok(secret) } diff --git a/crates/smtp/src/inbound/data.rs b/crates/smtp/src/inbound/data.rs index 3e1ba1ee..3013378c 100644 --- a/crates/smtp/src/inbound/data.rs +++ b/crates/smtp/src/inbound/data.rs @@ -409,7 +409,6 @@ impl Session { let params = self .build_script_parameters("data") .with_message(edited_message.as_ref().unwrap_or(&raw_message).clone()) - .set_variable("dmarc.from", auth_message.from().to_string()) .set_variable( "arc.result", arc_output diff --git a/resources/config.zip b/resources/config.zip new file mode 100644 index 00000000..878944dc Binary files /dev/null and b/resources/config.zip differ diff --git a/resources/config/spamfilter/maps/scores.map b/resources/config/spamfilter/maps/scores.map index 017d4ec0..94efcbf7 100644 --- a/resources/config/spamfilter/maps/scores.map +++ b/resources/config/spamfilter/maps/scores.map @@ -55,7 +55,7 @@ DMARC_BAD_POLICY 0.5 DMARC_DNSFAIL 0.0 DMARC_NA 0.0 DMARC_POLICY_ALLOW -0.5 -DMARC_POLICY_ALLOW_WITH_FAILURES -0.5 +DMARC_POLICY_ALLOW_WITH_FAILURES 0.0 DMARC_POLICY_QUARANTINE 1.5 DMARC_POLICY_REJECT 2.0 DMARC_POLICY_SOFTFAIL 0.1