Fjern frase-sjekk, legg til domene-alias i synops-mail

- Fjernet "Kjære vaktmester"-krav: avsender-verifisering via
  auth_identities.email er tilstrekkelig spam-filter
- Domene-alias: mottaker-username oppslås i auth_identities
  uavhengig av domene. vegard@synops.no, vegard@sidelinja.org,
  vegard@vegard.info ruter til samme bruker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-19 01:55:37 +00:00
parent 25713c4482
commit 36bbe0a193

View file

@ -30,7 +30,7 @@ use std::process::{Command, Stdio};
const DEFAULT_FROM: &str = "vaktmester@synops.no"; const DEFAULT_FROM: &str = "vaktmester@synops.no";
const DEFAULT_FROM_NAME: &str = "Synops Vaktmester"; const DEFAULT_FROM_NAME: &str = "Synops Vaktmester";
const DEFAULT_CONFIG: &str = "/srv/synops/config/msmtp/msmtprc"; const DEFAULT_CONFIG: &str = "/srv/synops/config/msmtp/msmtprc";
const DEFAULT_PHRASE: &str = "Kjære vaktmester"; // Frase-sjekk fjernet — avsender-verifisering via auth_identities er nok.
/// Synops epost-verktøy: send og motta epost. /// Synops epost-verktøy: send og motta epost.
#[derive(Parser)] #[derive(Parser)]
@ -72,9 +72,6 @@ struct Cli {
#[arg(long)] #[arg(long)]
sender: Option<String>, sender: Option<String>,
/// Aktiveringsfrase som epost-body må starte med (default: "Kjære vaktmester")
#[arg(long, env = "SYNOPS_MAIL_PHRASE", default_value = DEFAULT_PHRASE)]
phrase: String,
} }
fn main() { fn main() {
@ -226,7 +223,7 @@ async fn run_receive(cli: &Cli) {
tracing::info!(subject = %subject, body_len = body.len(), "epost parset"); tracing::info!(subject = %subject, body_len = body.len(), "epost parset");
// Sjekk 1: Avsender-epost matcher auth_identities.email? // Verifiser avsender: epost matcher auth_identities.email?
let db = match synops_common::db::connect().await { let db = match synops_common::db::connect().await {
Ok(pool) => pool, Ok(pool) => pool,
Err(e) => { Err(e) => {
@ -253,7 +250,7 @@ async fn run_receive(cli: &Cli) {
let user_node_id = match user_node_id { let user_node_id = match user_node_id {
Some(id) => { Some(id) => {
tracing::info!(user_node_id = %id, "avsender verifisert"); tracing::info!(user_node_id = %id, "avsender verifisert via epost");
id id
} }
None => { None => {
@ -265,18 +262,44 @@ async fn run_receive(cli: &Cli) {
} }
}; };
// Sjekk 2: Body starter med aktiveringsfrasen? // Domene-alias: mottaker-username oppslås uavhengig av domene.
let body_trimmed = body.trim(); // vegard@synops.no, vegard@sidelinja.org, vegard@vegard.info
if !body_trimmed.starts_with(&cli.phrase) { // ruter alle til samme bruker.
let recipient_username = recipient
.split('@')
.next()
.unwrap_or("")
.trim()
.to_lowercase();
let target_node_id: Option<uuid::Uuid> = match sqlx::query_scalar(
"SELECT node_id FROM auth_identities WHERE LOWER(username) = $1",
)
.bind(&recipient_username)
.fetch_optional(&db)
.await
{
Ok(id) => id,
Err(e) => {
tracing::warn!("username-oppslag feilet: {e}");
None
}
};
// Hvis mottaker-username matcher en bruker, bruk den.
// Ellers havner noden hos avsender (epost til seg selv / vaktmester).
let owner_node_id = target_node_id.unwrap_or(user_node_id);
if target_node_id.is_some() {
tracing::info!( tracing::info!(
phrase = %cli.phrase, recipient_username = %recipient_username,
body_start = &body_trimmed[..body_trimmed.len().min(50)], owner = %owner_node_id,
"epost mangler aktiveringsfrase — forkaster" "mottaker funnet via username"
); );
return;
} }
// Begge sjekker bestått — opprett content-node let body_trimmed = body.trim();
// Avsender verifisert — opprett content-node
let node_id = uuid::Uuid::now_v7(); let node_id = uuid::Uuid::now_v7();
let title = if subject.is_empty() { let title = if subject.is_empty() {
format!("Epost fra {}", sender_email) format!("Epost fra {}", sender_email)
@ -299,14 +322,14 @@ async fn run_receive(cli: &Cli) {
.bind(&title) .bind(&title)
.bind(body_trimmed) .bind(body_trimmed)
.bind(&metadata) .bind(&metadata)
.bind(user_node_id) .bind(owner_node_id)
.execute(&db) .execute(&db)
.await .await
{ {
Ok(_) => { Ok(_) => {
tracing::info!( tracing::info!(
node_id = %node_id, node_id = %node_id,
user = %user_node_id, owner = %owner_node_id,
title = %title, title = %title,
"content-node opprettet fra epost" "content-node opprettet fra epost"
); );