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:
parent
25713c4482
commit
36bbe0a193
1 changed files with 39 additions and 16 deletions
|
|
@ -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"
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue