mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2024-09-20 07:16:18 +08:00
Improved tracing (part 1)
This commit is contained in:
parent
9c23774aa5
commit
ae7cadc27d
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -6421,7 +6421,6 @@ dependencies = [
|
|||
"store",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.0",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"trc",
|
||||
"utils",
|
||||
|
@ -6883,6 +6882,7 @@ dependencies = [
|
|||
"arc-swap",
|
||||
"base64 0.22.1",
|
||||
"bincode",
|
||||
"mail-auth",
|
||||
"parking_lot",
|
||||
"reqwest 0.12.5",
|
||||
"rtrb",
|
||||
|
@ -7146,7 +7146,6 @@ dependencies = [
|
|||
"smtp-proto",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.0",
|
||||
"tracing",
|
||||
"tracing-journald",
|
||||
"trc",
|
||||
"webpki-roots 0.26.3",
|
||||
|
|
|
@ -20,7 +20,6 @@ dns-update = { version = "0.1" }
|
|||
ahash = { version = "0.8.2", features = ["serde"] }
|
||||
parking_lot = "0.12.1"
|
||||
regex = "1.7.0"
|
||||
tracing = "0.1"
|
||||
proxy-header = { version = "0.1.0", features = ["tokio"] }
|
||||
arc-swap = "1.6.0"
|
||||
rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
|
||||
|
@ -60,6 +59,7 @@ hostname = "0.4.0"
|
|||
zip = "2.1"
|
||||
pwhash = "1.0.0"
|
||||
xxhash-rust = { version = "0.8.5", features = ["xxh3"] }
|
||||
tracing = "0.1"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
privdrop = "0.5.3"
|
||||
|
|
|
@ -153,6 +153,8 @@ impl AddressMapping {
|
|||
core: &Core,
|
||||
address: &'y str,
|
||||
) -> Cow<'x, str> {
|
||||
let todo = "pass session_id";
|
||||
let session_id = 0;
|
||||
match self {
|
||||
AddressMapping::Enable => {
|
||||
if let Some((local_part, domain_part)) = address.rsplit_once('@') {
|
||||
|
@ -162,11 +164,10 @@ impl AddressMapping {
|
|||
}
|
||||
}
|
||||
AddressMapping::Custom(if_block) => {
|
||||
if let Ok(result) = String::try_from(
|
||||
if_block
|
||||
.eval(&Address(address), core, "session.rcpt.sub-addressing")
|
||||
.await,
|
||||
) {
|
||||
if let Some(result) = core
|
||||
.eval_if::<String, _>(if_block, &Address(address), session_id)
|
||||
.await
|
||||
{
|
||||
return result.into();
|
||||
}
|
||||
}
|
||||
|
@ -181,23 +182,18 @@ impl AddressMapping {
|
|||
core: &Core,
|
||||
address: &'y str,
|
||||
) -> Option<Cow<'x, str>> {
|
||||
let todo = "pass session_id";
|
||||
let session_id = 0;
|
||||
|
||||
match self {
|
||||
AddressMapping::Enable => address
|
||||
.rsplit_once('@')
|
||||
.map(|(_, domain_part)| format!("@{}", domain_part))
|
||||
.map(Cow::Owned),
|
||||
|
||||
AddressMapping::Custom(if_block) => {
|
||||
if let Ok(result) = String::try_from(
|
||||
if_block
|
||||
.eval(&Address(address), core, "session.rcpt.catch-all")
|
||||
.await,
|
||||
) {
|
||||
Some(result.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
AddressMapping::Custom(if_block) => core
|
||||
.eval_if::<String, _>(if_block, &Address(address), session_id)
|
||||
.await
|
||||
.map(Cow::Owned),
|
||||
AddressMapping::Disable => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
use opentelemetry_otlp::{HttpExporterBuilder, TonicExporterBuilder, WithExportConfig};
|
||||
use tracing::Level;
|
||||
use tracing_appender::rolling::RollingFileAppender;
|
||||
use trc::Level;
|
||||
use utils::config::Config;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -69,7 +69,7 @@ impl Tracers {
|
|||
format!("Invalid log level: {err}"),
|
||||
)
|
||||
})
|
||||
.unwrap_or(Level::INFO);
|
||||
.unwrap_or(Level::Info);
|
||||
match config
|
||||
.value(("tracer", id, "type"))
|
||||
.unwrap_or_default()
|
||||
|
|
|
@ -15,6 +15,7 @@ pub mod undelete;
|
|||
use std::time::Duration;
|
||||
|
||||
use license::LicenseKey;
|
||||
use mail_parser::DateTime;
|
||||
|
||||
use crate::Core;
|
||||
|
||||
|
@ -46,12 +47,14 @@ impl Core {
|
|||
|
||||
pub fn log_license_details(&self) {
|
||||
if let Some(enterprise) = &self.enterprise {
|
||||
tracing::info!(
|
||||
licensed_to = enterprise.license.hostname,
|
||||
valid_from = enterprise.license.valid_from,
|
||||
valid_to = enterprise.license.valid_to,
|
||||
accounts = enterprise.license.accounts,
|
||||
"Stalwart Enterprise Edition license key is valid",
|
||||
trc::event!(
|
||||
Server(trc::ServerEvent::Licensing),
|
||||
Details = "Stalwart Enterprise Edition license key is valid",
|
||||
Hostname = enterprise.license.hostname.clone(),
|
||||
Total = enterprise.license.accounts,
|
||||
ValidFrom =
|
||||
DateTime::from_timestamp(enterprise.license.valid_from as i64).to_rfc3339(),
|
||||
ValidTo = DateTime::from_timestamp(enterprise.license.valid_to as i64).to_rfc3339(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
use std::{borrow::Cow, cmp::Ordering, fmt::Display};
|
||||
|
||||
use trc::EvalEvent;
|
||||
|
||||
use crate::Core;
|
||||
|
||||
use super::{
|
||||
|
@ -19,23 +21,52 @@ impl Core {
|
|||
&self,
|
||||
if_block: &'x IfBlock,
|
||||
resolver: &'x V,
|
||||
session_id: u64,
|
||||
) -> Option<R> {
|
||||
if if_block.is_empty() {
|
||||
tracing::trace!(context = "eval_if", property = if_block.key, result = "");
|
||||
trc::event!(
|
||||
Eval(EvalEvent::Result),
|
||||
SessionId = session_id,
|
||||
Property = if_block.key.clone(),
|
||||
Result = ""
|
||||
);
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
let result = if_block.eval(resolver, self, &if_block.key).await;
|
||||
match if_block.eval(resolver, self).await {
|
||||
Ok(result) => {
|
||||
trc::event!(
|
||||
Eval(EvalEvent::Result),
|
||||
SessionId = session_id,
|
||||
Property = if_block.key.clone(),
|
||||
Result = format!("{result:?}"),
|
||||
);
|
||||
|
||||
tracing::trace!(context = "eval_if",
|
||||
property = if_block.key,
|
||||
result = ?result,
|
||||
);
|
||||
match result.try_into() {
|
||||
Ok(value) => Some(value),
|
||||
Err(_) => {
|
||||
trc::event!(
|
||||
Eval(EvalEvent::Error),
|
||||
SessionId = session_id,
|
||||
Property = if_block.key.clone(),
|
||||
Details = "Failed to convert result",
|
||||
);
|
||||
|
||||
match result.try_into() {
|
||||
Ok(value) => Some(value),
|
||||
Err(_) => None,
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
trc::event!(
|
||||
Eval(EvalEvent::Error),
|
||||
SessionId = session_id,
|
||||
Property = if_block.key.clone(),
|
||||
CausedBy = err,
|
||||
);
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,21 +75,45 @@ impl Core {
|
|||
expr: &'x Expression,
|
||||
resolver: &'x V,
|
||||
expr_id: &str,
|
||||
session_id: u64,
|
||||
) -> Option<R> {
|
||||
if expr.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let result = expr.eval(resolver, self, expr_id, &mut Vec::new()).await;
|
||||
match expr.eval(resolver, self, &mut Vec::new()).await {
|
||||
Ok(result) => {
|
||||
trc::event!(
|
||||
Eval(EvalEvent::Result),
|
||||
SessionId = session_id,
|
||||
Property = expr_id.to_string(),
|
||||
Result = format!("{result:?}"),
|
||||
);
|
||||
|
||||
tracing::trace!(context = "eval_expr",
|
||||
property = expr_id,
|
||||
result = ?result,
|
||||
);
|
||||
match result.try_into() {
|
||||
Ok(value) => Some(value),
|
||||
Err(_) => {
|
||||
trc::event!(
|
||||
Eval(EvalEvent::Error),
|
||||
SessionId = session_id,
|
||||
Property = expr_id.to_string(),
|
||||
Details = "Failed to convert result",
|
||||
);
|
||||
|
||||
match result.try_into() {
|
||||
Ok(value) => Some(value),
|
||||
Err(_) => None,
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
trc::event!(
|
||||
Eval(EvalEvent::Error),
|
||||
SessionId = session_id,
|
||||
Property = expr_id.to_string(),
|
||||
CausedBy = err,
|
||||
);
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,27 +123,21 @@ impl IfBlock {
|
|||
&'x self,
|
||||
resolver: &'x V,
|
||||
core: &Core,
|
||||
property: &str,
|
||||
) -> Variable<'x> {
|
||||
) -> trc::Result<Variable<'x>> {
|
||||
let mut captures = Vec::new();
|
||||
|
||||
for if_then in &self.if_then {
|
||||
if if_then
|
||||
.expr
|
||||
.eval(resolver, core, property, &mut captures)
|
||||
.await
|
||||
.eval(resolver, core, &mut captures)
|
||||
.await?
|
||||
.to_bool()
|
||||
{
|
||||
return if_then
|
||||
.then
|
||||
.eval(resolver, core, property, &mut captures)
|
||||
.await;
|
||||
return if_then.then.eval(resolver, core, &mut captures).await;
|
||||
}
|
||||
}
|
||||
|
||||
self.default
|
||||
.eval(resolver, core, property, &mut captures)
|
||||
.await
|
||||
self.default.eval(resolver, core, &mut captures).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,9 +146,8 @@ impl Expression {
|
|||
&'x self,
|
||||
resolver: &'x V,
|
||||
core: &Core,
|
||||
property: &str,
|
||||
captures: &'y mut Vec<String>,
|
||||
) -> Variable<'x> {
|
||||
) -> trc::Result<Variable<'x>> {
|
||||
let mut stack = Vec::new();
|
||||
let mut exprs = self.items.iter();
|
||||
|
||||
|
@ -157,8 +205,8 @@ impl Expression {
|
|||
let result = if let Some((_, fnc, _)) = FUNCTIONS.get(*id as usize) {
|
||||
(fnc)(arguments)
|
||||
} else {
|
||||
core.eval_fnc(*id - FUNCTIONS.len() as u32, arguments, property)
|
||||
.await
|
||||
core.eval_fnc(*id - FUNCTIONS.len() as u32, arguments)
|
||||
.await?
|
||||
};
|
||||
|
||||
stack.push(result);
|
||||
|
@ -202,7 +250,7 @@ impl Expression {
|
|||
}
|
||||
}
|
||||
|
||||
stack.pop().unwrap_or_default()
|
||||
Ok(stack.pop().unwrap_or_default())
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::{cmp::Ordering, net::IpAddr, vec::IntoIter};
|
|||
|
||||
use mail_auth::IpLookupStrategy;
|
||||
use store::{Deserialize, Rows, Value};
|
||||
use trc::AddContext;
|
||||
|
||||
use crate::Core;
|
||||
|
||||
|
@ -12,8 +13,7 @@ impl Core {
|
|||
&self,
|
||||
fnc_id: u32,
|
||||
params: Vec<Variable<'x>>,
|
||||
property: &str,
|
||||
) -> Variable<'x> {
|
||||
) -> trc::Result<Variable<'x>> {
|
||||
let mut params = FncParams::new(params);
|
||||
|
||||
match fnc_id {
|
||||
|
@ -24,18 +24,8 @@ impl Core {
|
|||
self.get_directory_or_default(directory.as_ref())
|
||||
.is_local_domain(domain.as_ref())
|
||||
.await
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::warn!(
|
||||
context = "eval_if",
|
||||
event = "error",
|
||||
property = property,
|
||||
error = ?err,
|
||||
"Failed to check if domain is local."
|
||||
);
|
||||
|
||||
false
|
||||
})
|
||||
.into()
|
||||
.caused_by(trc::location!())
|
||||
.map(|v| v.into())
|
||||
}
|
||||
F_IS_LOCAL_ADDRESS => {
|
||||
let directory = params.next_as_string();
|
||||
|
@ -44,18 +34,8 @@ impl Core {
|
|||
self.get_directory_or_default(directory.as_ref())
|
||||
.rcpt(address.as_ref())
|
||||
.await
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::warn!(
|
||||
context = "eval_if",
|
||||
event = "error",
|
||||
property = property,
|
||||
error = ?err,
|
||||
"Failed to check if address is local."
|
||||
);
|
||||
|
||||
false
|
||||
})
|
||||
.into()
|
||||
.caused_by(trc::location!())
|
||||
.map(|v| v.into())
|
||||
}
|
||||
F_KEY_GET => {
|
||||
let store = params.next_as_string();
|
||||
|
@ -65,17 +45,8 @@ impl Core {
|
|||
.key_get::<VariableWrapper>(key.into_owned().into_bytes())
|
||||
.await
|
||||
.map(|value| value.map(|v| v.into_inner()).unwrap_or_default())
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::warn!(
|
||||
context = "eval_if",
|
||||
event = "error",
|
||||
property = property,
|
||||
error = ?err,
|
||||
"Failed to get key."
|
||||
);
|
||||
|
||||
Variable::default()
|
||||
})
|
||||
.caused_by(trc::location!())
|
||||
.map(|v| v.into())
|
||||
}
|
||||
F_KEY_EXISTS => {
|
||||
let store = params.next_as_string();
|
||||
|
@ -84,18 +55,8 @@ impl Core {
|
|||
self.get_lookup_store(store.as_ref())
|
||||
.key_exists(key.into_owned().into_bytes())
|
||||
.await
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::warn!(
|
||||
context = "eval_if",
|
||||
event = "error",
|
||||
property = property,
|
||||
error = ?err,
|
||||
"Failed to get key."
|
||||
);
|
||||
|
||||
false
|
||||
})
|
||||
.into()
|
||||
.caused_by(trc::location!())
|
||||
.map(|v| v.into())
|
||||
}
|
||||
F_KEY_SET => {
|
||||
let store = params.next_as_string();
|
||||
|
@ -110,18 +71,8 @@ impl Core {
|
|||
)
|
||||
.await
|
||||
.map(|_| true)
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::warn!(
|
||||
context = "eval_if",
|
||||
event = "error",
|
||||
property = property,
|
||||
error = ?err,
|
||||
"Failed to set key."
|
||||
);
|
||||
|
||||
false
|
||||
})
|
||||
.into()
|
||||
.caused_by(trc::location!())
|
||||
.map(|v| v.into())
|
||||
}
|
||||
F_COUNTER_INCR => {
|
||||
let store = params.next_as_string();
|
||||
|
@ -132,17 +83,8 @@ impl Core {
|
|||
.counter_incr(key.into_owned().into_bytes(), value, None, true)
|
||||
.await
|
||||
.map(Variable::Integer)
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::warn!(
|
||||
context = "eval_if",
|
||||
event = "error",
|
||||
property = property,
|
||||
error = ?err,
|
||||
"Failed to increment counter."
|
||||
);
|
||||
|
||||
Variable::default()
|
||||
})
|
||||
.caused_by(trc::location!())
|
||||
.map(|v| v.into())
|
||||
}
|
||||
F_COUNTER_GET => {
|
||||
let store = params.next_as_string();
|
||||
|
@ -152,35 +94,23 @@ impl Core {
|
|||
.counter_get(key.into_owned().into_bytes())
|
||||
.await
|
||||
.map(Variable::Integer)
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::warn!(
|
||||
context = "eval_if",
|
||||
event = "error",
|
||||
property = property,
|
||||
error = ?err,
|
||||
"Failed to increment counter."
|
||||
);
|
||||
|
||||
Variable::default()
|
||||
})
|
||||
.caused_by(trc::location!())
|
||||
.map(|v| v.into())
|
||||
}
|
||||
F_DNS_QUERY => self.dns_query(params).await,
|
||||
F_SQL_QUERY => self.sql_query(params).await,
|
||||
_ => Variable::default(),
|
||||
_ => Ok(Variable::default()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn sql_query<'x>(&self, mut arguments: FncParams<'x>) -> Variable<'x> {
|
||||
async fn sql_query<'x>(&self, mut arguments: FncParams<'x>) -> trc::Result<Variable<'x>> {
|
||||
let store = self.get_lookup_store(arguments.next_as_string().as_ref());
|
||||
let query = arguments.next_as_string();
|
||||
|
||||
if query.is_empty() {
|
||||
tracing::warn!(
|
||||
context = "eval:sql_query",
|
||||
event = "invalid",
|
||||
reason = "Empty query string",
|
||||
);
|
||||
return Variable::default();
|
||||
return Err(trc::EventType::Eval(trc::EvalEvent::Error)
|
||||
.into_err()
|
||||
.details("Empty query string"));
|
||||
}
|
||||
|
||||
// Obtain arguments
|
||||
|
@ -195,115 +125,140 @@ impl Core {
|
|||
.get(..6)
|
||||
.map_or(false, |q| q.eq_ignore_ascii_case(b"SELECT"))
|
||||
{
|
||||
if let Ok(mut rows) = store.query::<Rows>(&query, arguments).await {
|
||||
match rows.rows.len().cmp(&1) {
|
||||
Ordering::Equal => {
|
||||
let mut row = rows.rows.pop().unwrap().values;
|
||||
match row.len().cmp(&1) {
|
||||
Ordering::Equal if !matches!(row.first(), Some(Value::Null)) => {
|
||||
row.pop().map(into_variable).unwrap()
|
||||
}
|
||||
Ordering::Less => Variable::default(),
|
||||
_ => Variable::Array(
|
||||
row.into_iter().map(into_variable).collect::<Vec<_>>(),
|
||||
),
|
||||
let mut rows = store
|
||||
.query::<Rows>(&query, arguments)
|
||||
.await
|
||||
.caused_by(trc::location!())?;
|
||||
Ok(match rows.rows.len().cmp(&1) {
|
||||
Ordering::Equal => {
|
||||
let mut row = rows.rows.pop().unwrap().values;
|
||||
match row.len().cmp(&1) {
|
||||
Ordering::Equal if !matches!(row.first(), Some(Value::Null)) => {
|
||||
row.pop().map(into_variable).unwrap()
|
||||
}
|
||||
Ordering::Less => Variable::default(),
|
||||
_ => {
|
||||
Variable::Array(row.into_iter().map(into_variable).collect::<Vec<_>>())
|
||||
}
|
||||
}
|
||||
Ordering::Less => Variable::default(),
|
||||
Ordering::Greater => rows
|
||||
.rows
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
Variable::Array(
|
||||
r.values.into_iter().map(into_variable).collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
}
|
||||
} else {
|
||||
false.into()
|
||||
}
|
||||
Ordering::Less => Variable::default(),
|
||||
Ordering::Greater => rows
|
||||
.rows
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
Variable::Array(r.values.into_iter().map(into_variable).collect::<Vec<_>>())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
})
|
||||
} else {
|
||||
store.query::<usize>(&query, arguments).await.is_ok().into()
|
||||
store
|
||||
.query::<usize>(&query, arguments)
|
||||
.await
|
||||
.caused_by(trc::location!())
|
||||
.map(|v| v.into())
|
||||
}
|
||||
}
|
||||
|
||||
async fn dns_query<'x>(&self, mut arguments: FncParams<'x>) -> Variable<'x> {
|
||||
async fn dns_query<'x>(&self, mut arguments: FncParams<'x>) -> trc::Result<Variable<'x>> {
|
||||
let entry = arguments.next_as_string();
|
||||
let record_type = arguments.next_as_string();
|
||||
|
||||
if record_type.eq_ignore_ascii_case("ip") {
|
||||
match self
|
||||
.smtp
|
||||
self.smtp
|
||||
.resolvers
|
||||
.dns
|
||||
.ip_lookup(entry.as_ref(), IpLookupStrategy::Ipv4thenIpv6, 10)
|
||||
.await
|
||||
{
|
||||
Ok(result) => result
|
||||
.iter()
|
||||
.map(|ip| Variable::from(ip.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
Err(_) => Variable::default(),
|
||||
}
|
||||
.map_err(|err| trc::Error::from(err).caused_by(trc::location!()))
|
||||
.map(|result| {
|
||||
result
|
||||
.iter()
|
||||
.map(|ip| Variable::from(ip.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
})
|
||||
} else if record_type.eq_ignore_ascii_case("mx") {
|
||||
match self.smtp.resolvers.dns.mx_lookup(entry.as_ref()).await {
|
||||
Ok(result) => result
|
||||
.iter()
|
||||
.flat_map(|mx| {
|
||||
mx.exchanges.iter().map(|host| {
|
||||
Variable::String(
|
||||
host.strip_suffix('.')
|
||||
.unwrap_or(host.as_str())
|
||||
.to_string()
|
||||
.into(),
|
||||
)
|
||||
self.smtp
|
||||
.resolvers
|
||||
.dns
|
||||
.mx_lookup(entry.as_ref())
|
||||
.await
|
||||
.map_err(|err| trc::Error::from(err).caused_by(trc::location!()))
|
||||
.map(|result| {
|
||||
result
|
||||
.iter()
|
||||
.flat_map(|mx| {
|
||||
mx.exchanges.iter().map(|host| {
|
||||
Variable::String(
|
||||
host.strip_suffix('.')
|
||||
.unwrap_or(host.as_str())
|
||||
.to_string()
|
||||
.into(),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
Err(_) => Variable::default(),
|
||||
}
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
})
|
||||
} else if record_type.eq_ignore_ascii_case("txt") {
|
||||
match self.smtp.resolvers.dns.txt_raw_lookup(entry.as_ref()).await {
|
||||
Ok(result) => Variable::from(String::from_utf8(result).unwrap_or_default()),
|
||||
Err(_) => Variable::default(),
|
||||
}
|
||||
self.smtp
|
||||
.resolvers
|
||||
.dns
|
||||
.txt_raw_lookup(entry.as_ref())
|
||||
.await
|
||||
.map_err(|err| trc::Error::from(err).caused_by(trc::location!()))
|
||||
.map(|result| Variable::from(String::from_utf8(result).unwrap_or_default()))
|
||||
} else if record_type.eq_ignore_ascii_case("ptr") {
|
||||
if let Ok(addr) = entry.parse::<IpAddr>() {
|
||||
match self.smtp.resolvers.dns.ptr_lookup(addr).await {
|
||||
Ok(result) => result
|
||||
self.smtp
|
||||
.resolvers
|
||||
.dns
|
||||
.ptr_lookup(entry.parse::<IpAddr>().map_err(|err| {
|
||||
trc::EventType::Eval(trc::EvalEvent::Error)
|
||||
.into_err()
|
||||
.details("Failed to parse IP address")
|
||||
.reason(err)
|
||||
})?)
|
||||
.await
|
||||
.map_err(|err| trc::Error::from(err).caused_by(trc::location!()))
|
||||
.map(|result| {
|
||||
result
|
||||
.iter()
|
||||
.map(|host| Variable::from(host.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
Err(_) => Variable::default(),
|
||||
}
|
||||
} else {
|
||||
Variable::default()
|
||||
}
|
||||
.into()
|
||||
})
|
||||
} else if record_type.eq_ignore_ascii_case("ipv4") {
|
||||
match self.smtp.resolvers.dns.ipv4_lookup(entry.as_ref()).await {
|
||||
Ok(result) => result
|
||||
.iter()
|
||||
.map(|ip| Variable::from(ip.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
Err(_) => Variable::default(),
|
||||
}
|
||||
self.smtp
|
||||
.resolvers
|
||||
.dns
|
||||
.ipv4_lookup(entry.as_ref())
|
||||
.await
|
||||
.map_err(|err| trc::Error::from(err).caused_by(trc::location!()))
|
||||
.map(|result| {
|
||||
result
|
||||
.iter()
|
||||
.map(|ip| Variable::from(ip.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
})
|
||||
} else if record_type.eq_ignore_ascii_case("ipv6") {
|
||||
match self.smtp.resolvers.dns.ipv6_lookup(entry.as_ref()).await {
|
||||
Ok(result) => result
|
||||
.iter()
|
||||
.map(|ip| Variable::from(ip.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
Err(_) => Variable::default(),
|
||||
}
|
||||
self.smtp
|
||||
.resolvers
|
||||
.dns
|
||||
.ipv6_lookup(entry.as_ref())
|
||||
.await
|
||||
.map_err(|err| trc::Error::from(err).caused_by(trc::location!()))
|
||||
.map(|result| {
|
||||
result
|
||||
.iter()
|
||||
.map(|ip| Variable::from(ip.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
})
|
||||
} else {
|
||||
Variable::default()
|
||||
Ok(Variable::default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -253,7 +253,7 @@ impl Core {
|
|||
}
|
||||
Ok(None) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.matches(trc::Cause::Auth(trc::AuthCause::MissingTotp)) {
|
||||
if err.matches(trc::EventType::Auth(trc::AuthEvent::MissingTotp)) {
|
||||
return Err(err);
|
||||
} else {
|
||||
Err(err)
|
||||
|
@ -329,7 +329,7 @@ impl Core {
|
|||
.await;
|
||||
}
|
||||
|
||||
Err(trc::AuthCause::Failed.into())
|
||||
Err(trc::AuthEvent::Failed.into())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ impl Core {
|
|||
.await;
|
||||
}
|
||||
|
||||
Err(trc::AuthCause::Banned.into())
|
||||
Err(trc::AuthEvent::Banned.into())
|
||||
} else {
|
||||
// Send webhook event
|
||||
if self.has_webhook_subscribers(WebhookType::AuthFailure) {
|
||||
|
@ -392,7 +392,7 @@ impl Core {
|
|||
.await;
|
||||
}
|
||||
|
||||
Err(trc::AuthCause::Failed.into())
|
||||
Err(trc::AuthEvent::Failed.into())
|
||||
}
|
||||
} else {
|
||||
// Send webhook event
|
||||
|
@ -409,7 +409,7 @@ impl Core {
|
|||
)
|
||||
.await;
|
||||
}
|
||||
Err(trc::AuthCause::Failed.into())
|
||||
Err(trc::AuthEvent::Failed.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ impl Core {
|
|||
URL_SAFE_NO_PAD
|
||||
.decode(content.as_bytes())
|
||||
.map_err(|err| {
|
||||
trc::Cause::Acme
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)
|
||||
.details("failed to decode certificate")
|
||||
|
|
|
@ -59,8 +59,12 @@ impl Account {
|
|||
S: AsRef<str> + 'a,
|
||||
I: IntoIterator<Item = &'a S>,
|
||||
{
|
||||
let key_pair = EcdsaKeyPair::from_pkcs8(ALG, key_pair, &SystemRandom::new())
|
||||
.map_err(|err| trc::Cause::Acme.reason(err).caused_by(trc::location!()))?;
|
||||
let key_pair =
|
||||
EcdsaKeyPair::from_pkcs8(ALG, key_pair, &SystemRandom::new()).map_err(|err| {
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.reason(err)
|
||||
.caused_by(trc::location!())
|
||||
})?;
|
||||
let contact: Vec<&'a str> = contact.into_iter().map(AsRef::<str>::as_ref).collect();
|
||||
let payload = json!({
|
||||
"termsOfServiceAgreed": true,
|
||||
|
@ -100,7 +104,7 @@ impl Account {
|
|||
let body = response
|
||||
.text()
|
||||
.await
|
||||
.map_err(|err| trc::Cause::Acme.from_http_error(err))?;
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))?;
|
||||
Ok((location, body))
|
||||
}
|
||||
|
||||
|
@ -108,23 +112,25 @@ impl Account {
|
|||
let domains: Vec<Identifier> = domains.into_iter().map(Identifier::Dns).collect();
|
||||
let payload = format!(
|
||||
"{{\"identifiers\":{}}}",
|
||||
serde_json::to_string(&domains).map_err(|err| trc::Cause::Acme.from_json_error(err))?
|
||||
serde_json::to_string(&domains)
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))?
|
||||
);
|
||||
let response = self.request(&self.directory.new_order, &payload).await?;
|
||||
let url = response.0.ok_or(
|
||||
trc::Cause::Acme
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.details("Missing header")
|
||||
.ctx(trc::Key::Id, "Location"),
|
||||
)?;
|
||||
let order = serde_json::from_str(&response.1)
|
||||
.map_err(|err| trc::Cause::Acme.from_json_error(err))?;
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))?;
|
||||
Ok((url, order))
|
||||
}
|
||||
|
||||
pub async fn auth(&self, url: impl AsRef<str>) -> trc::Result<Auth> {
|
||||
let response = self.request(url, "").await?;
|
||||
serde_json::from_str(&response.1).map_err(|err| trc::Cause::Acme.from_json_error(err))
|
||||
serde_json::from_str(&response.1)
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))
|
||||
}
|
||||
|
||||
pub async fn challenge(&self, url: impl AsRef<str>) -> trc::Result<()> {
|
||||
|
@ -133,13 +139,15 @@ impl Account {
|
|||
|
||||
pub async fn order(&self, url: impl AsRef<str>) -> trc::Result<Order> {
|
||||
let response = self.request(&url, "").await?;
|
||||
serde_json::from_str(&response.1).map_err(|err| trc::Cause::Acme.from_json_error(err))
|
||||
serde_json::from_str(&response.1)
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))
|
||||
}
|
||||
|
||||
pub async fn finalize(&self, url: impl AsRef<str>, csr: Vec<u8>) -> trc::Result<Order> {
|
||||
let payload = format!("{{\"csr\":\"{}\"}}", URL_SAFE_NO_PAD.encode(csr));
|
||||
let response = self.request(&url, &payload).await?;
|
||||
serde_json::from_str(&response.1).map_err(|err| trc::Cause::Acme.from_json_error(err))
|
||||
serde_json::from_str(&response.1)
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))
|
||||
}
|
||||
|
||||
pub async fn certificate(&self, url: impl AsRef<str>) -> trc::Result<String> {
|
||||
|
@ -161,13 +169,18 @@ impl Account {
|
|||
let key_auth = key_authorization_sha256(&self.key_pair, &challenge.token)?;
|
||||
params.alg = &PKCS_ECDSA_P256_SHA256;
|
||||
params.custom_extensions = vec![CustomExtension::new_acme_identifier(key_auth.as_ref())];
|
||||
let cert = Certificate::from_params(params)
|
||||
.map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?;
|
||||
let cert = Certificate::from_params(params).map_err(|err| {
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)
|
||||
})?;
|
||||
|
||||
Ok(Bincode::new(SerializedCert {
|
||||
certificate: cert
|
||||
.serialize_der()
|
||||
.map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?,
|
||||
certificate: cert.serialize_der().map_err(|err| {
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)
|
||||
})?,
|
||||
private_key: cert.serialize_private_key_der(),
|
||||
})
|
||||
.serialize())
|
||||
|
@ -195,9 +208,9 @@ impl Directory {
|
|||
.await?
|
||||
.text()
|
||||
.await
|
||||
.map_err(|err| trc::Cause::Acme.from_http_error(err))?,
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))?,
|
||||
)
|
||||
.map_err(|err| trc::Cause::Acme.from_json_error(err))
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))
|
||||
}
|
||||
pub async fn nonce(&self) -> trc::Result<String> {
|
||||
get_header(
|
||||
|
@ -300,7 +313,7 @@ async fn https(
|
|||
|
||||
let mut request = builder
|
||||
.build()
|
||||
.map_err(|err| trc::Cause::Acme.from_http_error(err))?
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))?
|
||||
.request(method, url);
|
||||
|
||||
if let Some(body) = body {
|
||||
|
@ -312,8 +325,8 @@ async fn https(
|
|||
request
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| trc::Cause::Acme.from_http_error(err))?
|
||||
.assert_success(trc::Cause::Acme)
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))?
|
||||
.assert_success(trc::EventType::Acme(trc::AcmeEvent::Error))
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -321,9 +334,9 @@ fn get_header(response: &Response, header: &'static str) -> trc::Result<String>
|
|||
match response.headers().get_all(header).iter().last() {
|
||||
Some(value) => Ok(value
|
||||
.to_str()
|
||||
.map_err(|err| trc::Cause::Acme.from_http_str_error(err))?
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_str_error(err))?
|
||||
.to_string()),
|
||||
None => Err(trc::Cause::Acme
|
||||
None => Err(trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.details("Missing header")
|
||||
.ctx(trc::Key::Id, header)),
|
||||
|
|
|
@ -23,7 +23,7 @@ pub(crate) fn sign(
|
|||
let combined = format!("{}.{}", &protected, &payload);
|
||||
let signature = key
|
||||
.sign(&SystemRandom::new(), combined.as_bytes())
|
||||
.map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?;
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).caused_by(trc::location!()).reason(err))?;
|
||||
let signature = URL_SAFE_NO_PAD.encode(signature.as_ref());
|
||||
let body = Body {
|
||||
protected,
|
||||
|
@ -31,7 +31,7 @@ pub(crate) fn sign(
|
|||
signature,
|
||||
};
|
||||
|
||||
serde_json::to_string(&body).map_err(|err| trc::Cause::Acme.from_json_error(err))
|
||||
serde_json::to_string(&body).map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))
|
||||
}
|
||||
|
||||
pub(crate) fn key_authorization(key: &EcdsaKeyPair, token: &str) -> trc::Result<String> {
|
||||
|
@ -85,8 +85,8 @@ impl<'a> Protected<'a> {
|
|||
nonce,
|
||||
url,
|
||||
};
|
||||
let protected =
|
||||
serde_json::to_vec(&protected).map_err(|err| trc::Cause::Acme.from_json_error(err))?;
|
||||
let protected = serde_json::to_vec(&protected)
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))?;
|
||||
Ok(URL_SAFE_NO_PAD.encode(protected))
|
||||
}
|
||||
}
|
||||
|
@ -121,8 +121,8 @@ impl Jwk {
|
|||
x: &self.x,
|
||||
y: &self.y,
|
||||
};
|
||||
let json =
|
||||
serde_json::to_vec(&jwk_thumb).map_err(|err| trc::Cause::Acme.from_json_error(err))?;
|
||||
let json = serde_json::to_vec(&jwk_thumb)
|
||||
.map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_json_error(err))?;
|
||||
let hash = digest(&SHA256, &json);
|
||||
Ok(URL_SAFE_NO_PAD.encode(hash))
|
||||
}
|
||||
|
|
|
@ -36,14 +36,14 @@ impl Core {
|
|||
.unwrap_or_default();
|
||||
let renewal_date = validity[1] - provider.renew_before;
|
||||
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "process-cert",
|
||||
valid_not_before = %validity[0],
|
||||
valid_not_after = %validity[1],
|
||||
renewal_date = ?renewal_date,
|
||||
domains = ?provider.domains,
|
||||
"Loaded certificate for domains {:?}", provider.domains);
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::ProcessCert),
|
||||
Id = provider.id.to_string(),
|
||||
Name = provider.domains.as_slice(),
|
||||
ValidFrom = trc::Value::Timestamp(validity[0].timestamp() as u64),
|
||||
ValidTo = trc::Value::Timestamp(validity[1].timestamp() as u64),
|
||||
Renewal = trc::Value::Timestamp(renewal_date.timestamp() as u64),
|
||||
);
|
||||
|
||||
if !cached {
|
||||
self.store_cert(provider, &pem).await?;
|
||||
|
@ -58,18 +58,23 @@ impl Core {
|
|||
match self.order(provider).await {
|
||||
Ok(pem) => return self.process_cert(provider, pem, false).await,
|
||||
Err(err) if backoff < 16 => {
|
||||
tracing::debug!(
|
||||
context = "acme",
|
||||
event = "renew-backoff",
|
||||
domains = ?provider.domains,
|
||||
attempt = backoff,
|
||||
reason = ?err,
|
||||
"Failed to renew certificate, backing off for {} seconds",
|
||||
1 << backoff);
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::RenewBackoff),
|
||||
Id = provider.id.to_string(),
|
||||
Name = provider.domains.as_slice(),
|
||||
Attempt = backoff,
|
||||
NextRetry = 1 << backoff,
|
||||
CausedBy = err,
|
||||
);
|
||||
backoff = (backoff + 1).min(16);
|
||||
tokio::time::sleep(Duration::from_secs(1 << backoff)).await;
|
||||
}
|
||||
Err(err) => return Err(err.details("Failed to renew certificate")),
|
||||
Err(err) => {
|
||||
return Err(err
|
||||
.details("Failed to renew certificate")
|
||||
.ctx_unique(trc::Key::Id, provider.id.to_string())
|
||||
.ctx_unique(trc::Key::Name, provider.domains.as_slice()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,8 +91,11 @@ impl Core {
|
|||
let mut params = CertificateParams::new(provider.domains.clone());
|
||||
params.distinguished_name = DistinguishedName::new();
|
||||
params.alg = &PKCS_ECDSA_P256_SHA256;
|
||||
let cert = rcgen::Certificate::from_params(params)
|
||||
.map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?;
|
||||
let cert = rcgen::Certificate::from_params(params).map_err(|err| {
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)
|
||||
})?;
|
||||
|
||||
let (order_url, mut order) = account.new_order(provider.domains.clone()).await?;
|
||||
loop {
|
||||
|
@ -98,23 +106,22 @@ impl Core {
|
|||
.iter()
|
||||
.map(|url| self.authorize(provider, &account, url));
|
||||
try_join_all(auth_futures).await?;
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "auth-complete",
|
||||
domains = ?provider.domains.as_slice(),
|
||||
"Completed all authorizations"
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::AuthCompleted),
|
||||
Id = provider.id.to_string(),
|
||||
Name = provider.domains.as_slice(),
|
||||
);
|
||||
order = account.order(&order_url).await?;
|
||||
}
|
||||
OrderStatus::Processing => {
|
||||
for i in 0u64..10 {
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "processing",
|
||||
domains = ?provider.domains.as_slice(),
|
||||
attempt = i,
|
||||
"Processing order"
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::OrderProcessing),
|
||||
Id = provider.id.to_string(),
|
||||
Name = provider.domains.as_slice(),
|
||||
Attempt = i,
|
||||
);
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(1u64 << i)).await;
|
||||
order = account.order(&order_url).await?;
|
||||
if order.status != OrderStatus::Processing {
|
||||
|
@ -122,30 +129,30 @@ impl Core {
|
|||
}
|
||||
}
|
||||
if order.status == OrderStatus::Processing {
|
||||
return Err(trc::Cause::Acme
|
||||
return Err(trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.details("Order processing timed out"));
|
||||
}
|
||||
}
|
||||
OrderStatus::Ready => {
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "csr-send",
|
||||
domains = ?provider.domains.as_slice(),
|
||||
"Sending CSR"
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::OrderReady),
|
||||
Id = provider.id.to_string(),
|
||||
Name = provider.domains.as_slice(),
|
||||
);
|
||||
|
||||
let csr = cert
|
||||
.serialize_request_der()
|
||||
.map_err(|err| trc::Cause::Acme.caused_by(trc::location!()).reason(err))?;
|
||||
let csr = cert.serialize_request_der().map_err(|err| {
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)
|
||||
})?;
|
||||
order = account.finalize(order.finalize, csr).await?
|
||||
}
|
||||
OrderStatus::Valid { certificate } => {
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "download",
|
||||
domains = ?provider.domains.as_slice(),
|
||||
"Downloading certificate"
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::OrderValid),
|
||||
Id = provider.id.to_string(),
|
||||
Name = provider.domains.as_slice(),
|
||||
);
|
||||
|
||||
let pem = [
|
||||
|
@ -157,15 +164,15 @@ impl Core {
|
|||
return Ok(pem.into_bytes());
|
||||
}
|
||||
OrderStatus::Invalid => {
|
||||
tracing::warn!(
|
||||
context = "acme",
|
||||
event = "error",
|
||||
reason = "invalid-order",
|
||||
domains = ?provider.domains.as_slice(),
|
||||
"Invalid order"
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::OrderInvalid),
|
||||
Id = provider.id.to_string(),
|
||||
Name = provider.domains.as_slice(),
|
||||
);
|
||||
|
||||
return Err(trc::Cause::Acme.into_err().details("Invalid ACME order"));
|
||||
return Err(trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.into_err()
|
||||
.details("Invalid ACME order"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,22 +189,24 @@ impl Core {
|
|||
AuthStatus::Pending => {
|
||||
let Identifier::Dns(domain) = auth.identifier;
|
||||
let challenge_type = provider.challenge.challenge_type();
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "challenge",
|
||||
domain = domain,
|
||||
challenge = ?challenge_type,
|
||||
"Requesting challenge for domain {domain}"
|
||||
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::AuthStart),
|
||||
Name = domain.to_string(),
|
||||
Type = challenge_type.as_str(),
|
||||
Id = provider.id.to_string(),
|
||||
);
|
||||
|
||||
let challenge = auth
|
||||
.challenges
|
||||
.iter()
|
||||
.find(|c| c.typ == challenge_type)
|
||||
.ok_or(
|
||||
trc::Cause::Acme
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.into_err()
|
||||
.details("Missing Parameter")
|
||||
.ctx(trc::Key::Id, challenge_type.as_str()),
|
||||
.ctx(trc::Key::Id, provider.id.to_string())
|
||||
.ctx(trc::Key::Type, challenge_type.as_str()),
|
||||
)?;
|
||||
|
||||
match &provider.challenge {
|
||||
|
@ -241,12 +250,12 @@ impl Core {
|
|||
// First try deleting the record
|
||||
if let Err(err) = updater.delete(&name, &origin).await {
|
||||
// Errors are expected if the record does not exist
|
||||
tracing::trace!(
|
||||
context = "acme",
|
||||
event = "dns-delete",
|
||||
name = name,
|
||||
origin = origin,
|
||||
error = ?err,
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::DnsRecordDeletionFailed),
|
||||
Name = name.to_string(),
|
||||
Reason = err.to_string(),
|
||||
Origin = origin.to_string(),
|
||||
Id = provider.id.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -262,23 +271,20 @@ impl Core {
|
|||
)
|
||||
.await
|
||||
{
|
||||
tracing::warn!(
|
||||
context = "acme",
|
||||
event = "dns-create",
|
||||
name = name,
|
||||
origin = origin,
|
||||
error = ?err,
|
||||
"Failed to create DNS record.",
|
||||
);
|
||||
return Err(trc::Cause::Dns.caused_by(trc::location!()).reason(err));
|
||||
return Err(trc::EventType::Acme(
|
||||
trc::AcmeEvent::DnsRecordCreationFailed,
|
||||
)
|
||||
.ctx(trc::Key::Id, provider.id.to_string())
|
||||
.ctx(trc::Key::Name, name)
|
||||
.ctx(trc::Key::Origin, origin)
|
||||
.reason(err));
|
||||
}
|
||||
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "dns-create",
|
||||
name = name,
|
||||
origin = origin,
|
||||
"Successfully created DNS record.",
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::DnsRecordCreated),
|
||||
Name = name.to_string(),
|
||||
Origin = origin.to_string(),
|
||||
Id = provider.id.to_string(),
|
||||
);
|
||||
|
||||
// Wait for changes to propagate
|
||||
|
@ -292,25 +298,23 @@ impl Core {
|
|||
did_propagate = true;
|
||||
break;
|
||||
} else {
|
||||
tracing::debug!(
|
||||
context = "acme",
|
||||
event = "dns-lookup",
|
||||
name = name,
|
||||
origin = origin,
|
||||
contents = ?result,
|
||||
expected_proof = ?dns_proof,
|
||||
"DNS record has not propagated yet.",
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::DnsRecordNotPropagated),
|
||||
Id = provider.id.to_string(),
|
||||
Name = name.to_string(),
|
||||
Origin = origin.to_string(),
|
||||
Result = result.to_string(),
|
||||
Expected = dns_proof.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::trace!(
|
||||
context = "acme",
|
||||
event = "dns-lookup",
|
||||
name = name,
|
||||
origin = origin,
|
||||
error = ?err,
|
||||
"Failed to lookup DNS record.",
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::DnsRecordLookupFailed),
|
||||
Id = provider.id.to_string(),
|
||||
Name = name.to_string(),
|
||||
Origin = origin.to_string(),
|
||||
Reason = err.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -319,20 +323,18 @@ impl Core {
|
|||
}
|
||||
|
||||
if did_propagate {
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "dns-lookup",
|
||||
name = name,
|
||||
origin = origin,
|
||||
"DNS changes have been propagated.",
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::DnsRecordPropagated),
|
||||
Id = provider.id.to_string(),
|
||||
Name = name.to_string(),
|
||||
Origin = origin.to_string(),
|
||||
);
|
||||
} else {
|
||||
tracing::warn!(
|
||||
context = "acme",
|
||||
event = "dns-lookup",
|
||||
name = name,
|
||||
origin = origin,
|
||||
"DNS changes have not been propagated within the timeout.",
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::DnsRecordPropagationTimeout),
|
||||
Id = provider.id.to_string(),
|
||||
Name = name.to_string(),
|
||||
Origin = origin.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -343,9 +345,9 @@ impl Core {
|
|||
}
|
||||
AuthStatus::Valid => return Ok(()),
|
||||
_ => {
|
||||
return Err(trc::Cause::Acme
|
||||
return Err(trc::EventType::Acme(trc::AcmeEvent::AuthError)
|
||||
.into_err()
|
||||
.details("Authentication error")
|
||||
.ctx(trc::Key::Id, provider.id.to_string())
|
||||
.ctx(trc::Key::Status, auth.status.as_str()))
|
||||
}
|
||||
};
|
||||
|
@ -355,45 +357,47 @@ impl Core {
|
|||
let auth = account.auth(url).await?;
|
||||
match auth.status {
|
||||
AuthStatus::Pending => {
|
||||
tracing::info!(
|
||||
context = "acme",
|
||||
event = "auth-pending",
|
||||
domain = domain,
|
||||
attempt = i,
|
||||
"Authorization for domain {domain} is still pending",
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::AuthPending),
|
||||
Name = domain.to_string(),
|
||||
Id = provider.id.to_string(),
|
||||
Attempt = i,
|
||||
);
|
||||
|
||||
account.challenge(&challenge_url).await?
|
||||
}
|
||||
AuthStatus::Valid => {
|
||||
tracing::debug!(
|
||||
context = "acme",
|
||||
event = "auth-valid",
|
||||
domain = domain,
|
||||
"Authorization for domain {domain} is valid",
|
||||
trc::event!(
|
||||
Acme(trc::AcmeEvent::AuthValid),
|
||||
Name = domain.to_string(),
|
||||
Id = provider.id.to_string(),
|
||||
);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
return Err(trc::Cause::Acme
|
||||
return Err(trc::EventType::Acme(trc::AcmeEvent::AuthError)
|
||||
.into_err()
|
||||
.details("Authentication error")
|
||||
.ctx(trc::Key::Id, provider.id.to_string())
|
||||
.ctx(trc::Key::Status, auth.status.as_str()))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(trc::Cause::Acme
|
||||
Err(trc::EventType::Acme(trc::AcmeEvent::AuthTooManyAttempts)
|
||||
.into_err()
|
||||
.details("Too many authentication attempts")
|
||||
.ctx(trc::Key::Id, domain))
|
||||
.ctx(trc::Key::Id, provider.id.to_string())
|
||||
.ctx(trc::Key::Name, domain))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_cert(pem: &[u8]) -> trc::Result<(CertifiedKey, [DateTime<Utc>; 2])> {
|
||||
let mut pems = pem::parse_many(pem)
|
||||
.map_err(|err| trc::Cause::Acme.reason(err).caused_by(trc::location!()))?;
|
||||
let mut pems = pem::parse_many(pem).map_err(|err| {
|
||||
trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.reason(err)
|
||||
.caused_by(trc::location!())
|
||||
})?;
|
||||
if pems.len() < 2 {
|
||||
return Err(trc::Cause::Acme
|
||||
return Err(trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Size, pems.len())
|
||||
.details("Too few PEMs"));
|
||||
|
@ -402,7 +406,11 @@ fn parse_cert(pem: &[u8]) -> trc::Result<(CertifiedKey, [DateTime<Utc>; 2])> {
|
|||
pems.remove(0).contents(),
|
||||
))) {
|
||||
Ok(pk) => pk,
|
||||
Err(err) => return Err(trc::Cause::Acme.reason(err).caused_by(trc::location!())),
|
||||
Err(err) => {
|
||||
return Err(trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.reason(err)
|
||||
.caused_by(trc::location!()))
|
||||
}
|
||||
};
|
||||
let cert_chain: Vec<CertificateDer> = pems
|
||||
.into_iter()
|
||||
|
@ -417,7 +425,11 @@ fn parse_cert(pem: &[u8]) -> trc::Result<(CertifiedKey, [DateTime<Utc>; 2])> {
|
|||
.unwrap_or_default()
|
||||
})
|
||||
}
|
||||
Err(err) => return Err(trc::Cause::Acme.reason(err).caused_by(trc::location!())),
|
||||
Err(err) => {
|
||||
return Err(trc::EventType::Acme(trc::AcmeEvent::Error)
|
||||
.reason(err)
|
||||
.caused_by(trc::location!()))
|
||||
}
|
||||
};
|
||||
let cert = CertifiedKey::new(cert_chain, pk);
|
||||
Ok((cert, validity))
|
||||
|
|
|
@ -18,7 +18,6 @@ use tokio::{
|
|||
sync::watch,
|
||||
};
|
||||
use tokio_rustls::server::TlsStream;
|
||||
use tracing::Span;
|
||||
use utils::{config::Config, UnwrapFailure};
|
||||
|
||||
use crate::{
|
||||
|
@ -203,19 +202,21 @@ impl BuildSession for Arc<ServerInstance> {
|
|||
);
|
||||
None
|
||||
} else if let Some(in_flight) = self.limiter.is_allowed() {
|
||||
let todo = "build session id";
|
||||
let span = tracing::info_span!(
|
||||
"session",
|
||||
instance = self.id,
|
||||
protocol = ?self.protocol,
|
||||
remote.ip = remote_ip.to_string(),
|
||||
remote.port = remote_port,
|
||||
);
|
||||
// Enforce concurrency
|
||||
SessionData {
|
||||
stream,
|
||||
in_flight,
|
||||
span: tracing::info_span!(
|
||||
"session",
|
||||
instance = self.id,
|
||||
protocol = ?self.protocol,
|
||||
remote.ip = remote_ip.to_string(),
|
||||
remote.port = remote_port,
|
||||
),
|
||||
local_ip: local_addr.ip(),
|
||||
local_port: local_addr.port(),
|
||||
session_id: 0,
|
||||
remote_ip,
|
||||
remote_port,
|
||||
protocol: self.protocol,
|
||||
|
@ -335,13 +336,12 @@ impl ServerInstance {
|
|||
pub async fn tls_accept<T: SessionStream>(
|
||||
&self,
|
||||
stream: T,
|
||||
span: &Span,
|
||||
session_id: u64,
|
||||
) -> Result<TlsStream<T>, ()> {
|
||||
match &self.acceptor {
|
||||
TcpAcceptor::Tls { acceptor, .. } => match acceptor.accept(stream).await {
|
||||
Ok(stream) => {
|
||||
tracing::info!(
|
||||
parent: span,
|
||||
context = "tls",
|
||||
event = "handshake",
|
||||
version = ?stream.get_ref().1.protocol_version().unwrap_or(rustls::ProtocolVersion::TLSv1_3),
|
||||
|
@ -351,7 +351,6 @@ impl ServerInstance {
|
|||
}
|
||||
Err(err) => {
|
||||
tracing::debug!(
|
||||
parent: span,
|
||||
context = "tls",
|
||||
event = "error",
|
||||
"Failed to accept TLS connection: {}",
|
||||
|
@ -362,7 +361,6 @@ impl ServerInstance {
|
|||
},
|
||||
TcpAcceptor::Plain => {
|
||||
tracing::debug!(
|
||||
parent: span,
|
||||
context = "tls",
|
||||
event = "error",
|
||||
"Failed to accept TLS connection: {}",
|
||||
|
|
|
@ -67,7 +67,7 @@ pub struct SessionData<T: SessionStream> {
|
|||
pub remote_ip: IpAddr,
|
||||
pub remote_port: u16,
|
||||
pub protocol: ServerProtocol,
|
||||
pub span: tracing::Span,
|
||||
pub session_id: u64,
|
||||
pub in_flight: InFlight,
|
||||
pub instance: Arc<ServerInstance>,
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ pub trait SessionManager: Sync + Send + 'static + Clone {
|
|||
remote_ip: session.remote_ip,
|
||||
remote_port: session.remote_port,
|
||||
protocol: session.protocol,
|
||||
span: session.span,
|
||||
session_id: session.session_id,
|
||||
in_flight: session.in_flight,
|
||||
instance: session.instance,
|
||||
};
|
||||
|
|
|
@ -1117,19 +1117,19 @@ pub(super) trait DeserializeBytes {
|
|||
impl DeserializeBytes for &[u8] {
|
||||
fn range(&self, range: Range<usize>) -> trc::Result<&[u8]> {
|
||||
self.get(range.start..std::cmp::min(range.end, self.len()))
|
||||
.ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!()))
|
||||
.ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!()))
|
||||
}
|
||||
|
||||
fn deserialize_u8(&self, offset: usize) -> trc::Result<u8> {
|
||||
self.get(offset)
|
||||
.copied()
|
||||
.ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!()))
|
||||
.ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!()))
|
||||
}
|
||||
|
||||
fn deserialize_leb128<U: Leb128_>(&self) -> trc::Result<U> {
|
||||
self.read_leb128::<U>()
|
||||
.map(|(v, _)| v)
|
||||
.ok_or_else(|| trc::StoreCause::DataCorruption.caused_by(trc::location!()))
|
||||
.ok_or_else(|| trc::StoreEvent::DataCorruption.caused_by(trc::location!()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -315,7 +315,7 @@ impl ConfigManager {
|
|||
tokio::fs::write(&self.cfg_local_path, cfg_text)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
trc::Cause::Configuration
|
||||
trc::EventType::Config(trc::ConfigEvent::WriteError)
|
||||
.reason(err)
|
||||
.details("Failed to write local configuration")
|
||||
.ctx(trc::Key::Path, self.cfg_local_path.display().to_string())
|
||||
|
@ -327,8 +327,9 @@ impl ConfigManager {
|
|||
.fetch_config_resource(resource_id)
|
||||
.await
|
||||
.map_err(|reason| {
|
||||
trc::Cause::Configuration
|
||||
trc::EventType::Config(trc::ConfigEvent::FetchError)
|
||||
.caused_by(trc::location!())
|
||||
.details("Failed to fetch external configuration")
|
||||
.ctx(trc::Key::Reason, reason)
|
||||
})?;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ impl WebAdminManager {
|
|||
contents,
|
||||
})
|
||||
.map_err(|err| {
|
||||
trc::ResourceCause::Error
|
||||
trc::ResourceEvent::Error
|
||||
.reason(err)
|
||||
.ctx(trc::Key::Path, path.to_string())
|
||||
.caused_by(trc::location!())
|
||||
|
@ -65,14 +65,14 @@ impl WebAdminManager {
|
|||
.get_blob(WEBADMIN_KEY, 0..usize::MAX)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
trc::ResourceCause::NotFound
|
||||
trc::ResourceEvent::NotFound
|
||||
.caused_by(trc::location!())
|
||||
.details("Webadmin bundle not found")
|
||||
})?;
|
||||
|
||||
// Uncompress
|
||||
let mut bundle = zip::ZipArchive::new(Cursor::new(bundle)).map_err(|err| {
|
||||
trc::ResourceCause::Error
|
||||
trc::ResourceEvent::Error
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)
|
||||
.details("Failed to decompress webadmin bundle")
|
||||
|
@ -81,7 +81,7 @@ impl WebAdminManager {
|
|||
for i in 0..bundle.len() {
|
||||
let (file_name, contents) = {
|
||||
let mut file = bundle.by_index(i).map_err(|err| {
|
||||
trc::ResourceCause::Error
|
||||
trc::ResourceEvent::Error
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)
|
||||
.details("Failed to read file from webadmin bundle")
|
||||
|
@ -139,7 +139,7 @@ impl WebAdminManager {
|
|||
.fetch_resource("webadmin")
|
||||
.await
|
||||
.map_err(|err| {
|
||||
trc::ResourceCause::Error
|
||||
trc::ResourceEvent::Error
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)
|
||||
.details("Failed to download webadmin")
|
||||
|
@ -175,7 +175,7 @@ impl TempDir {
|
|||
}
|
||||
|
||||
fn unpack_error(err: std::io::Error) -> trc::Error {
|
||||
trc::ResourceCause::Error
|
||||
trc::ResourceEvent::Error
|
||||
.reason(err)
|
||||
.details("Failed to unpack webadmin bundle")
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ pub async fn exec_untrain(ctx: PluginContext<'_>) -> Variable {
|
|||
}
|
||||
|
||||
async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable {
|
||||
let span: &tracing::Span = ctx.span;
|
||||
let store = match &ctx.arguments[0] {
|
||||
Variable::String(v) if !v.is_empty() => ctx.core.storage.lookups.get(v.as_ref()),
|
||||
_ => Some(&ctx.core.storage.lookup),
|
||||
|
@ -51,7 +50,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable {
|
|||
store
|
||||
} else {
|
||||
tracing::warn!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_train",
|
||||
event = "failed",
|
||||
reason = "Unknown store id",
|
||||
|
@ -63,7 +62,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable {
|
|||
let is_spam = ctx.arguments[2].to_bool();
|
||||
if text.is_empty() {
|
||||
tracing::debug!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_train",
|
||||
event = "failed",
|
||||
reason = "Empty message",
|
||||
|
@ -82,7 +81,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable {
|
|||
);
|
||||
if model.weights.is_empty() {
|
||||
tracing::debug!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_train",
|
||||
event = "failed",
|
||||
reason = "No weights found",
|
||||
|
@ -91,7 +90,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable {
|
|||
}
|
||||
|
||||
tracing::debug!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_train",
|
||||
event = "train",
|
||||
is_spam = is_spam,
|
||||
|
@ -152,7 +151,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> Variable {
|
|||
}
|
||||
|
||||
pub async fn exec_classify(ctx: PluginContext<'_>) -> Variable {
|
||||
let span = ctx.span;
|
||||
|
||||
let store = match &ctx.arguments[0] {
|
||||
Variable::String(v) if !v.is_empty() => ctx.core.storage.lookups.get(v.as_ref()),
|
||||
_ => Some(&ctx.core.storage.lookup),
|
||||
|
@ -161,7 +160,7 @@ pub async fn exec_classify(ctx: PluginContext<'_>) -> Variable {
|
|||
store
|
||||
} else {
|
||||
tracing::warn!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_classify",
|
||||
event = "failed",
|
||||
reason = "Unknown store id",
|
||||
|
@ -198,7 +197,7 @@ pub async fn exec_classify(ctx: PluginContext<'_>) -> Variable {
|
|||
(weights.spam, weights.ham)
|
||||
} else {
|
||||
tracing::warn!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:classify",
|
||||
event = "failed",
|
||||
reason = "Failed to obtain training counts",
|
||||
|
@ -209,7 +208,7 @@ pub async fn exec_classify(ctx: PluginContext<'_>) -> Variable {
|
|||
// Make sure we have enough training data
|
||||
if spam_learns < classifier.min_learns || ham_learns < classifier.min_learns {
|
||||
tracing::debug!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_classify",
|
||||
event = "skip-classify",
|
||||
reason = "Not enough training data",
|
||||
|
@ -249,7 +248,7 @@ pub async fn exec_is_balanced(ctx: PluginContext<'_>) -> Variable {
|
|||
return true.into();
|
||||
}
|
||||
|
||||
let span = ctx.span;
|
||||
|
||||
let store = match &ctx.arguments[0] {
|
||||
Variable::String(v) if !v.is_empty() => ctx.core.storage.lookups.get(v.as_ref()),
|
||||
_ => Some(&ctx.core.storage.lookup),
|
||||
|
@ -258,7 +257,7 @@ pub async fn exec_is_balanced(ctx: PluginContext<'_>) -> Variable {
|
|||
store
|
||||
} else {
|
||||
tracing::warn!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_is_balanced",
|
||||
event = "failed",
|
||||
reason = "Unknown store id",
|
||||
|
@ -275,7 +274,7 @@ pub async fn exec_is_balanced(ctx: PluginContext<'_>) -> Variable {
|
|||
(weights.spam as f64, weights.ham as f64)
|
||||
} else {
|
||||
tracing::warn!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_is_balanced",
|
||||
event = "failed",
|
||||
reason = "Failed to obtain training counts",
|
||||
|
@ -294,7 +293,7 @@ pub async fn exec_is_balanced(ctx: PluginContext<'_>) -> Variable {
|
|||
};
|
||||
|
||||
tracing::debug!(
|
||||
parent: span,
|
||||
|
||||
context = "sieve:bayes_is_balanced",
|
||||
event = "result",
|
||||
is_balanced = %result,
|
||||
|
|
|
@ -15,7 +15,6 @@ pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
|
|||
}
|
||||
|
||||
pub async fn exec(ctx: PluginContext<'_>) -> Variable {
|
||||
let span = ctx.span.clone();
|
||||
let mut arguments = ctx.arguments.into_iter();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
@ -36,7 +35,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable {
|
|||
Ok(result) => result.status.success(),
|
||||
Err(err) => {
|
||||
tracing::warn!(
|
||||
parent: span,
|
||||
context = "sieve",
|
||||
event = "execute-failed",
|
||||
reason = %err,
|
||||
|
|
|
@ -67,7 +67,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable {
|
|||
}
|
||||
} else {
|
||||
tracing::debug!(
|
||||
parent: ctx.span,
|
||||
context = "sieve:lookup",
|
||||
event = "failed",
|
||||
reason = "Unknown lookup id",
|
||||
|
@ -93,7 +92,6 @@ pub async fn exec_get(ctx: PluginContext<'_>) -> Variable {
|
|||
.unwrap_or_default()
|
||||
} else {
|
||||
tracing::debug!(
|
||||
parent: ctx.span,
|
||||
context = "sieve:key_get",
|
||||
event = "failed",
|
||||
reason = "Unknown store or lookup id",
|
||||
|
@ -131,7 +129,6 @@ pub async fn exec_set(ctx: PluginContext<'_>) -> Variable {
|
|||
.into()
|
||||
} else {
|
||||
tracing::warn!(
|
||||
parent: ctx.span,
|
||||
context = "sieve:key_set",
|
||||
event = "failed",
|
||||
reason = "Unknown store id",
|
||||
|
@ -293,7 +290,7 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable {
|
|||
}
|
||||
Err(err) => {
|
||||
tracing::warn!(
|
||||
parent: ctx.span,
|
||||
|
||||
context = "sieve:key_exists_http",
|
||||
event = "failed",
|
||||
resource = resource.as_ref(),
|
||||
|
@ -309,7 +306,6 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable {
|
|||
}
|
||||
|
||||
tracing::debug!(
|
||||
parent: ctx.span,
|
||||
context = "sieve:key_exists_http",
|
||||
event = "fetch",
|
||||
resource = resource.as_ref(),
|
||||
|
@ -322,7 +318,7 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable {
|
|||
}
|
||||
Err(err) => {
|
||||
tracing::warn!(
|
||||
parent: ctx.span,
|
||||
|
||||
context = "sieve:key_exists_http",
|
||||
event = "failed",
|
||||
resource = resource.as_ref(),
|
||||
|
@ -333,7 +329,7 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable {
|
|||
}
|
||||
Ok(response) => {
|
||||
tracing::warn!(
|
||||
parent: ctx.span,
|
||||
|
||||
context = "sieve:key_exists_http",
|
||||
event = "failed",
|
||||
resource = resource.as_ref(),
|
||||
|
@ -342,7 +338,7 @@ pub async fn exec_remote(ctx: PluginContext<'_>) -> Variable {
|
|||
}
|
||||
Err(err) => {
|
||||
tracing::warn!(
|
||||
parent: ctx.span,
|
||||
|
||||
context = "sieve:key_exists_http",
|
||||
event = "failed",
|
||||
resource = resource.as_ref(),
|
||||
|
@ -384,7 +380,6 @@ pub async fn exec_local_domain(ctx: PluginContext<'_>) -> Variable {
|
|||
.into();
|
||||
} else {
|
||||
tracing::warn!(
|
||||
parent: ctx.span,
|
||||
context = "sieve:is_local_domain",
|
||||
event = "failed",
|
||||
reason = "Unknown directory",
|
||||
|
|
|
@ -24,7 +24,7 @@ use super::ScriptModification;
|
|||
type RegisterPluginFnc = fn(u32, &mut FunctionMap) -> ();
|
||||
|
||||
pub struct PluginContext<'x> {
|
||||
pub span: &'x tracing::Span,
|
||||
pub session_id: u64,
|
||||
pub core: &'x Core,
|
||||
pub cache: &'x ScriptCache,
|
||||
pub message: &'x Message<'x>,
|
||||
|
|
|
@ -77,7 +77,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable {
|
|||
}
|
||||
}
|
||||
|
||||
let span = ctx.span;
|
||||
let address = ctx.arguments[0].to_string();
|
||||
let timeout = Duration::from_secs((ctx.arguments[1].to_integer() as u64).clamp(5, 60));
|
||||
// Send message to address
|
||||
|
@ -85,7 +84,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable {
|
|||
Ok(response) => response.into(),
|
||||
Err(err) => {
|
||||
tracing::debug!(
|
||||
parent: span,
|
||||
context = "sieve:pyzor_check",
|
||||
event = "failed",
|
||||
reason = %err,
|
||||
|
|
|
@ -17,8 +17,6 @@ pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
|
|||
}
|
||||
|
||||
pub async fn exec(ctx: PluginContext<'_>) -> Variable {
|
||||
let span = ctx.span;
|
||||
|
||||
// Obtain store name
|
||||
let store = match &ctx.arguments[0] {
|
||||
Variable::String(v) if !v.is_empty() => ctx.core.storage.lookups.get(v.as_ref()),
|
||||
|
@ -29,7 +27,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable {
|
|||
store
|
||||
} else {
|
||||
tracing::warn!(
|
||||
parent: span,
|
||||
context = "sieve:query",
|
||||
event = "failed",
|
||||
reason = "Unknown store",
|
||||
|
@ -42,7 +39,6 @@ pub async fn exec(ctx: PluginContext<'_>) -> Variable {
|
|||
let query = ctx.arguments[1].to_string();
|
||||
if query.is_empty() {
|
||||
tracing::warn!(
|
||||
parent: span,
|
||||
context = "sieve:query",
|
||||
event = "invalid",
|
||||
reason = "Empty query string",
|
||||
|
|
|
@ -38,7 +38,7 @@ impl ImapDirectory {
|
|||
AUTH_XOAUTH2
|
||||
}
|
||||
_ => {
|
||||
trc::bail!(trc::StoreCause::NotSupported
|
||||
trc::bail!(trc::StoreEvent::NotSupported
|
||||
.ctx(
|
||||
trc::Key::Reason,
|
||||
"IMAP server does not offer any supported auth mechanisms."
|
||||
|
@ -58,32 +58,32 @@ impl ImapDirectory {
|
|||
},
|
||||
}
|
||||
} else {
|
||||
Err(trc::StoreCause::NotSupported
|
||||
Err(trc::StoreEvent::NotSupported
|
||||
.caused_by(trc::location!())
|
||||
.protocol(trc::Protocol::Imap))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn email_to_ids(&self, _address: &str) -> trc::Result<Vec<u32>> {
|
||||
Err(trc::StoreCause::NotSupported
|
||||
Err(trc::StoreEvent::NotSupported
|
||||
.caused_by(trc::location!())
|
||||
.protocol(trc::Protocol::Imap))
|
||||
}
|
||||
|
||||
pub async fn rcpt(&self, _address: &str) -> trc::Result<bool> {
|
||||
Err(trc::StoreCause::NotSupported
|
||||
Err(trc::StoreEvent::NotSupported
|
||||
.caused_by(trc::location!())
|
||||
.protocol(trc::Protocol::Imap))
|
||||
}
|
||||
|
||||
pub async fn vrfy(&self, _address: &str) -> trc::Result<Vec<String>> {
|
||||
Err(trc::StoreCause::NotSupported
|
||||
Err(trc::StoreEvent::NotSupported
|
||||
.caused_by(trc::location!())
|
||||
.protocol(trc::Protocol::Imap))
|
||||
}
|
||||
|
||||
pub async fn expn(&self, _address: &str) -> trc::Result<Vec<String>> {
|
||||
Err(trc::StoreCause::NotSupported
|
||||
Err(trc::StoreEvent::NotSupported
|
||||
.caused_by(trc::location!())
|
||||
.protocol(trc::Protocol::Imap))
|
||||
}
|
||||
|
|
|
@ -422,7 +422,7 @@ impl ManageDirectory for Store {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
return Err(trc::ManageCause::NotSupported.caused_by(trc::location!()));
|
||||
return Err(trc::ManageEvent::NotSupported.caused_by(trc::location!()));
|
||||
}
|
||||
(
|
||||
PrincipalAction::Set,
|
||||
|
@ -762,7 +762,7 @@ impl ManageDirectory for Store {
|
|||
}
|
||||
|
||||
_ => {
|
||||
return Err(trc::StoreCause::NotSupported.caused_by(trc::location!()));
|
||||
return Err(trc::StoreEvent::NotSupported.caused_by(trc::location!()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1056,25 +1056,25 @@ impl From<Principal<String>> for Principal<u32> {
|
|||
}
|
||||
|
||||
pub fn err_missing(field: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::ManageCause::MissingParameter.ctx(trc::Key::Key, field)
|
||||
trc::ManageEvent::MissingParameter.ctx(trc::Key::Key, field)
|
||||
}
|
||||
|
||||
pub fn err_exists(field: impl Into<trc::Value>, value: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::ManageCause::AlreadyExists
|
||||
trc::ManageEvent::AlreadyExists
|
||||
.ctx(trc::Key::Key, field)
|
||||
.ctx(trc::Key::Value, value)
|
||||
}
|
||||
|
||||
pub fn not_found(value: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::ManageCause::NotFound.ctx(trc::Key::Key, value)
|
||||
trc::ManageEvent::NotFound.ctx(trc::Key::Key, value)
|
||||
}
|
||||
|
||||
pub fn unsupported(details: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::ManageCause::NotSupported.ctx(trc::Key::Details, details)
|
||||
trc::ManageEvent::NotSupported.ctx(trc::Key::Details, details)
|
||||
}
|
||||
|
||||
pub fn error(details: impl Into<trc::Value>, reason: Option<impl Into<trc::Value>>) -> trc::Error {
|
||||
trc::ManageCause::Error
|
||||
trc::ManageEvent::Error
|
||||
.ctx(trc::Key::Details, details)
|
||||
.ctx_opt(trc::Key::Reason, reason)
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ impl Serialize for &Principal<u32> {
|
|||
impl Deserialize for Principal<u32> {
|
||||
fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
|
||||
deserialize(bytes).ok_or_else(|| {
|
||||
trc::StoreCause::DataCorruption
|
||||
trc::StoreEvent::DataCorruption
|
||||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Value, bytes)
|
||||
})
|
||||
|
@ -79,12 +79,12 @@ impl Deserialize for PrincipalIdType {
|
|||
let mut bytes = bytes_.iter();
|
||||
Ok(PrincipalIdType {
|
||||
account_id: bytes.next_leb128().ok_or_else(|| {
|
||||
trc::StoreCause::DataCorruption
|
||||
trc::StoreEvent::DataCorruption
|
||||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Value, bytes_)
|
||||
})?,
|
||||
typ: Type::from_u8(*bytes.next().ok_or_else(|| {
|
||||
trc::StoreCause::DataCorruption
|
||||
trc::StoreEvent::DataCorruption
|
||||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Value, bytes_)
|
||||
})?),
|
||||
|
|
|
@ -79,7 +79,7 @@ impl LdapDirectory {
|
|||
{
|
||||
Ok(Some(principal)) => principal,
|
||||
Err(err)
|
||||
if err.matches(trc::Cause::Store(trc::StoreCause::Ldap))
|
||||
if err.matches(trc::EventType::Store(trc::StoreEvent::LdapError))
|
||||
&& err
|
||||
.value(trc::Key::Code)
|
||||
.and_then(|v| v.to_uint())
|
||||
|
@ -332,7 +332,10 @@ impl LdapMappings {
|
|||
fn entry_to_principal(&self, entry: SearchEntry) -> Principal<String> {
|
||||
let mut principal = Principal::default();
|
||||
|
||||
trc::event!(LdapQuery, Value = format!("{entry:?}"));
|
||||
trc::event!(
|
||||
Store(trc::StoreEvent::LdapQuery),
|
||||
Value = format!("{entry:?}")
|
||||
);
|
||||
|
||||
for (attr, value) in entry.attrs {
|
||||
if self.attr_name.contains(&attr) {
|
||||
|
|
|
@ -21,14 +21,14 @@ impl SmtpDirectory {
|
|||
.authenticate(credentials)
|
||||
.await
|
||||
} else {
|
||||
Err(trc::StoreCause::NotSupported
|
||||
Err(trc::StoreEvent::NotSupported
|
||||
.caused_by(trc::location!())
|
||||
.protocol(trc::Protocol::Smtp))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn email_to_ids(&self, _address: &str) -> trc::Result<Vec<u32>> {
|
||||
Err(trc::StoreCause::NotSupported
|
||||
Err(trc::StoreEvent::NotSupported
|
||||
.caused_by(trc::location!())
|
||||
.protocol(trc::Protocol::Smtp))
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl SmtpDirectory {
|
|||
Ok(true)
|
||||
}
|
||||
Severity::PermanentNegativeCompletion => Ok(false),
|
||||
_ => Err(trc::StoreCause::Unexpected
|
||||
_ => Err(trc::StoreEvent::UnexpectedError
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Smtp)
|
||||
.ctx(trc::Key::Code, reply.code())
|
||||
.ctx(trc::Key::Details, reply.message)),
|
||||
|
@ -127,10 +127,10 @@ impl SmtpClient {
|
|||
.split('\n')
|
||||
.map(|p| p.to_string())
|
||||
.collect::<Vec<String>>()),
|
||||
code @ (550 | 551 | 553 | 500 | 502) => Err(trc::StoreCause::NotSupported
|
||||
code @ (550 | 551 | 553 | 500 | 502) => Err(trc::StoreEvent::NotSupported
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Smtp)
|
||||
.ctx(trc::Key::Code, code)),
|
||||
code => Err(trc::StoreCause::Unexpected
|
||||
code => Err(trc::StoreEvent::UnexpectedError
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Smtp)
|
||||
.ctx(trc::Key::Code, code)
|
||||
.ctx(trc::Key::Details, reply.message)),
|
||||
|
|
|
@ -59,7 +59,7 @@ impl<T: serde::Serialize + serde::de::DeserializeOwned> Principal<T> {
|
|||
// Token needs to validate with at least one of the TOTP secrets
|
||||
is_totp_verified = TOTP::from_url(secret)
|
||||
.map_err(|err| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.reason(err)
|
||||
.details(secret.to_string())
|
||||
})?
|
||||
|
@ -86,7 +86,7 @@ impl<T: serde::Serialize + serde::de::DeserializeOwned> Principal<T> {
|
|||
// Only let the client know if the TOTP code is missing
|
||||
// if the password is correct
|
||||
|
||||
Err(trc::AuthCause::MissingTotp.into_err())
|
||||
Err(trc::AuthEvent::MissingTotp.into_err())
|
||||
} else {
|
||||
// Return the TOTP verification status
|
||||
|
||||
|
@ -128,7 +128,7 @@ async fn verify_hash_prefix(hashed_secret: &str, secret: &str) -> trc::Result<bo
|
|||
.ok();
|
||||
}
|
||||
Err(err) => {
|
||||
tx.send(Err(trc::AuthCause::Error
|
||||
tx.send(Err(trc::AuthEvent::Error
|
||||
.reason(err)
|
||||
.details(hashed_secret)))
|
||||
.ok();
|
||||
|
@ -137,7 +137,9 @@ async fn verify_hash_prefix(hashed_secret: &str, secret: &str) -> trc::Result<bo
|
|||
|
||||
match rx.await {
|
||||
Ok(result) => result,
|
||||
Err(err) => Err(trc::Cause::Thread.reason(err)),
|
||||
Err(err) => Err(trc::EventType::Server(trc::ServerEvent::ThreadError)
|
||||
.caused_by(trc::location!())
|
||||
.reason(err)),
|
||||
}
|
||||
} else if hashed_secret.starts_with("$2") {
|
||||
// Blowfish crypt
|
||||
|
@ -155,7 +157,7 @@ async fn verify_hash_prefix(hashed_secret: &str, secret: &str) -> trc::Result<bo
|
|||
// MD5 based hash
|
||||
Ok(md5_crypt::verify(secret, hashed_secret))
|
||||
} else {
|
||||
Err(trc::AuthCause::Error
|
||||
Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details(hashed_secret.to_string()))
|
||||
}
|
||||
|
@ -256,12 +258,12 @@ pub async fn verify_secret_hash(hashed_secret: &str, secret: &str) -> trc::Resul
|
|||
}
|
||||
}
|
||||
"PLAIN" | "plain" | "CLEAR" | "clear" => Ok(hashed_secret == secret),
|
||||
_ => Err(trc::AuthCause::Error
|
||||
_ => Err(trc::AuthEvent::Error
|
||||
.ctx(trc::Key::Reason, "Unsupported algorithm")
|
||||
.details(hashed_secret.to_string())),
|
||||
}
|
||||
} else {
|
||||
Err(trc::AuthCause::Error
|
||||
Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details(hashed_secret.to_string()))
|
||||
}
|
||||
|
|
|
@ -158,10 +158,10 @@ impl IntoError for PoolError<LdapError> {
|
|||
fn into_error(self) -> trc::Error {
|
||||
match self {
|
||||
PoolError::Backend(error) => error.into_error(),
|
||||
PoolError::Timeout(_) => trc::StoreCause::Pool
|
||||
PoolError::Timeout(_) => trc::StoreEvent::PoolError
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Ldap)
|
||||
.details("Connection timed out"),
|
||||
err => trc::StoreCause::Pool
|
||||
err => trc::StoreEvent::PoolError
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Ldap)
|
||||
.reason(err),
|
||||
}
|
||||
|
@ -172,10 +172,10 @@ impl IntoError for PoolError<ImapError> {
|
|||
fn into_error(self) -> trc::Error {
|
||||
match self {
|
||||
PoolError::Backend(error) => error.into_error(),
|
||||
PoolError::Timeout(_) => trc::StoreCause::Pool
|
||||
PoolError::Timeout(_) => trc::StoreEvent::PoolError
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Imap)
|
||||
.details("Connection timed out"),
|
||||
err => trc::StoreCause::Pool
|
||||
err => trc::StoreEvent::PoolError
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Imap)
|
||||
.reason(err),
|
||||
}
|
||||
|
@ -186,10 +186,10 @@ impl IntoError for PoolError<mail_send::Error> {
|
|||
fn into_error(self) -> trc::Error {
|
||||
match self {
|
||||
PoolError::Backend(error) => error.into_error(),
|
||||
PoolError::Timeout(_) => trc::StoreCause::Pool
|
||||
PoolError::Timeout(_) => trc::StoreEvent::PoolError
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Smtp)
|
||||
.details("Connection timed out"),
|
||||
err => trc::StoreCause::Pool
|
||||
err => trc::StoreEvent::PoolError
|
||||
.ctx(trc::Key::Protocol, trc::Protocol::Smtp)
|
||||
.reason(err),
|
||||
}
|
||||
|
@ -198,24 +198,24 @@ impl IntoError for PoolError<mail_send::Error> {
|
|||
|
||||
impl IntoError for ImapError {
|
||||
fn into_error(self) -> trc::Error {
|
||||
trc::Cause::Imap.reason(self)
|
||||
trc::ImapEvent::Error.into_err().reason(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoError for mail_send::Error {
|
||||
fn into_error(self) -> trc::Error {
|
||||
trc::Cause::Smtp.reason(self)
|
||||
trc::SmtpEvent::Error.into_err().reason(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoError for LdapError {
|
||||
fn into_error(self) -> trc::Error {
|
||||
if let LdapError::LdapResult { result } = &self {
|
||||
trc::StoreCause::Ldap
|
||||
trc::StoreEvent::LdapError
|
||||
.ctx(trc::Key::Code, result.rc)
|
||||
.reason(self)
|
||||
} else {
|
||||
trc::StoreCause::Ldap.reason(self)
|
||||
trc::StoreEvent::LdapError.reason(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -497,13 +497,13 @@ impl SerializeResponse for trc::Error {
|
|||
if let Some(code) = self
|
||||
.value_as_str(trc::Key::Code)
|
||||
.or_else(|| match self.as_ref() {
|
||||
trc::Cause::Store(trc::StoreCause::NotFound) => {
|
||||
trc::EventType::Store(trc::StoreEvent::NotFound) => {
|
||||
Some(ResponseCode::NonExistent.as_str())
|
||||
}
|
||||
trc::Cause::Store(_) => Some(ResponseCode::ContactAdmin.as_str()),
|
||||
trc::Cause::Limit(trc::LimitCause::Quota) => Some(ResponseCode::OverQuota.as_str()),
|
||||
trc::Cause::Limit(_) => Some(ResponseCode::Limit.as_str()),
|
||||
trc::Cause::Auth(_) => Some(ResponseCode::AuthenticationFailed.as_str()),
|
||||
trc::EventType::Store(_) => Some(ResponseCode::ContactAdmin.as_str()),
|
||||
trc::EventType::Limit(trc::LimitEvent::Quota) => Some(ResponseCode::OverQuota.as_str()),
|
||||
trc::EventType::Limit(_) => Some(ResponseCode::Limit.as_str()),
|
||||
trc::EventType::Auth(_) => Some(ResponseCode::AuthenticationFailed.as_str()),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
|
|
|
@ -464,7 +464,7 @@ impl Display for Token {
|
|||
impl Error {
|
||||
pub fn err(tag: Option<String>, message: impl Into<trc::Value>) -> Self {
|
||||
Error::Error {
|
||||
response: trc::Cause::Imap
|
||||
response: trc::ImapEvent::Error
|
||||
.ctx(trc::Key::Details, message)
|
||||
.ctx_opt(trc::Key::Id, tag)
|
||||
.ctx(trc::Key::Type, ResponseType::Bad)
|
||||
|
@ -488,13 +488,13 @@ impl<T: CommandParser> Default for Receiver<T> {
|
|||
|
||||
impl<T: CommandParser> Request<T> {
|
||||
pub fn into_error(self, message: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.ctx(trc::Key::Details, message)
|
||||
.ctx(trc::Key::Id, self.tag)
|
||||
}
|
||||
|
||||
pub fn into_parse_error(self, message: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.ctx(trc::Key::Details, message)
|
||||
.ctx(trc::Key::Id, self.tag)
|
||||
.ctx(trc::Key::Code, ResponseCode::Parse)
|
||||
|
@ -503,7 +503,7 @@ impl<T: CommandParser> Request<T> {
|
|||
}
|
||||
|
||||
pub(crate) fn bad(tag: impl Into<trc::Value>, message: impl Into<trc::Value>) -> trc::Error {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.ctx(trc::Key::Details, message)
|
||||
.ctx(trc::Key::Id, tag)
|
||||
.ctx(trc::Key::Type, ResponseType::Bad)
|
||||
|
|
|
@ -21,11 +21,11 @@ rustls-pemfile = "2.0"
|
|||
tokio = { version = "1.23", features = ["full"] }
|
||||
tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
|
||||
parking_lot = "0.12"
|
||||
tracing = "0.1"
|
||||
ahash = { version = "0.8" }
|
||||
md5 = "0.7.0"
|
||||
dashmap = "6.0"
|
||||
rand = "0.8.5"
|
||||
tracing = "0.1"
|
||||
|
||||
[features]
|
||||
test_mode = []
|
||||
|
|
|
@ -21,10 +21,11 @@ impl<T: SessionStream> Session<T> {
|
|||
let c = println!("{}", line);
|
||||
}*/
|
||||
|
||||
tracing::trace!(parent: &self.span,
|
||||
tracing::trace!(
|
||||
event = "read",
|
||||
data = std::str::from_utf8(bytes).unwrap_or("[invalid UTF8]"),
|
||||
size = bytes.len());
|
||||
data = std::str::from_utf8(bytes).unwrap_or("[invalid UTF8]"),
|
||||
size = bytes.len()
|
||||
);
|
||||
|
||||
let mut bytes = bytes.iter();
|
||||
let mut requests = Vec::with_capacity(2);
|
||||
|
@ -267,7 +268,7 @@ impl<T: SessionStream> Session<T> {
|
|||
.await?
|
||||
.is_some()
|
||||
{
|
||||
return Err(trc::LimitCause::TooManyRequests.into_err());
|
||||
return Err(trc::LimitEvent::TooManyRequests.into_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,13 +280,13 @@ impl<T: SessionStream> Session<T> {
|
|||
if self.instance.acceptor.is_tls() {
|
||||
Ok(request)
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("TLS is not available.")
|
||||
.id(request.tag))
|
||||
}
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Already in TLS mode.")
|
||||
.id(request.tag))
|
||||
|
@ -295,7 +296,7 @@ impl<T: SessionStream> Session<T> {
|
|||
if let State::NotAuthenticated { .. } = state {
|
||||
Ok(request)
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Already authenticated.")
|
||||
.id(request.tag))
|
||||
|
@ -306,13 +307,13 @@ impl<T: SessionStream> Session<T> {
|
|||
if self.is_tls || self.jmap.core.imap.allow_plain_auth {
|
||||
Ok(request)
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("LOGIN is disabled on the clear-text port.")
|
||||
.id(request.tag))
|
||||
}
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Already authenticated.")
|
||||
.id(request.tag))
|
||||
|
@ -341,7 +342,7 @@ impl<T: SessionStream> Session<T> {
|
|||
if let State::Authenticated { .. } | State::Selected { .. } = state {
|
||||
Ok(request)
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Not authenticated.")
|
||||
.id(request.tag))
|
||||
|
@ -367,18 +368,18 @@ impl<T: SessionStream> Session<T> {
|
|||
{
|
||||
Ok(request)
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Not permitted in EXAMINE state.")
|
||||
.id(request.tag))
|
||||
}
|
||||
}
|
||||
State::Authenticated { .. } => Err(trc::Cause::Imap
|
||||
State::Authenticated { .. } => Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("No mailbox is selected.")
|
||||
.ctx(trc::Key::Type, ResponseType::Bad)
|
||||
.id(request.tag)),
|
||||
State::NotAuthenticated { .. } => Err(trc::Cause::Imap
|
||||
State::NotAuthenticated { .. } => Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Not authenticated.")
|
||||
.id(request.tag)),
|
||||
|
|
|
@ -36,7 +36,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
jmap: session.jmap.clone(),
|
||||
imap: session.imap.clone(),
|
||||
account_id: access_token.primary_id(),
|
||||
span: session.span.clone(),
|
||||
session_id: session.session_id,
|
||||
mailboxes: Mutex::new(vec![]),
|
||||
state: access_token.state().into(),
|
||||
in_flight,
|
||||
|
@ -356,7 +356,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
{
|
||||
new_accounts.push(account);
|
||||
} else {
|
||||
tracing::debug!(parent: &self.span, "Removed unlinked shared account {}", account.account_id);
|
||||
tracing::debug!("Removed unlinked shared account {}", account.account_id);
|
||||
|
||||
// Add unshared mailboxes to deleted list
|
||||
if let Some(changes) = &mut changes {
|
||||
|
@ -374,7 +374,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.skip(1)
|
||||
.any(|m| m.account_id == account_id)
|
||||
{
|
||||
tracing::debug!(parent: &self.span, "Adding shared account {}", account_id);
|
||||
tracing::debug!("Adding shared account {}", account_id);
|
||||
added_account_ids.push(account_id);
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
added_accounts.push(account);
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::debug!(parent: &self.span, "Failed to fetch shared mailbox.");
|
||||
tracing::debug!("Failed to fetch shared mailbox.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -520,7 +520,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
changed_accounts.push(account_mailboxes);
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::debug!(parent: &self.span, "Failed to fetch mailboxes:.");
|
||||
tracing::debug!("Failed to fetch mailboxes:.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -638,7 +638,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await?
|
||||
.map(|mailbox| mailbox.effective_acl(&access_token).contains(item))
|
||||
.ok_or_else(|| {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.caused_by(trc::location!())
|
||||
.details("Mailbox no longer exists.")
|
||||
})?)
|
||||
|
|
|
@ -229,7 +229,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await?
|
||||
.and_then(|obj| obj.get(&Property::Cid).as_uint())
|
||||
.ok_or_else(|| {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.caused_by(trc::location!())
|
||||
.details("Mailbox unavailable")
|
||||
.account_id(mailbox.account_id)
|
||||
|
@ -270,7 +270,7 @@ impl SelectedMailbox {
|
|||
Ok(ids)
|
||||
} else {
|
||||
let saved_ids = self.get_saved_search().await.ok_or_else(|| {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("No saved search found.")
|
||||
})?;
|
||||
|
|
|
@ -77,14 +77,14 @@ pub struct Session<T: SessionStream> {
|
|||
pub stream_tx: Arc<tokio::sync::Mutex<WriteHalf<T>>>,
|
||||
pub in_flight: InFlight,
|
||||
pub remote_addr: IpAddr,
|
||||
pub span: tracing::Span,
|
||||
pub session_id: u64,
|
||||
}
|
||||
|
||||
pub struct SessionData<T: SessionStream> {
|
||||
pub account_id: u32,
|
||||
pub jmap: JMAP,
|
||||
pub imap: Arc<Inner>,
|
||||
pub span: tracing::Span,
|
||||
pub session_id: u64,
|
||||
pub mailboxes: parking_lot::Mutex<Vec<Account>>,
|
||||
pub stream_tx: Arc<tokio::sync::Mutex<WriteHalf<T>>>,
|
||||
pub state: AtomicU32,
|
||||
|
@ -234,7 +234,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
account_id: self.account_id,
|
||||
jmap: self.jmap,
|
||||
imap: self.imap,
|
||||
span: self.span,
|
||||
session_id: self.session_id,
|
||||
mailboxes: self.mailboxes,
|
||||
stream_tx: new_stream,
|
||||
state: self.state,
|
||||
|
|
|
@ -67,24 +67,24 @@ impl<T: SessionStream> Session<T> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
tracing::debug!(parent: &self.span, event = "close", "IMAP connection closed by client.");
|
||||
tracing::debug!( event = "close", "IMAP connection closed by client.");
|
||||
break;
|
||||
}
|
||||
},
|
||||
Ok(Err(err)) => {
|
||||
tracing::debug!(parent: &self.span, event = "error", reason = %err, "IMAP connection error.");
|
||||
tracing::debug!( event = "error", reason = %err, "IMAP connection error.");
|
||||
break;
|
||||
},
|
||||
Err(_) => {
|
||||
self.write_bytes(&b"* BYE Connection timed out.\r\n"[..]).await.ok();
|
||||
tracing::debug!(parent: &self.span, "IMAP connection timed out.");
|
||||
tracing::debug!( "IMAP connection timed out.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ = shutdown_rx.changed() => {
|
||||
self.write_bytes(&b"* BYE Server shutting down.\r\n"[..]).await.ok();
|
||||
tracing::debug!(parent: &self.span, event = "shutdown", "IMAP server shutting down.");
|
||||
tracing::debug!( event = "shutdown", "IMAP server shutting down.");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
@ -104,7 +104,7 @@ impl<T: SessionStream> Session<T> {
|
|||
(false, &manager.imap.imap_inner.greeting_plain)
|
||||
};
|
||||
if let Err(err) = session.stream.write_all(greeting).await {
|
||||
tracing::debug!(parent: &session.span, event = "error", reason = %err, "Failed to write greeting.");
|
||||
tracing::debug!( event = "error", reason = %err, "Failed to write greeting.");
|
||||
return Err(());
|
||||
}
|
||||
let _ = session.stream.flush().await;
|
||||
|
@ -123,7 +123,7 @@ impl<T: SessionStream> Session<T> {
|
|||
jmap,
|
||||
imap: manager.imap.imap_inner,
|
||||
instance: session.instance,
|
||||
span: session.span,
|
||||
session_id: session.session_id,
|
||||
in_flight: session.in_flight,
|
||||
remote_addr: session.remote_ip,
|
||||
stream_rx,
|
||||
|
@ -156,7 +156,7 @@ impl<T: SessionStream> Session<T> {
|
|||
|
||||
// Upgrade to TLS
|
||||
let (stream_rx, stream_tx) =
|
||||
tokio::io::split(self.instance.tls_accept(stream, &self.span).await?);
|
||||
tokio::io::split(self.instance.tls_accept(stream, self.session_id).await?);
|
||||
let stream_tx = Arc::new(tokio::sync::Mutex::new(stream_tx));
|
||||
|
||||
Ok(Session {
|
||||
|
@ -169,7 +169,7 @@ impl<T: SessionStream> Session<T> {
|
|||
is_tls: true,
|
||||
is_condstore: self.is_condstore,
|
||||
is_qresync: self.is_qresync,
|
||||
span: self.span,
|
||||
session_id: self.session_id,
|
||||
in_flight: self.in_flight,
|
||||
remote_addr: self.remote_addr,
|
||||
stream_rx,
|
||||
|
@ -185,7 +185,6 @@ impl<T: SessionStream> Session<T> {
|
|||
let c = println!("{}", line);
|
||||
}*/
|
||||
tracing::trace!(
|
||||
parent: &self.span,
|
||||
event = "write",
|
||||
data = std::str::from_utf8(bytes).unwrap_or_default(),
|
||||
size = bytes.len()
|
||||
|
@ -193,7 +192,8 @@ impl<T: SessionStream> Session<T> {
|
|||
|
||||
let mut stream = self.stream_tx.lock().await;
|
||||
if let Err(err) = stream.write_all(bytes).await {
|
||||
Err(trc::Cause::Network
|
||||
Err(trc::NetworkEvent::WriteError
|
||||
.into_err()
|
||||
.reason(err)
|
||||
.details("Failed to write to stream"))
|
||||
} else {
|
||||
|
@ -203,13 +203,13 @@ impl<T: SessionStream> Session<T> {
|
|||
}
|
||||
|
||||
pub async fn write_error(&self, err: trc::Error) -> bool {
|
||||
tracing::warn!(parent: &self.span, event = "error", reason = %err, "IMAP error.");
|
||||
tracing::warn!( event = "error", reason = %err, "IMAP error.");
|
||||
|
||||
if err.should_write_err() {
|
||||
let disconnect = err.must_disconnect();
|
||||
|
||||
if let Err(err) = self.write_bytes(err.serialize()).await {
|
||||
tracing::debug!(parent: &self.span, event = "error", reason = %err, "Failed to write error.");
|
||||
tracing::debug!( event = "error", reason = %err, "Failed to write error.");
|
||||
false
|
||||
} else {
|
||||
!disconnect
|
||||
|
@ -227,7 +227,6 @@ impl<T: SessionStream> super::SessionData<T> {
|
|||
let c = println!("{}", line);
|
||||
}*/
|
||||
tracing::trace!(
|
||||
parent: &self.span,
|
||||
event = "write",
|
||||
data = std::str::from_utf8(bytes).unwrap_or_default(),
|
||||
size = bytes.len()
|
||||
|
@ -235,7 +234,8 @@ impl<T: SessionStream> super::SessionData<T> {
|
|||
|
||||
let mut stream = self.stream_tx.lock().await;
|
||||
if let Err(err) = stream.write_all(bytes.as_ref()).await {
|
||||
Err(trc::Cause::Network
|
||||
Err(trc::NetworkEvent::WriteError
|
||||
.into_err()
|
||||
.reason(err)
|
||||
.details("Failed to write to stream"))
|
||||
} else {
|
||||
|
@ -245,7 +245,7 @@ impl<T: SessionStream> super::SessionData<T> {
|
|||
}
|
||||
|
||||
pub async fn write_error(&self, err: trc::Error) -> trc::Result<()> {
|
||||
tracing::warn!(parent: &self.span, event = "error", reason = %err, "IMAP error.");
|
||||
tracing::warn!( event = "error", reason = %err, "IMAP error.");
|
||||
|
||||
if err.should_write_err() {
|
||||
self.write_bytes(err.serialize()).await
|
||||
|
|
|
@ -218,7 +218,7 @@ impl<T: SessionStream> Session<T> {
|
|||
.await
|
||||
.imap_ctx(&arguments.tag, trc::location!())?
|
||||
.ok_or_else(|| {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Account does not exist")
|
||||
.id(arguments.tag.to_string())
|
||||
|
@ -250,7 +250,7 @@ impl<T: SessionStream> Session<T> {
|
|||
}) {
|
||||
acl
|
||||
} else {
|
||||
return Err(trc::StoreCause::DataCorruption
|
||||
return Err(trc::StoreEvent::DataCorruption
|
||||
.into_err()
|
||||
.id(arguments.tag)
|
||||
.ctx(trc::Key::Reason, "Invalid mailbox ACL")
|
||||
|
@ -393,18 +393,18 @@ impl<T: SessionStream> SessionData<T> {
|
|||
{
|
||||
Ok((mailbox, values, access_token))
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("You do not have enough permissions to perform this operation.")
|
||||
.code(ResponseCode::NoPerm))
|
||||
}
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.caused_by(trc::location!())
|
||||
.details("Mailbox does not exist."))
|
||||
}
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox does not exist."))
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ impl<T: SessionStream> Session<T> {
|
|||
let mailbox = if let Some(mailbox) = data.get_mailbox_by_name(&arguments.mailbox_name) {
|
||||
mailbox
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox does not exist.")
|
||||
.code(ResponseCode::TryCreate)
|
||||
|
@ -72,7 +72,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await
|
||||
.imap_ctx(&arguments.tag, trc::location!())?
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(
|
||||
"You do not have the required permissions to append messages to this mailbox.",
|
||||
|
@ -116,7 +116,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
last_change_id = Some(email.change_id);
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(if err.matches(trc::Cause::Limit(trc::LimitCause::Quota)) {
|
||||
return Err(if err.matches(trc::EventType::Limit(trc::LimitEvent::Quota)) {
|
||||
err.details("Disk quota exceeded.")
|
||||
.code(ResponseCode::OverQuota)
|
||||
} else {
|
||||
|
|
|
@ -25,7 +25,7 @@ impl<T: SessionStream> Session<T> {
|
|||
if !args.params.is_empty() {
|
||||
let challenge = base64_decode(args.params.pop().unwrap().as_bytes())
|
||||
.ok_or_else(|| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details("Failed to decode challenge.")
|
||||
.id(args.tag.clone())
|
||||
|
@ -38,7 +38,7 @@ impl<T: SessionStream> Session<T> {
|
|||
decode_challenge_oauth(&challenge)
|
||||
}
|
||||
.map_err(|err| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details(err)
|
||||
.id(args.tag.clone())
|
||||
|
@ -55,7 +55,7 @@ impl<T: SessionStream> Session<T> {
|
|||
self.write_bytes(b"+ \"\"\r\n".to_vec()).await
|
||||
}
|
||||
}
|
||||
_ => Err(trc::AuthCause::Error
|
||||
_ => Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details("Authentication mechanism not supported.")
|
||||
.id(args.tag)
|
||||
|
@ -93,14 +93,14 @@ impl<T: SessionStream> Session<T> {
|
|||
}
|
||||
}
|
||||
.map_err(|err| {
|
||||
if err.matches(trc::Cause::Auth(trc::AuthCause::Failed)) {
|
||||
if err.matches(trc::EventType::Auth(trc::AuthEvent::Failed)) {
|
||||
let auth_failures = self.state.auth_failures();
|
||||
if auth_failures < self.jmap.core.imap.max_auth_failures {
|
||||
self.state = State::NotAuthenticated {
|
||||
auth_failures: auth_failures + 1,
|
||||
};
|
||||
} else {
|
||||
return trc::AuthCause::TooManyAttempts.into_err().caused_by(err);
|
||||
return trc::AuthEvent::TooManyAttempts.into_err().caused_by(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ impl<T: SessionStream> Session<T> {
|
|||
Some(Some(limiter)) => Some(limiter),
|
||||
None => None,
|
||||
Some(None) => {
|
||||
return Err(trc::LimitCause::ConcurrentRequest
|
||||
return Err(trc::LimitEvent::ConcurrentRequest
|
||||
.into_err()
|
||||
.id(tag.clone()));
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ impl<T: SessionStream> Session<T> {
|
|||
if let Some(mailbox) = data.get_mailbox_by_name(&arguments.mailbox_name) {
|
||||
mailbox
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Destination mailbox does not exist.")
|
||||
.code(ResponseCode::TryCreate)
|
||||
|
@ -64,7 +64,7 @@ impl<T: SessionStream> Session<T> {
|
|||
if src_mailbox.id.account_id == dest_mailbox.account_id
|
||||
&& src_mailbox.id.mailbox_id == dest_mailbox.mailbox_id
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Source and destination mailboxes are the same.")
|
||||
.code(ResponseCode::Cannot)
|
||||
|
@ -101,7 +101,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.imap_ctx(&arguments.tag, trc::location!())?;
|
||||
|
||||
if ids.is_empty() {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("No messages were found.")
|
||||
.id(arguments.tag));
|
||||
|
@ -118,7 +118,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await
|
||||
.imap_ctx(&arguments.tag, trc::location!())?
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(concat!(
|
||||
"You do not have the required permissions to ",
|
||||
|
@ -135,7 +135,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await
|
||||
.imap_ctx(&arguments.tag, trc::location!())?
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(concat!(
|
||||
"You do not have the required permissions to ",
|
||||
|
@ -325,12 +325,12 @@ impl<T: SessionStream> SessionData<T> {
|
|||
// Map copied JMAP Ids to IMAP UIDs in the destination folder.
|
||||
if copied_ids.is_empty() {
|
||||
return Err(if response.rtype != ResponseType::Ok {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(response.message)
|
||||
.ctx_opt(trc::Key::Code, response.code)
|
||||
} else {
|
||||
trc::Cause::Imap.into_err().details(if is_move {
|
||||
trc::ImapEvent::Error.into_err().details(if is_move {
|
||||
"No messages were moved."
|
||||
} else {
|
||||
"No messages were copied."
|
||||
|
|
|
@ -150,7 +150,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
{
|
||||
account
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Account no longer available.")
|
||||
.caused_by(trc::location!()));
|
||||
|
@ -236,7 +236,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
name = prefix.trim();
|
||||
}
|
||||
if name.is_empty() {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(format!("Invalid folder name '{mailbox_name}'.",)));
|
||||
}
|
||||
|
@ -248,11 +248,11 @@ impl<T: SessionStream> SessionData<T> {
|
|||
for path_item in name.split('/') {
|
||||
let path_item = path_item.trim();
|
||||
if path_item.is_empty() {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Invalid empty path item."));
|
||||
} else if path_item.len() > self.jmap.core.jmap.mailbox_name_max_len {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox name is too long."));
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
}
|
||||
|
||||
if path.len() > self.jmap.core.jmap.mailbox_max_depth {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox path is too deep."));
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
let account = if first_path_item == &self.jmap.core.jmap.shared_folder {
|
||||
// Shared Folders/<username>/<folder>
|
||||
if path.len() < 3 {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailboxes under root shared folders are not allowed.")
|
||||
.code(ResponseCode::Cannot));
|
||||
|
@ -294,7 +294,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
account
|
||||
} else {
|
||||
#[allow(clippy::unnecessary_literal_unwrap)]
|
||||
return Err(trc::Cause::Imap.into_err().details(format!(
|
||||
return Err(trc::ImapEvent::Error.into_err().details(format!(
|
||||
"Shared account '{}' not found.",
|
||||
prefix.unwrap_or_default()
|
||||
)));
|
||||
|
@ -302,7 +302,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
} else if let Some(account) = mailboxes.first() {
|
||||
account
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Internal server error.")
|
||||
.caused_by(trc::location!())
|
||||
|
@ -311,7 +311,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
|
||||
// Locate parent mailbox
|
||||
if account.mailbox_names.contains_key(&full_path) {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(format!("Mailbox '{}' already exists.", full_path)));
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.check_mailbox_acl(account_id, parent_mailbox_id, Acl::CreateChild)
|
||||
.await?
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("You are not allowed to create sub mailboxes under this mailbox.")
|
||||
.code(ResponseCode::NoPerm));
|
||||
|
@ -356,7 +356,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.caused_by(trc::location!())?
|
||||
.is_member(account_id)
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("You are not allowed to create root folders under shared folders.")
|
||||
.code(ResponseCode::Cannot));
|
||||
|
@ -382,7 +382,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.results
|
||||
.is_empty()
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(format!(
|
||||
"A mailbox with role '{mailbox_role}' already exists.",
|
||||
|
|
|
@ -54,7 +54,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
if let Some(mailbox) = self.get_mailbox_by_name(&arguments.mailbox_name) {
|
||||
(mailbox.account_id, mailbox.mailbox_id)
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox does not exist.")
|
||||
.code(ResponseCode::TryCreate)
|
||||
|
@ -75,7 +75,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
{
|
||||
Ok(did_remove_emails) => did_remove_emails,
|
||||
Err(err) => {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(err.description.unwrap_or("Delete failed".into()))
|
||||
.code(ResponseCode::from(err.type_))
|
||||
|
|
|
@ -46,7 +46,7 @@ impl<T: SessionStream> Session<T> {
|
|||
.await
|
||||
.imap_ctx(&request.tag, trc::location!())?
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(concat!(
|
||||
"You do not have the required permissions ",
|
||||
|
@ -60,7 +60,7 @@ impl<T: SessionStream> Session<T> {
|
|||
let sequence = match request.tokens.into_iter().next() {
|
||||
Some(Token::Argument(value)) if is_uid => {
|
||||
let sequence = parse_sequence_set(&value).map_err(|err| {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(err)
|
||||
.ctx(trc::Key::Type, ResponseType::Bad)
|
||||
|
|
|
@ -88,13 +88,13 @@ impl<T: SessionStream> SessionData<T> {
|
|||
// Validate VANISHED parameter
|
||||
if arguments.include_vanished {
|
||||
if !is_qresync {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Enable QRESYNC first to use the VANISHED parameter.")
|
||||
.ctx(trc::Key::Type, ResponseType::Bad)
|
||||
.id(arguments.tag));
|
||||
} else if !is_uid {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("VANISHED parameter is only available for UID FETCH.")
|
||||
.ctx(trc::Key::Type, ResponseType::Bad)
|
||||
|
@ -423,7 +423,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
}
|
||||
Err(_) => {
|
||||
self.write_error(
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(format!(
|
||||
"Failed to decode part {} of message {}.",
|
||||
|
|
|
@ -56,7 +56,7 @@ impl<T: SessionStream> Session<T> {
|
|||
// Send continuation response
|
||||
self.write_bytes(b"+ Idling, send 'DONE' to stop.\r\n".to_vec())
|
||||
.await?;
|
||||
tracing::debug!(parent: &self.span, event = "start", context = "idle", "Starting IDLE.");
|
||||
tracing::debug!(event = "start", context = "idle", "Starting IDLE.");
|
||||
let mut buf = vec![0; 1024];
|
||||
loop {
|
||||
tokio::select! {
|
||||
|
@ -65,22 +65,22 @@ impl<T: SessionStream> Session<T> {
|
|||
Ok(Ok(bytes_read)) => {
|
||||
if bytes_read > 0 {
|
||||
if (buf[..bytes_read]).windows(4).any(|w| w == b"DONE") {
|
||||
tracing::debug!(parent: &self.span, event = "stop", context = "idle", "Stopping IDLE.");
|
||||
tracing::debug!( event = "stop", context = "idle", "Stopping IDLE.");
|
||||
return self.write_bytes(StatusResponse::completed(Command::Idle)
|
||||
.with_tag(request.tag)
|
||||
.into_bytes()).await;
|
||||
}
|
||||
} else {
|
||||
tracing::debug!(parent: &self.span, event = "close", );
|
||||
return Err(trc::Cause::Network.into_err().details("IMAP connection closed by client.").id(request.tag));
|
||||
tracing::debug!( event = "close", );
|
||||
return Err(trc::NetworkEvent::Closed.into_err().details("IMAP connection closed by client.").id(request.tag));
|
||||
}
|
||||
},
|
||||
Ok(Err(err)) => {
|
||||
return Err(trc::Cause::Network.reason(err).details("IMAP connection error.").id(request.tag));
|
||||
return Err(trc::NetworkEvent::ReadError.into_err().reason(err).details("IMAP connection error.").id(request.tag));
|
||||
},
|
||||
Err(_) => {
|
||||
self.write_bytes(&b"* BYE IDLE timed out.\r\n"[..]).await.ok();
|
||||
return Err(trc::Cause::Network.into_err().details("IMAP IDLE timed out.").id(request.tag));
|
||||
return Err(trc::NetworkEvent::Timeout.into_err().details("IMAP IDLE timed out.").id(request.tag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ impl<T: SessionStream> Session<T> {
|
|||
}
|
||||
} else {
|
||||
self.write_bytes(&b"* BYE Server shutting down.\r\n"[..]).await.ok();
|
||||
return Err(trc::Cause::Network.into_err().details("IDLE channel closed.").id(request.tag));
|
||||
return Err(trc::NetworkEvent::Closed.into_err().details("IDLE channel closed.").id(request.tag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
}
|
||||
}
|
||||
if recursive_match && !filter_subscribed {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("RECURSIVEMATCH requires the SUBSCRIBED selection option.")
|
||||
.id(tag));
|
||||
|
|
|
@ -84,14 +84,16 @@ impl<T> ImapContext<T> for trc::Result<T> {
|
|||
fn imap_ctx(self, tag: &str, location: &'static str) -> trc::Result<T> {
|
||||
match self {
|
||||
Ok(value) => Ok(value),
|
||||
Err(err) => Err(if !err.matches(trc::Cause::Imap) {
|
||||
err.ctx(trc::Key::Id, tag.to_string())
|
||||
.ctx(trc::Key::Details, "Internal Server Error")
|
||||
.ctx(trc::Key::Code, ResponseCode::ContactAdmin)
|
||||
.ctx(trc::Key::CausedBy, location)
|
||||
} else {
|
||||
err.ctx(trc::Key::Id, tag.to_string())
|
||||
}),
|
||||
Err(err) => Err(
|
||||
if !err.matches(trc::EventType::Imap(trc::ImapEvent::Error)) {
|
||||
err.ctx(trc::Key::Id, tag.to_string())
|
||||
.ctx(trc::Key::Details, "Internal Server Error")
|
||||
.ctx(trc::Key::Code, ResponseCode::ContactAdmin)
|
||||
.ctx(trc::Key::CausedBy, location)
|
||||
} else {
|
||||
err.ctx(trc::Key::Id, tag.to_string())
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
mailbox_id = (*mailbox_id_).into();
|
||||
break;
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Cannot move mailboxes between accounts.")
|
||||
.code(ResponseCode::Cannot)
|
||||
|
@ -73,7 +73,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
if let Some(mailbox_id) = mailbox_id {
|
||||
mailbox_id
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(format!("Mailbox '{}' not found.", arguments.mailbox_name))
|
||||
.code(ResponseCode::NonExistent)
|
||||
|
@ -93,7 +93,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await
|
||||
.imap_ctx(&arguments.tag, trc::location!())?
|
||||
.ok_or_else(|| {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(format!("Mailbox '{}' not found.", arguments.mailbox_name))
|
||||
.caused_by(trc::location!())
|
||||
|
@ -112,7 +112,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.effective_acl(&access_token)
|
||||
.contains(Acl::Modify)
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("You are not allowed to rename this mailbox.")
|
||||
.code(ResponseCode::NoPerm)
|
||||
|
|
|
@ -287,9 +287,11 @@ impl<T: SessionStream> SessionData<T> {
|
|||
search::Filter::Header(header, value) => {
|
||||
match HeaderName::parse(header) {
|
||||
Some(HeaderName::Other(header_name)) => {
|
||||
return Err(trc::Cause::Imap.into_err().details(format!(
|
||||
"Querying header '{header_name}' is not supported.",
|
||||
)));
|
||||
return Err(trc::ImapEvent::Error.into_err().details(
|
||||
format!(
|
||||
"Querying header '{header_name}' is not supported.",
|
||||
),
|
||||
));
|
||||
}
|
||||
Some(header_name) => {
|
||||
if !value.is_empty() {
|
||||
|
@ -410,7 +412,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("No saved search found."));
|
||||
}
|
||||
|
@ -610,7 +612,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
RoaringBitmap::from_sorted_iter([id.document_id()]).unwrap(),
|
||||
));
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(format!("Failed to parse email id '{id}'.",)));
|
||||
}
|
||||
|
@ -622,7 +624,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
id.document_id(),
|
||||
));
|
||||
} else {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(format!("Failed to parse thread id '{id}'.",)));
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ impl<T: SessionStream> Session<T> {
|
|||
// Validate QRESYNC arguments
|
||||
if let Some(qresync) = arguments.qresync {
|
||||
if !self.is_qresync {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("QRESYNC is not enabled.")
|
||||
.id(arguments.tag));
|
||||
|
@ -155,7 +155,7 @@ impl<T: SessionStream> Session<T> {
|
|||
)
|
||||
.await
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox does not exist.")
|
||||
.code(ResponseCode::NonExistent)
|
||||
|
|
|
@ -99,7 +99,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.collect(),
|
||||
})
|
||||
} else {
|
||||
Err(trc::Cause::Imap
|
||||
Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox does not exist.")
|
||||
.code(ResponseCode::NonExistent))
|
||||
|
@ -239,7 +239,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await?
|
||||
.and_then(|obj| obj.get(&Property::Cid).as_uint())
|
||||
.ok_or_else(|| {
|
||||
trc::StoreCause::Unexpected
|
||||
trc::StoreEvent::UnexpectedError
|
||||
.into_err()
|
||||
.details("Mailbox unavailable")
|
||||
.ctx(trc::Key::Reason, "Failed to obtain uid validity")
|
||||
|
|
|
@ -87,7 +87,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await
|
||||
.imap_ctx(&arguments.tag, trc::location!())?
|
||||
{
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(
|
||||
"You do not have the required permissions to modify messages in this mailbox.",
|
||||
|
|
|
@ -57,7 +57,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
let (account_id, mailbox_id) = match self.get_mailbox_by_name(&mailbox_name) {
|
||||
Some(mailbox) => (mailbox.account_id, mailbox.mailbox_id),
|
||||
None => {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox does not exist.")
|
||||
.code(ResponseCode::NonExistent)
|
||||
|
@ -71,7 +71,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
if account.account_id == account_id {
|
||||
if let Some(mailbox) = account.mailbox_state.get(&mailbox_id) {
|
||||
if mailbox.is_subscribed == subscribe {
|
||||
return Err(trc::Cause::Imap
|
||||
return Err(trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details(if subscribe {
|
||||
"Mailbox is already subscribed."
|
||||
|
@ -97,7 +97,7 @@ impl<T: SessionStream> SessionData<T> {
|
|||
.await
|
||||
.imap_ctx(&tag, trc::location!())?
|
||||
.ok_or_else(|| {
|
||||
trc::Cause::Imap
|
||||
trc::ImapEvent::Error
|
||||
.into_err()
|
||||
.details("Mailbox does not exist.")
|
||||
.code(ResponseCode::NonExistent)
|
||||
|
|
|
@ -79,64 +79,64 @@ impl Serialize for MethodErrorWrapper {
|
|||
let description = self.0.value(trc::Key::Details).and_then(|v| v.as_str());
|
||||
|
||||
let (error_type, description) = match self.0.as_ref() {
|
||||
trc::Cause::Jmap(cause) => match cause {
|
||||
trc::JmapCause::InvalidArguments => {
|
||||
trc::EventType::Jmap(cause) => match cause {
|
||||
trc::JmapEvent::InvalidArguments => {
|
||||
("invalidArguments", description.unwrap_or_default())
|
||||
}
|
||||
trc::JmapCause::RequestTooLarge => (
|
||||
trc::JmapEvent::RequestTooLarge => (
|
||||
"requestTooLarge",
|
||||
concat!(
|
||||
"The number of ids requested by the client exceeds the maximum number ",
|
||||
"the server is willing to process in a single method call."
|
||||
),
|
||||
),
|
||||
trc::JmapCause::StateMismatch => (
|
||||
trc::JmapEvent::StateMismatch => (
|
||||
"stateMismatch",
|
||||
concat!(
|
||||
"An \"ifInState\" argument was supplied, but ",
|
||||
"it does not match the current state."
|
||||
),
|
||||
),
|
||||
trc::JmapCause::AnchorNotFound => (
|
||||
trc::JmapEvent::AnchorNotFound => (
|
||||
"anchorNotFound",
|
||||
concat!(
|
||||
"An anchor argument was supplied, but it ",
|
||||
"cannot be found in the results of the query."
|
||||
),
|
||||
),
|
||||
trc::JmapCause::UnsupportedFilter => {
|
||||
trc::JmapEvent::UnsupportedFilter => {
|
||||
("unsupportedFilter", description.unwrap_or_default())
|
||||
}
|
||||
trc::JmapCause::UnsupportedSort => {
|
||||
trc::JmapEvent::UnsupportedSort => {
|
||||
("unsupportedSort", description.unwrap_or_default())
|
||||
}
|
||||
trc::JmapCause::NotFound => ("serverPartialFail", {
|
||||
trc::JmapEvent::NotFound => ("serverPartialFail", {
|
||||
concat!(
|
||||
"One or more items are no longer available on the ",
|
||||
"server, please try again."
|
||||
)
|
||||
}),
|
||||
trc::JmapCause::UnknownMethod => ("unknownMethod", description.unwrap_or_default()),
|
||||
trc::JmapCause::InvalidResultReference => {
|
||||
trc::JmapEvent::UnknownMethod => ("unknownMethod", description.unwrap_or_default()),
|
||||
trc::JmapEvent::InvalidResultReference => {
|
||||
("invalidResultReference", description.unwrap_or_default())
|
||||
}
|
||||
trc::JmapCause::Forbidden => ("forbidden", description.unwrap_or_default()),
|
||||
trc::JmapCause::AccountNotFound => (
|
||||
trc::JmapEvent::Forbidden => ("forbidden", description.unwrap_or_default()),
|
||||
trc::JmapEvent::AccountNotFound => (
|
||||
"accountNotFound",
|
||||
"The accountId does not correspond to a valid account",
|
||||
),
|
||||
trc::JmapCause::AccountNotSupportedByMethod => (
|
||||
trc::JmapEvent::AccountNotSupportedByMethod => (
|
||||
"accountNotSupportedByMethod",
|
||||
concat!(
|
||||
"The accountId given corresponds to a valid account, ",
|
||||
"but the account does not support this method or data type."
|
||||
),
|
||||
),
|
||||
trc::JmapCause::AccountReadOnly => (
|
||||
trc::JmapEvent::AccountReadOnly => (
|
||||
"accountReadOnly",
|
||||
"This method modifies state, but the account is read-only.",
|
||||
),
|
||||
trc::JmapCause::UnknownDataType => (
|
||||
trc::JmapEvent::UnknownDataType => (
|
||||
"unknownDataType",
|
||||
concat!(
|
||||
"The server does not recognise this data type, ",
|
||||
|
@ -144,16 +144,16 @@ impl Serialize for MethodErrorWrapper {
|
|||
"in the current Request Object."
|
||||
),
|
||||
),
|
||||
trc::JmapCause::CannotCalculateChanges => (
|
||||
trc::JmapEvent::CannotCalculateChanges => (
|
||||
"cannotCalculateChanges",
|
||||
concat!(
|
||||
"The server cannot calculate the changes ",
|
||||
"between the old and new states."
|
||||
),
|
||||
),
|
||||
trc::JmapCause::UnknownCapability
|
||||
| trc::JmapCause::NotJSON
|
||||
| trc::JmapCause::NotRequest => (
|
||||
trc::JmapEvent::UnknownCapability
|
||||
| trc::JmapEvent::NotJSON
|
||||
| trc::JmapEvent::NotRequest => (
|
||||
"serverUnavailable",
|
||||
concat!(
|
||||
"This server is temporarily unavailable. ",
|
||||
|
|
|
@ -67,7 +67,7 @@ impl JsonObjectParser for ChangesRequest {
|
|||
MethodObject::EmailSubmission => RequestArguments::EmailSubmission,
|
||||
MethodObject::Quota => RequestArguments::Quota,
|
||||
_ => {
|
||||
return Err(trc::JmapCause::UnknownMethod
|
||||
return Err(trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details(format!("{}/changes", parser.ctx)))
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ impl JsonObjectParser for CopyRequest<RequestArguments> {
|
|||
arguments: match &parser.ctx {
|
||||
MethodObject::Email => RequestArguments::Email,
|
||||
_ => {
|
||||
return Err(trc::JmapCause::UnknownMethod
|
||||
return Err(trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details(format!("{}/copy", parser.ctx)))
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ impl JsonObjectParser for GetRequest<RequestArguments> {
|
|||
MethodObject::Blob => RequestArguments::Blob(Default::default()),
|
||||
MethodObject::Quota => RequestArguments::Quota,
|
||||
_ => {
|
||||
return Err(trc::JmapCause::UnknownMethod
|
||||
return Err(trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details(format!("{}/get", parser.ctx)))
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ impl<T> GetRequest<T> {
|
|||
.collect::<Vec<_>>(),
|
||||
))
|
||||
} else {
|
||||
Err(trc::JmapCause::RequestTooLarge.into_err())
|
||||
Err(trc::JmapEvent::RequestTooLarge.into_err())
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
|
@ -195,7 +195,7 @@ impl<T> GetRequest<T> {
|
|||
.collect::<Vec<_>>(),
|
||||
))
|
||||
} else {
|
||||
Err(trc::JmapCause::RequestTooLarge.into_err())
|
||||
Err(trc::JmapEvent::RequestTooLarge.into_err())
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
|
|
|
@ -163,7 +163,7 @@ impl JsonObjectParser for QueryRequest<RequestArguments> {
|
|||
MethodObject::Principal => RequestArguments::Principal,
|
||||
MethodObject::Quota => RequestArguments::Quota,
|
||||
_ => {
|
||||
return Err(trc::JmapCause::UnknownMethod
|
||||
return Err(trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details(format!("{}/query", parser.ctx)))
|
||||
}
|
||||
|
@ -451,7 +451,7 @@ pub fn parse_filter(parser: &mut Parser) -> trc::Result<Vec<Filter>> {
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
return Err(trc::JmapCause::InvalidArguments
|
||||
return Err(trc::JmapEvent::InvalidArguments
|
||||
.into_err()
|
||||
.details("Malformed filter"));
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ impl JsonObjectParser for QueryChangesRequest {
|
|||
MethodObject::EmailSubmission => RequestArguments::EmailSubmission,
|
||||
MethodObject::Quota => RequestArguments::Quota,
|
||||
_ => {
|
||||
return Err(trc::JmapCause::UnknownMethod
|
||||
return Err(trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details(format!("{}/queryChanges", parser.ctx)))
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ impl JsonObjectParser for SetRequest<RequestArguments> {
|
|||
MethodObject::VacationResponse => RequestArguments::VacationResponse,
|
||||
MethodObject::SieveScript => RequestArguments::SieveScript(Default::default()),
|
||||
_ => {
|
||||
return Err(trc::JmapCause::UnknownMethod
|
||||
return Err(trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details(format!("{}/set", parser.ctx)))
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ impl<T> SetRequest<T> {
|
|||
})
|
||||
> max_objects_in_set
|
||||
{
|
||||
Err(trc::JmapCause::RequestTooLarge.into_err())
|
||||
Err(trc::JmapEvent::RequestTooLarge.into_err())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ impl SetResponse {
|
|||
state_change: None,
|
||||
})
|
||||
} else {
|
||||
Err(trc::JmapCause::RequestTooLarge.into_err())
|
||||
Err(trc::JmapEvent::RequestTooLarge.into_err())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ impl Serialize for Value {
|
|||
impl Deserialize for Value {
|
||||
fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
|
||||
Self::deserialize_from(&mut bytes.iter()).ok_or_else(|| {
|
||||
trc::StoreCause::DataCorruption
|
||||
trc::StoreEvent::DataCorruption
|
||||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Value, bytes)
|
||||
})
|
||||
|
@ -148,7 +148,7 @@ impl Serialize for &Object<Value> {
|
|||
impl Deserialize for Object<Value> {
|
||||
fn deserialize(bytes: &[u8]) -> trc::Result<Self> {
|
||||
Object::deserialize_from(&mut bytes.iter()).ok_or_else(|| {
|
||||
trc::StoreCause::DataCorruption
|
||||
trc::StoreEvent::DataCorruption
|
||||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Value, bytes)
|
||||
})
|
||||
|
|
|
@ -41,20 +41,20 @@ impl<'x> Parser<'x> {
|
|||
}
|
||||
|
||||
pub fn error(&self, message: &str) -> trc::Error {
|
||||
trc::JmapCause::NotJSON
|
||||
trc::JmapEvent::NotJSON
|
||||
.into_err()
|
||||
.details(format!("{message} at position {}.", self.pos))
|
||||
}
|
||||
|
||||
pub fn error_unterminated(&self) -> trc::Error {
|
||||
trc::JmapCause::NotJSON.into_err().details(format!(
|
||||
trc::JmapEvent::NotJSON.into_err().details(format!(
|
||||
"Unterminated string at position {pos}.",
|
||||
pos = self.pos
|
||||
))
|
||||
}
|
||||
|
||||
pub fn error_utf8(&self) -> trc::Error {
|
||||
trc::JmapCause::NotJSON.into_err().details(format!(
|
||||
trc::JmapEvent::NotJSON.into_err().details(format!(
|
||||
"Invalid UTF-8 sequence at position {pos}.",
|
||||
pos = self.pos
|
||||
))
|
||||
|
@ -62,7 +62,7 @@ impl<'x> Parser<'x> {
|
|||
|
||||
pub fn error_value(&mut self) -> trc::Error {
|
||||
if self.is_eof || self.skip_string() {
|
||||
trc::JmapCause::InvalidArguments.into_err().details(format!(
|
||||
trc::JmapEvent::InvalidArguments.into_err().details(format!(
|
||||
"Invalid value {:?} at position {}.",
|
||||
String::from_utf8_lossy(self.bytes[self.pos_marker..self.pos - 1].as_ref()),
|
||||
self.pos
|
||||
|
|
|
@ -117,14 +117,14 @@ impl<T: Eq> Token<T> {
|
|||
if self == token {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(trc::JmapCause::NotRequest.into_err().details(format!(
|
||||
Err(trc::JmapEvent::NotRequest.into_err().details(format!(
|
||||
"Invalid JMAP request: expected '{token}', got '{self}'."
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error(&self, property: &str, expected: &str) -> trc::Error {
|
||||
trc::JmapCause::InvalidArguments.into_err().details(if !property.is_empty() {
|
||||
trc::JmapEvent::InvalidArguments.into_err().details(if !property.is_empty() {
|
||||
format!("Invalid argument for '{property:?}': expected '{expected}', got '{self}'.",)
|
||||
} else {
|
||||
format!("Invalid argument: expected '{expected}', got '{self}'.")
|
||||
|
|
|
@ -351,7 +351,7 @@ impl JsonObjectParser for Capability {
|
|||
impl<'x> Parser<'x> {
|
||||
fn error_capability(&mut self) -> trc::Error {
|
||||
if self.is_eof || self.skip_string() {
|
||||
trc::JmapCause::UnknownCapability.into_err().details(
|
||||
trc::JmapEvent::UnknownCapability.into_err().details(
|
||||
String::from_utf8_lossy(self.bytes[self.pos_marker..self.pos - 1].as_ref())
|
||||
.into_owned(),
|
||||
)
|
||||
|
|
|
@ -50,12 +50,12 @@ impl Request {
|
|||
if found_valid_keys {
|
||||
Ok(request)
|
||||
} else {
|
||||
Err(trc::JmapCause::NotRequest
|
||||
Err(trc::JmapEvent::NotRequest
|
||||
.into_err()
|
||||
.details("Invalid JMAP request"))
|
||||
}
|
||||
} else {
|
||||
Err(trc::LimitCause::SizeRequest.into_err())
|
||||
Err(trc::LimitEvent::SizeRequest.into_err())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ impl Request {
|
|||
Token::Comma => continue,
|
||||
Token::ArrayEnd => break,
|
||||
_ => {
|
||||
return Err(trc::JmapCause::NotRequest
|
||||
return Err(trc::JmapEvent::NotRequest
|
||||
.into_err()
|
||||
.details("Invalid JMAP request"));
|
||||
}
|
||||
|
@ -99,13 +99,13 @@ impl Request {
|
|||
let method_name = match parser.next_token::<MethodName>() {
|
||||
Ok(Token::String(method)) => method,
|
||||
Ok(_) => {
|
||||
return Err(trc::JmapCause::NotRequest
|
||||
return Err(trc::JmapEvent::NotRequest
|
||||
.into_err()
|
||||
.details("Invalid JMAP request"));
|
||||
}
|
||||
Err(err)
|
||||
if err.matches(trc::Cause::Jmap(
|
||||
trc::JmapCause::InvalidArguments,
|
||||
if err.matches(trc::EventType::Jmap(
|
||||
trc::JmapEvent::InvalidArguments,
|
||||
)) =>
|
||||
{
|
||||
MethodName::error()
|
||||
|
@ -175,7 +175,7 @@ impl Request {
|
|||
(MethodFunction::Echo, MethodObject::Core) => {
|
||||
Echo::parse(parser).map(RequestMethod::Echo)
|
||||
}
|
||||
_ => Err(trc::JmapCause::UnknownMethod
|
||||
_ => Err(trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details(method_name.to_string())),
|
||||
};
|
||||
|
@ -202,7 +202,7 @@ impl Request {
|
|||
name: method_name,
|
||||
});
|
||||
} else {
|
||||
return Err(trc::LimitCause::CallsIn.into_err());
|
||||
return Err(trc::LimitEvent::CallsIn.into_err());
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
|
|
|
@ -80,7 +80,7 @@ impl JsonObjectParser for ResultReference {
|
|||
path,
|
||||
})
|
||||
} else {
|
||||
Err(trc::JmapCause::InvalidResultReference
|
||||
Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details("Missing required fields"))
|
||||
}
|
||||
|
|
|
@ -170,12 +170,12 @@ impl WebSocketMessage {
|
|||
MessageType::PushDisable if !found_request_keys && !found_push_keys => {
|
||||
Ok(WebSocketMessage::PushDisable)
|
||||
}
|
||||
_ => Err(trc::JmapCause::NotRequest
|
||||
_ => Err(trc::JmapEvent::NotRequest
|
||||
.into_err()
|
||||
.details("Invalid WebSocket JMAP request")),
|
||||
}
|
||||
} else {
|
||||
Err(trc::LimitCause::SizeRequest.into_err())
|
||||
Err(trc::LimitEvent::SizeRequest.into_err())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ impl Response {
|
|||
if let Some(resolved_id) = self.created_ids.get(reference) {
|
||||
*id = MaybeReference::Value(resolved_id.clone());
|
||||
} else {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!(
|
||||
"Id reference {reference:?} does not exist."
|
||||
|
@ -151,7 +151,7 @@ impl Response {
|
|||
*id = MaybeReference::Value(blob_id.clone());
|
||||
}
|
||||
Some(_) => {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!(
|
||||
"Id reference {parent_id:?} points to invalid type."
|
||||
|
@ -254,7 +254,7 @@ impl Response {
|
|||
if let Some(AnyId::Id(id)) = self.created_ids.get(ir) {
|
||||
Ok(*id)
|
||||
} else {
|
||||
Err(trc::JmapCause::InvalidResultReference
|
||||
Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!("Id reference {ir:?} not found.")))
|
||||
}
|
||||
|
@ -276,7 +276,7 @@ impl Response {
|
|||
.or_insert_with(Vec::new)
|
||||
.push(parent_id.to_string());
|
||||
} else {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!("Id reference {parent_id:?} not found.")));
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ impl Response {
|
|||
.or_insert_with(Vec::new)
|
||||
.push(parent_id.to_string());
|
||||
} else {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!("Id reference {parent_id:?} not found.")));
|
||||
}
|
||||
|
@ -319,7 +319,7 @@ fn topological_sort<T>(
|
|||
for (from_id, to_ids) in graph.iter() {
|
||||
for to_id in to_ids {
|
||||
if !create.contains_key(to_id) {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!(
|
||||
"Invalid reference to non-existing object {to_id:?} from {from_id:?}"
|
||||
|
@ -338,7 +338,7 @@ fn topological_sort<T>(
|
|||
if let Some(to_ids) = graph.get(from_id) {
|
||||
it_stack.push((it, from_id));
|
||||
if it_stack.len() > 1000 {
|
||||
return Err(trc::JmapCause::InvalidArguments
|
||||
return Err(trc::JmapEvent::InvalidArguments
|
||||
.into_err()
|
||||
.details("Cyclical references are not allowed.".to_string()));
|
||||
}
|
||||
|
@ -454,7 +454,7 @@ impl EvalResult {
|
|||
match value {
|
||||
Value::Id(id) => ids.push(id),
|
||||
_ => {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!(
|
||||
"Failed to evaluate {rr} result reference."
|
||||
|
@ -464,7 +464,7 @@ impl EvalResult {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!("Failed to evaluate {rr} result reference.")))
|
||||
}
|
||||
|
@ -472,7 +472,7 @@ impl EvalResult {
|
|||
}
|
||||
Ok(ids)
|
||||
} else {
|
||||
Err(trc::JmapCause::InvalidResultReference
|
||||
Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!("Failed to evaluate {rr} result reference.")))
|
||||
}
|
||||
|
@ -496,7 +496,7 @@ impl EvalResult {
|
|||
ids.push(MaybeReference::Value(blob_id.into()))
|
||||
}
|
||||
_ => {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!(
|
||||
"Failed to evaluate {rr} result reference."
|
||||
|
@ -506,7 +506,7 @@ impl EvalResult {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(trc::JmapCause::InvalidResultReference
|
||||
return Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!("Failed to evaluate {rr} result reference.")))
|
||||
}
|
||||
|
@ -514,7 +514,7 @@ impl EvalResult {
|
|||
}
|
||||
Ok(ids)
|
||||
} else {
|
||||
Err(trc::JmapCause::InvalidResultReference
|
||||
Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!("Failed to evaluate {rr} result reference.")))
|
||||
}
|
||||
|
@ -524,7 +524,7 @@ impl EvalResult {
|
|||
if let EvalResult::Properties(properties) = self {
|
||||
Ok(properties)
|
||||
} else {
|
||||
Err(trc::JmapCause::InvalidResultReference
|
||||
Err(trc::JmapEvent::InvalidResultReference
|
||||
.into_err()
|
||||
.details(format!("Failed to evaluate {rr} result reference.")))
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ hyper = { version = "1.0.1", features = ["server", "http1", "http2"] }
|
|||
hyper-util = { version = "0.1.1", features = ["tokio"] }
|
||||
http-body-util = "0.1.0"
|
||||
form_urlencoded = "1.1.0"
|
||||
tracing = "0.1"
|
||||
tokio = { version = "1.23", features = ["rt"] }
|
||||
aes-gcm = "0.10.1"
|
||||
aes-gcm-siv = "0.11.1"
|
||||
|
@ -58,6 +57,7 @@ lz4_flex = { version = "0.11", default-features = false }
|
|||
rev_lines = "0.3.0"
|
||||
x509-parser = "0.16.0"
|
||||
quick-xml = "0.35"
|
||||
tracing = "0.1"
|
||||
|
||||
[features]
|
||||
test_mode = []
|
||||
|
|
|
@ -81,7 +81,7 @@ impl JMAP {
|
|||
// Obtain parameters
|
||||
let emailaddress = parse_autodiscover_request(body.as_deref().unwrap_or_default())
|
||||
.map_err(|err| {
|
||||
trc::ResourceCause::BadParameters
|
||||
trc::ResourceEvent::BadParameters
|
||||
.into_err()
|
||||
.details("Failed to parse autodiscover request")
|
||||
.ctx(trc::Key::Reason, err)
|
||||
|
@ -159,7 +159,7 @@ impl JMAP {
|
|||
emailaddress: &'x str,
|
||||
) -> trc::Result<(String, String, &'x str)> {
|
||||
let (_, domain) = emailaddress.rsplit_once('@').ok_or_else(|| {
|
||||
trc::ResourceCause::BadParameters
|
||||
trc::ResourceEvent::BadParameters
|
||||
.into_err()
|
||||
.details("Missing domain in email address")
|
||||
})?;
|
||||
|
@ -172,8 +172,8 @@ impl JMAP {
|
|||
.get("lookup.default.hostname")
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
trc::Cause::Configuration
|
||||
.into_err()
|
||||
trc::EventType::Config(trc::ConfigEvent::BuildError)
|
||||
.caused_by(trc::location!())
|
||||
.details("Server name not configured")
|
||||
})?;
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ impl JMAP {
|
|||
} else if let Ok(type_state) = DataType::try_from(type_state) {
|
||||
types.insert(type_state);
|
||||
} else {
|
||||
return Err(trc::ResourceCause::BadParameters.into_err());
|
||||
return Err(trc::ResourceEvent::BadParameters.into_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,13 +58,13 @@ impl JMAP {
|
|||
close_after_state = true;
|
||||
}
|
||||
"no" => {}
|
||||
_ => return Err(trc::ResourceCause::BadParameters.into_err()),
|
||||
_ => return Err(trc::ResourceEvent::BadParameters.into_err()),
|
||||
},
|
||||
"ping" => match value.parse::<u32>() {
|
||||
Ok(value) => {
|
||||
ping = value;
|
||||
}
|
||||
Err(_) => return Err(trc::ResourceCause::BadParameters.into_err()),
|
||||
Err(_) => return Err(trc::ResourceEvent::BadParameters.into_err()),
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ pub struct HttpSessionData {
|
|||
pub remote_ip: IpAddr,
|
||||
pub remote_port: u16,
|
||||
pub is_tls: bool,
|
||||
pub session_id: u64,
|
||||
}
|
||||
|
||||
impl JMAP {
|
||||
|
@ -75,7 +76,7 @@ impl JMAP {
|
|||
},
|
||||
)
|
||||
.await
|
||||
.ok_or_else(|| trc::LimitCause::SizeRequest.into_err())
|
||||
.ok_or_else(|| trc::LimitEvent::SizeRequest.into_err())
|
||||
.and_then(|bytes| {
|
||||
//let c = println!("<- {}", String::from_utf8_lossy(&bytes));
|
||||
|
||||
|
@ -116,7 +117,7 @@ impl JMAP {
|
|||
blob,
|
||||
}
|
||||
.into_http_response()),
|
||||
None => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
None => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +151,7 @@ impl JMAP {
|
|||
)
|
||||
.await?
|
||||
.into_http_response()),
|
||||
None => Err(trc::LimitCause::SizeUpload.into_err()),
|
||||
None => Err(trc::LimitEvent::SizeUpload.into_err()),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +218,7 @@ impl JMAP {
|
|||
contents: proof.into_bytes(),
|
||||
}
|
||||
.into_http_response()),
|
||||
None => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
None => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +230,7 @@ impl JMAP {
|
|||
}
|
||||
.into_http_response());
|
||||
} else {
|
||||
return Err(trc::ResourceCause::NotFound.into_err());
|
||||
return Err(trc::ResourceEvent::NotFound.into_err());
|
||||
}
|
||||
}
|
||||
("mail-v1.xml", &Method::GET) => {
|
||||
|
@ -328,18 +329,17 @@ impl JMAP {
|
|||
return if !resource.is_empty() {
|
||||
Ok(resource.into_http_response())
|
||||
} else {
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
}
|
||||
}
|
||||
|
||||
impl JmapInstance {
|
||||
async fn handle_session<T: SessionStream>(self, session: SessionData<T>) {
|
||||
let span = session.span;
|
||||
let _in_flight = session.in_flight;
|
||||
let is_tls = session.stream.is_tls();
|
||||
|
||||
|
@ -349,15 +349,10 @@ impl JmapInstance {
|
|||
TokioIo::new(session.stream),
|
||||
service_fn(|req: hyper::Request<body::Incoming>| {
|
||||
let jmap_instance = self.clone();
|
||||
let span = span.clone();
|
||||
let instance = session.instance.clone();
|
||||
|
||||
async move {
|
||||
tracing::debug!(
|
||||
parent: &span,
|
||||
event = "request",
|
||||
uri = req.uri().to_string(),
|
||||
);
|
||||
tracing::debug!(event = "request", uri = req.uri().to_string(),);
|
||||
let jmap = JMAP::from(jmap_instance);
|
||||
|
||||
// Obtain remote IP
|
||||
|
@ -389,6 +384,7 @@ impl JmapInstance {
|
|||
remote_ip,
|
||||
remote_port: session.remote_port,
|
||||
is_tls,
|
||||
session_id: session.session_id,
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
@ -396,7 +392,7 @@ impl JmapInstance {
|
|||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
tracing::error!(
|
||||
parent: &span,
|
||||
|
||||
event = "error",
|
||||
context = "http",
|
||||
reason = %err,
|
||||
|
@ -422,7 +418,7 @@ impl JmapInstance {
|
|||
.await
|
||||
{
|
||||
tracing::debug!(
|
||||
parent: &span,
|
||||
|
||||
event = "error",
|
||||
context = "http",
|
||||
reason = %http_err,
|
||||
|
@ -469,7 +465,7 @@ impl ResolveVariable for HttpSessionData {
|
|||
|
||||
impl HttpSessionData {
|
||||
pub async fn resolve_url(&self, core: &Core) -> String {
|
||||
core.eval_if(&core.network.url, self)
|
||||
core.eval_if(&core.network.url, self, self.session_id)
|
||||
.await
|
||||
.unwrap_or_else(|| {
|
||||
format!(
|
||||
|
@ -517,28 +513,28 @@ impl<T: serde::Serialize> ToHttpResponse for JsonResponse<T> {
|
|||
impl ToHttpResponse for trc::Error {
|
||||
fn into_http_response(self) -> HttpResponse {
|
||||
match self.as_ref() {
|
||||
trc::Cause::Manage(cause) => {
|
||||
trc::EventType::Manage(cause) => {
|
||||
let details_or_reason = self
|
||||
.value(trc::Key::Details)
|
||||
.or_else(|| self.value(trc::Key::Reason))
|
||||
.and_then(|v| v.as_str());
|
||||
|
||||
match cause {
|
||||
trc::ManageCause::MissingParameter => ManagementApiError::FieldMissing {
|
||||
trc::ManageEvent::MissingParameter => ManagementApiError::FieldMissing {
|
||||
field: self.value_as_str(trc::Key::Key).unwrap_or_default(),
|
||||
},
|
||||
trc::ManageCause::AlreadyExists => ManagementApiError::FieldAlreadyExists {
|
||||
trc::ManageEvent::AlreadyExists => ManagementApiError::FieldAlreadyExists {
|
||||
field: self.value_as_str(trc::Key::Key).unwrap_or_default(),
|
||||
value: self.value_as_str(trc::Key::Value).unwrap_or_default(),
|
||||
},
|
||||
trc::ManageCause::NotFound => ManagementApiError::NotFound {
|
||||
trc::ManageEvent::NotFound => ManagementApiError::NotFound {
|
||||
item: self.value_as_str(trc::Key::Key).unwrap_or_default(),
|
||||
},
|
||||
trc::ManageCause::NotSupported => ManagementApiError::Unsupported {
|
||||
trc::ManageEvent::NotSupported => ManagementApiError::Unsupported {
|
||||
details: details_or_reason.unwrap_or("Requested action is unsupported"),
|
||||
},
|
||||
trc::ManageCause::AssertFailed => ManagementApiError::AssertFailed,
|
||||
trc::ManageCause::Error => ManagementApiError::Other {
|
||||
trc::ManageEvent::AssertFailed => ManagementApiError::AssertFailed,
|
||||
trc::ManageEvent::Error => ManagementApiError::Other {
|
||||
details: details_or_reason.unwrap_or("An error occurred."),
|
||||
},
|
||||
}
|
||||
|
@ -563,24 +559,24 @@ impl ToRequestError for trc::Error {
|
|||
let details = details_or_reason.unwrap_or_else(|| self.as_ref().message());
|
||||
|
||||
match self.as_ref() {
|
||||
trc::Cause::Jmap(cause) => match cause {
|
||||
trc::JmapCause::UnknownCapability => RequestError::unknown_capability(details),
|
||||
trc::JmapCause::NotJSON => RequestError::not_json(details),
|
||||
trc::JmapCause::NotRequest => RequestError::not_request(details),
|
||||
trc::EventType::Jmap(cause) => match cause {
|
||||
trc::JmapEvent::UnknownCapability => RequestError::unknown_capability(details),
|
||||
trc::JmapEvent::NotJSON => RequestError::not_json(details),
|
||||
trc::JmapEvent::NotRequest => RequestError::not_request(details),
|
||||
_ => RequestError::invalid_parameters(),
|
||||
},
|
||||
trc::Cause::Limit(cause) => match cause {
|
||||
trc::LimitCause::SizeRequest => RequestError::limit(RequestLimitError::SizeRequest),
|
||||
trc::LimitCause::SizeUpload => RequestError::limit(RequestLimitError::SizeUpload),
|
||||
trc::LimitCause::CallsIn => RequestError::limit(RequestLimitError::CallsIn),
|
||||
trc::LimitCause::ConcurrentRequest => {
|
||||
trc::EventType::Limit(cause) => match cause {
|
||||
trc::LimitEvent::SizeRequest => RequestError::limit(RequestLimitError::SizeRequest),
|
||||
trc::LimitEvent::SizeUpload => RequestError::limit(RequestLimitError::SizeUpload),
|
||||
trc::LimitEvent::CallsIn => RequestError::limit(RequestLimitError::CallsIn),
|
||||
trc::LimitEvent::ConcurrentRequest => {
|
||||
RequestError::limit(RequestLimitError::ConcurrentRequest)
|
||||
}
|
||||
trc::LimitCause::ConcurrentUpload => {
|
||||
trc::LimitEvent::ConcurrentUpload => {
|
||||
RequestError::limit(RequestLimitError::ConcurrentUpload)
|
||||
}
|
||||
trc::LimitCause::Quota => RequestError::over_quota(),
|
||||
trc::LimitCause::BlobQuota => RequestError::over_blob_quota(
|
||||
trc::LimitEvent::Quota => RequestError::over_quota(),
|
||||
trc::LimitEvent::BlobQuota => RequestError::over_blob_quota(
|
||||
self.value(trc::Key::Total)
|
||||
.and_then(|v| v.to_uint())
|
||||
.unwrap_or_default() as usize,
|
||||
|
@ -588,26 +584,26 @@ impl ToRequestError for trc::Error {
|
|||
.and_then(|v| v.to_uint())
|
||||
.unwrap_or_default() as usize,
|
||||
),
|
||||
trc::LimitCause::TooManyRequests => RequestError::too_many_requests(),
|
||||
trc::LimitEvent::TooManyRequests => RequestError::too_many_requests(),
|
||||
},
|
||||
trc::Cause::Auth(cause) => match cause {
|
||||
trc::AuthCause::Failed => RequestError::unauthorized(),
|
||||
trc::AuthCause::MissingTotp => {
|
||||
trc::EventType::Auth(cause) => match cause {
|
||||
trc::AuthEvent::Failed => RequestError::unauthorized(),
|
||||
trc::AuthEvent::MissingTotp => {
|
||||
RequestError::blank(403, "TOTP code required", cause.message())
|
||||
}
|
||||
trc::AuthCause::TooManyAttempts | trc::AuthCause::Banned => {
|
||||
trc::AuthEvent::TooManyAttempts | trc::AuthEvent::Banned => {
|
||||
RequestError::too_many_auth_attempts()
|
||||
}
|
||||
trc::AuthCause::Error => RequestError::unauthorized(),
|
||||
trc::AuthEvent::Error => RequestError::unauthorized(),
|
||||
},
|
||||
trc::Cause::Resource(cause) => match cause {
|
||||
trc::ResourceCause::NotFound => RequestError::not_found(),
|
||||
trc::ResourceCause::BadParameters => RequestError::blank(
|
||||
trc::EventType::Resource(cause) => match cause {
|
||||
trc::ResourceEvent::NotFound => RequestError::not_found(),
|
||||
trc::ResourceEvent::BadParameters => RequestError::blank(
|
||||
StatusCode::BAD_REQUEST.as_u16(),
|
||||
"Invalid parameters",
|
||||
details_or_reason.unwrap_or("One or multiple parameters could not be parsed."),
|
||||
),
|
||||
trc::ResourceCause::Error => RequestError::internal_server_error(),
|
||||
trc::ResourceEvent::Error => RequestError::internal_server_error(),
|
||||
},
|
||||
_ => RequestError::internal_server_error(),
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ impl JMAP {
|
|||
match *req.method() {
|
||||
Method::GET => self.handle_get_public_key(path).await,
|
||||
Method::POST => self.handle_create_signature(body).await,
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ impl JMAP {
|
|||
let signature_id = match path.get(1) {
|
||||
Some(signature_id) => decode_path_element(signature_id),
|
||||
None => {
|
||||
return Err(trc::ResourceCause::NotFound.into_err());
|
||||
return Err(trc::ResourceEvent::NotFound.into_err());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,7 @@ impl JMAP {
|
|||
) {
|
||||
(Ok(Some(pk)), Ok(Some(algorithm))) => (pk, algorithm),
|
||||
(Err(err), _) | (_, Err(err)) => return Err(err.caused_by(trc::location!())),
|
||||
_ => return Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => return Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
};
|
||||
|
||||
match obtain_dkim_public_key(algo, &pk) {
|
||||
|
@ -96,7 +96,9 @@ impl JMAP {
|
|||
match serde_json::from_slice::<DkimSignature>(body.as_deref().unwrap_or_default()) {
|
||||
Ok(request) => request,
|
||||
Err(err) => {
|
||||
return Err(trc::Cause::Resource(trc::ResourceCause::BadParameters).reason(err))
|
||||
return Err(
|
||||
trc::EventType::Resource(trc::ResourceEvent::BadParameters).reason(err)
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ impl JMAP {
|
|||
.into_http_response())
|
||||
}
|
||||
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ impl JMAP {
|
|||
) -> trc::Result<HttpResponse> {
|
||||
match path.get(1).copied().unwrap_or_default() {
|
||||
"undelete" => self.handle_undelete_api_request(req, path, body).await,
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ impl JMAP {
|
|||
.data
|
||||
.get_account_id(account_name)
|
||||
.await?
|
||||
.ok_or_else(|| trc::ResourceCause::NotFound.into_err())?;
|
||||
.ok_or_else(|| trc::ResourceEvent::NotFound.into_err())?;
|
||||
let mut deleted = self.core.list_deleted(account_id).await?;
|
||||
|
||||
let params = UrlParams::new(req.uri().query());
|
||||
|
@ -125,7 +125,7 @@ impl JMAP {
|
|||
.data
|
||||
.get_account_id(account_name)
|
||||
.await?
|
||||
.ok_or_else(|| trc::ResourceCause::NotFound.into_err())?;
|
||||
.ok_or_else(|| trc::ResourceEvent::NotFound.into_err())?;
|
||||
|
||||
let requests =
|
||||
serde_json::from_slice::<Vec<UndeleteRequest<String, String, String>>>(
|
||||
|
@ -162,7 +162,7 @@ impl JMAP {
|
|||
})
|
||||
.collect::<Option<Vec<_>>>()
|
||||
})
|
||||
.ok_or_else(|| trc::ResourceCause::BadParameters.into_err())?;
|
||||
.ok_or_else(|| trc::ResourceEvent::BadParameters.into_err())?;
|
||||
|
||||
let mut results = Vec::with_capacity(requests.len());
|
||||
let mut batch = BatchBuilder::new();
|
||||
|
@ -195,7 +195,11 @@ impl JMAP {
|
|||
}));
|
||||
}
|
||||
}
|
||||
Err(mut err) if err.matches(trc::Cause::Ingest) => {
|
||||
Err(mut err)
|
||||
if err.matches(trc::EventType::Store(
|
||||
trc::StoreEvent::IngestError,
|
||||
)) =>
|
||||
{
|
||||
results.push(UndeleteResponse::Error {
|
||||
reason: err
|
||||
.take_value(trc::Key::Reason)
|
||||
|
@ -237,7 +241,7 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,9 +49,13 @@ impl JMAP {
|
|||
|
||||
let (total, items) = rx
|
||||
.await
|
||||
.map_err(|err| trc::Cause::Thread.reason(err).caused_by(trc::location!()))?
|
||||
.map_err(|err| {
|
||||
trc::ManageCause::Error
|
||||
trc::EventType::Server(trc::ServerEvent::ThreadError)
|
||||
.reason(err)
|
||||
.caused_by(trc::location!())
|
||||
})?
|
||||
.map_err(|err| {
|
||||
trc::ManageEvent::Error
|
||||
.reason(err)
|
||||
.details("Failed to read log files")
|
||||
.caused_by(trc::location!())
|
||||
|
|
|
@ -73,7 +73,7 @@ impl JMAP {
|
|||
("auth", &Method::POST) => {
|
||||
self.handle_account_auth_post(req, access_token, body).await
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
},
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
|
@ -99,7 +99,7 @@ impl JMAP {
|
|||
}
|
||||
}
|
||||
// SPDX-SnippetEnd
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ impl JMAP {
|
|||
body.as_deref().unwrap_or_default(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
trc::Cause::Resource(trc::ResourceCause::BadParameters).from_json_error(err)
|
||||
trc::EventType::Resource(trc::ResourceEvent::BadParameters).from_json_error(err)
|
||||
})?;
|
||||
|
||||
Ok(JsonResponse::new(json!({
|
||||
|
@ -152,7 +152,7 @@ impl JMAP {
|
|||
.data
|
||||
.get_account_id(name.as_ref())
|
||||
.await?
|
||||
.ok_or_else(|| trc::ManageCause::NotFound.into_err())?;
|
||||
.ok_or_else(|| trc::ManageEvent::NotFound.into_err())?;
|
||||
|
||||
match *method {
|
||||
Method::GET => {
|
||||
|
@ -162,7 +162,7 @@ impl JMAP {
|
|||
.data
|
||||
.query(QueryBy::Id(account_id), true)
|
||||
.await?
|
||||
.ok_or_else(|| trc::ManageCause::NotFound.into_err())?;
|
||||
.ok_or_else(|| trc::ManageEvent::NotFound.into_err())?;
|
||||
let principal = self.core.storage.data.map_group_ids(principal).await?;
|
||||
|
||||
// Obtain quota usage
|
||||
|
@ -210,7 +210,7 @@ impl JMAP {
|
|||
body.as_deref().unwrap_or_default(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
trc::Cause::Resource(trc::ResourceCause::BadParameters)
|
||||
trc::EventType::Resource(trc::ResourceEvent::BadParameters)
|
||||
.from_json_error(err)
|
||||
})?;
|
||||
|
||||
|
@ -243,11 +243,11 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,7 @@ impl JMAP {
|
|||
.directory
|
||||
.query(QueryBy::Id(access_token.primary_id()), false)
|
||||
.await?
|
||||
.ok_or_else(|| trc::ManageCause::NotFound.into_err())?;
|
||||
.ok_or_else(|| trc::ManageEvent::NotFound.into_err())?;
|
||||
|
||||
for secret in principal.secrets {
|
||||
if secret.is_otp_auth() {
|
||||
|
@ -297,11 +297,11 @@ impl JMAP {
|
|||
let requests =
|
||||
serde_json::from_slice::<Vec<AccountAuthRequest>>(body.as_deref().unwrap_or_default())
|
||||
.map_err(|err| {
|
||||
trc::Cause::Resource(trc::ResourceCause::BadParameters).from_json_error(err)
|
||||
trc::EventType::Resource(trc::ResourceEvent::BadParameters).from_json_error(err)
|
||||
})?;
|
||||
|
||||
if requests.is_empty() {
|
||||
return Err(trc::Cause::Resource(trc::ResourceCause::BadParameters)
|
||||
return Err(trc::EventType::Resource(trc::ResourceEvent::BadParameters)
|
||||
.into_err()
|
||||
.details("Empty request"));
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
} else {
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
}
|
||||
}
|
||||
("messages", Some(queue_id), &Method::PATCH) => {
|
||||
|
@ -272,7 +272,7 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
} else {
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
}
|
||||
}
|
||||
("messages", Some(queue_id), &Method::DELETE) => {
|
||||
|
@ -352,7 +352,7 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
} else {
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
}
|
||||
}
|
||||
("reports", None, &Method::GET) => {
|
||||
|
@ -441,7 +441,7 @@ impl JMAP {
|
|||
let mut rua = Vec::new();
|
||||
if let Some(report) = self
|
||||
.smtp
|
||||
.generate_dmarc_aggregate_report(&event, &mut rua, None)
|
||||
.generate_dmarc_aggregate_report(&event, &mut rua, None, 0)
|
||||
.await?
|
||||
{
|
||||
result = Report::dmarc(event, report, rua).into();
|
||||
|
@ -451,7 +451,7 @@ impl JMAP {
|
|||
let mut rua = Vec::new();
|
||||
if let Some(report) = self
|
||||
.smtp
|
||||
.generate_tls_aggregate_report(&[event.clone()], &mut rua, None)
|
||||
.generate_tls_aggregate_report(&[event.clone()], &mut rua, None, 0)
|
||||
.await?
|
||||
{
|
||||
result = Report::tls(event, report, rua).into();
|
||||
|
@ -467,7 +467,7 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
} else {
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
}
|
||||
}
|
||||
("reports", Some(report_id), &Method::DELETE) => {
|
||||
|
@ -487,10 +487,10 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
} else {
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
}
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ impl JMAP {
|
|||
.send(Event::AcmeReload)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
trc::Cause::Thread
|
||||
trc::EventType::Server(trc::ServerEvent::ThreadError)
|
||||
.reason(err)
|
||||
.details("Failed to send ACME reload event to housekeeper")
|
||||
.caused_by(trc::location!())
|
||||
|
@ -76,7 +76,7 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ impl JMAP {
|
|||
"data": report.inner,
|
||||
}))
|
||||
.into_http_response()),
|
||||
None => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
None => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
},
|
||||
ReportClass::Dmarc { .. } => match self
|
||||
.core
|
||||
|
@ -184,7 +184,7 @@ impl JMAP {
|
|||
"data": report.inner,
|
||||
}))
|
||||
.into_http_response()),
|
||||
None => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
None => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
},
|
||||
ReportClass::Arf { .. } => match self
|
||||
.core
|
||||
|
@ -199,11 +199,11 @@ impl JMAP {
|
|||
"data": report.inner,
|
||||
}))
|
||||
.into_http_response()),
|
||||
None => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
None => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
}
|
||||
}
|
||||
(class @ ("dmarc" | "tls" | "arf"), Some(report_id), &Method::DELETE) => {
|
||||
|
@ -217,10 +217,10 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
} else {
|
||||
Err(trc::ResourceCause::NotFound.into_err())
|
||||
Err(trc::ResourceEvent::NotFound.into_err())
|
||||
}
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,7 +246,7 @@ impl JMAP {
|
|||
body.as_deref().unwrap_or_default(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
trc::Cause::Resource(trc::ResourceCause::BadParameters).from_json_error(err)
|
||||
trc::EventType::Resource(trc::ResourceEvent::BadParameters).from_json_error(err)
|
||||
})?;
|
||||
|
||||
for change in changes {
|
||||
|
@ -274,11 +274,11 @@ impl JMAP {
|
|||
.await?
|
||||
.is_empty()
|
||||
{
|
||||
return Err(trc::ManageCause::AssertFailed.into_err());
|
||||
return Err(trc::ManageEvent::AssertFailed.into_err());
|
||||
}
|
||||
} else if let Some((key, _)) = values.first() {
|
||||
if self.core.storage.config.get(key).await?.is_some() {
|
||||
return Err(trc::ManageCause::AssertFailed.into_err());
|
||||
return Err(trc::ManageEvent::AssertFailed.into_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ impl JMAP {
|
|||
}))
|
||||
.into_http_response())
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ impl JMAP {
|
|||
) {
|
||||
(Some(script), &Method::POST) => script,
|
||||
_ => {
|
||||
return Err(trc::ResourceCause::NotFound.into_err());
|
||||
return Err(trc::ResourceEvent::NotFound.into_err());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -94,11 +94,7 @@ impl JMAP {
|
|||
}
|
||||
|
||||
// Run script
|
||||
let result = match self
|
||||
.smtp
|
||||
.run_script(script, params, tracing::debug_span!("sieve_manual_run"))
|
||||
.await
|
||||
{
|
||||
let result = match self.smtp.run_script(script, params, 0).await {
|
||||
ScriptResult::Accept { modifications } => Response::Accept { modifications },
|
||||
ScriptResult::Replace {
|
||||
message,
|
||||
|
|
|
@ -35,7 +35,7 @@ impl JMAP {
|
|||
let blob_hash = URL_SAFE_NO_PAD
|
||||
.decode(decode_path_element(blob_hash).as_bytes())
|
||||
.map_err(|err| {
|
||||
trc::Cause::Resource(trc::ResourceCause::BadParameters)
|
||||
trc::EventType::Resource(trc::ResourceEvent::BadParameters)
|
||||
.from_base64_error(err)
|
||||
})?;
|
||||
let contents = self
|
||||
|
@ -44,7 +44,7 @@ impl JMAP {
|
|||
.blob
|
||||
.get_blob(&blob_hash, 0..usize::MAX)
|
||||
.await?
|
||||
.ok_or_else(|| trc::ManageCause::NotFound.into_err())?;
|
||||
.ok_or_else(|| trc::ManageEvent::NotFound.into_err())?;
|
||||
let params = UrlParams::new(req.uri().query());
|
||||
let offset = params.parse("offset").unwrap_or(0);
|
||||
let limit = params.parse("limit").unwrap_or(usize::MAX);
|
||||
|
@ -75,7 +75,7 @@ impl JMAP {
|
|||
if let Some(store) = self.core.storage.stores.get(id) {
|
||||
store.clone()
|
||||
} else {
|
||||
return Err(trc::ResourceCause::NotFound.into_err());
|
||||
return Err(trc::ResourceEvent::NotFound.into_err());
|
||||
}
|
||||
} else {
|
||||
self.core.storage.data.clone()
|
||||
|
@ -89,7 +89,7 @@ impl JMAP {
|
|||
if let Some(store) = self.core.storage.lookups.get(id) {
|
||||
store.clone()
|
||||
} else {
|
||||
return Err(trc::ResourceCause::NotFound.into_err());
|
||||
return Err(trc::ResourceEvent::NotFound.into_err());
|
||||
}
|
||||
} else {
|
||||
self.core.storage.lookup.clone()
|
||||
|
@ -105,7 +105,7 @@ impl JMAP {
|
|||
.data
|
||||
.get_account_id(decode_path_element(id).as_ref())
|
||||
.await?
|
||||
.ok_or_else(|| trc::ManageCause::NotFound.into_err())?
|
||||
.ok_or_else(|| trc::ManageEvent::NotFound.into_err())?
|
||||
.into()
|
||||
} else {
|
||||
None
|
||||
|
@ -114,13 +114,13 @@ impl JMAP {
|
|||
self.housekeeper_request(Event::Purge(PurgeType::Account(account_id)))
|
||||
.await
|
||||
}
|
||||
_ => Err(trc::ResourceCause::NotFound.into_err()),
|
||||
_ => Err(trc::ResourceEvent::NotFound.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn housekeeper_request(&self, event: Event) -> trc::Result<HttpResponse> {
|
||||
self.inner.housekeeper_tx.send(event).await.map_err(|err| {
|
||||
trc::Cause::Thread
|
||||
trc::EventType::Server(trc::ServerEvent::ThreadError)
|
||||
.reason(err)
|
||||
.details("Failed to send housekeeper event")
|
||||
})?;
|
||||
|
|
|
@ -163,7 +163,7 @@ impl JMAP {
|
|||
if self.core.jmap.principal_allow_lookups || access_token.is_super_user() {
|
||||
self.principal_get(req).await?.into()
|
||||
} else {
|
||||
return Err(trc::JmapCause::Forbidden
|
||||
return Err(trc::JmapEvent::Forbidden
|
||||
.into_err()
|
||||
.details("Principal lookups are disabled".to_string()));
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ impl JMAP {
|
|||
if self.core.jmap.principal_allow_lookups || access_token.is_super_user() {
|
||||
self.principal_query(req).await?.into()
|
||||
} else {
|
||||
return Err(trc::JmapCause::Forbidden
|
||||
return Err(trc::JmapEvent::Forbidden
|
||||
.into_err()
|
||||
.details("Principal lookups are disabled".to_string()));
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ impl JMAP {
|
|||
let acl = Bitmap::<Acl>::from(acl_item.permissions);
|
||||
let collection = Collection::from(acl_item.to_collection);
|
||||
if !collection.is_valid() {
|
||||
return Err(trc::StoreCause::DataCorruption
|
||||
return Err(trc::StoreEvent::DataCorruption
|
||||
.ctx(trc::Key::Reason, "Corrupted collection found in ACL key.")
|
||||
.details(format!("{acl_item:?}"))
|
||||
.account_id(grant_account_id)
|
||||
|
|
|
@ -48,7 +48,7 @@ impl JMAP {
|
|||
self.authenticate_plain(&account, &secret, remote_ip, ServerProtocol::Http)
|
||||
.await?
|
||||
} else {
|
||||
return Err(trc::AuthCause::Error
|
||||
return Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details("Failed to decode Basic auth request.")
|
||||
.id(token)
|
||||
|
@ -65,7 +65,7 @@ impl JMAP {
|
|||
} else {
|
||||
// Enforce anonymous rate limit
|
||||
self.is_anonymous_allowed(&remote_ip).await?;
|
||||
return Err(trc::AuthCause::Error
|
||||
return Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.reason("Unsupported authentication mechanism.")
|
||||
.details(token)
|
||||
|
@ -87,7 +87,7 @@ impl JMAP {
|
|||
// Enforce anonymous rate limit
|
||||
self.is_anonymous_allowed(&remote_ip).await?;
|
||||
|
||||
Err(trc::AuthCause::Error
|
||||
Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details("Missing Authorization header.")
|
||||
.caused_by(trc::location!()))
|
||||
|
@ -147,7 +147,7 @@ impl JMAP {
|
|||
{
|
||||
Ok(principal) => Ok(AccessToken::new(principal)),
|
||||
Err(err) => {
|
||||
if !err.matches(trc::Cause::Auth(trc::AuthCause::MissingTotp)) {
|
||||
if !err.matches(trc::EventType::Auth(trc::AuthEvent::MissingTotp)) {
|
||||
let _ = self.is_auth_allowed_hard(&remote_ip).await;
|
||||
}
|
||||
Err(err)
|
||||
|
@ -164,7 +164,7 @@ impl JMAP {
|
|||
.await
|
||||
{
|
||||
Ok(Some(principal)) => self.update_access_token(AccessToken::new(principal)).await,
|
||||
Ok(None) => Err(trc::AuthCause::Error
|
||||
Ok(None) => Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details("Account not found.")
|
||||
.caused_by(trc::location!())),
|
||||
|
|
|
@ -115,7 +115,7 @@ impl AccessToken {
|
|||
if self.has_access(to_account_id.document_id(), to_collection) {
|
||||
Ok(self)
|
||||
} else {
|
||||
Err(trc::JmapCause::Forbidden.into_err().details(format!(
|
||||
Err(trc::JmapEvent::Forbidden.into_err().details(format!(
|
||||
"You do not have access to account {}",
|
||||
to_account_id
|
||||
)))
|
||||
|
@ -126,7 +126,7 @@ impl AccessToken {
|
|||
if self.is_member(account_id.document_id()) {
|
||||
Ok(self)
|
||||
} else {
|
||||
Err(trc::JmapCause::Forbidden
|
||||
Err(trc::JmapEvent::Forbidden
|
||||
.into_err()
|
||||
.details(format!("You are not an owner of account {}", account_id)))
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ impl JMAP {
|
|||
let request =
|
||||
serde_json::from_slice::<OAuthCodeRequest>(body.as_deref().unwrap_or_default())
|
||||
.map_err(|err| {
|
||||
trc::Cause::Resource(trc::ResourceCause::BadParameters).from_json_error(err)
|
||||
trc::EventType::Resource(trc::ResourceEvent::BadParameters).from_json_error(err)
|
||||
})?;
|
||||
|
||||
let response = match request {
|
||||
|
@ -44,14 +44,14 @@ impl JMAP {
|
|||
} => {
|
||||
// Validate clientId
|
||||
if client_id.len() > CLIENT_ID_MAX_LEN {
|
||||
return Err(trc::ManageCause::Error
|
||||
return Err(trc::ManageEvent::Error
|
||||
.into_err()
|
||||
.details("Client ID is invalid."));
|
||||
} else if redirect_uri
|
||||
.as_ref()
|
||||
.map_or(false, |uri| !uri.starts_with("https://"))
|
||||
{
|
||||
return Err(trc::ManageCause::Error
|
||||
return Err(trc::ManageEvent::Error
|
||||
.into_err()
|
||||
.details("Redirect URI must be HTTPS."));
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ impl JMAP {
|
|||
.remove("client_id")
|
||||
.filter(|client_id| client_id.len() < CLIENT_ID_MAX_LEN)
|
||||
.ok_or_else(|| {
|
||||
trc::ResourceCause::BadParameters
|
||||
trc::ResourceEvent::BadParameters
|
||||
.into_err()
|
||||
.details("Client ID is missing.")
|
||||
})?;
|
||||
|
|
|
@ -226,7 +226,7 @@ impl FormData {
|
|||
}
|
||||
Ok(FormData { fields })
|
||||
}
|
||||
_ => Err(trc::ResourceCause::BadParameters
|
||||
_ => Err(trc::ResourceEvent::BadParameters
|
||||
.into_err()
|
||||
.details("Invalid post request")),
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ impl JMAP {
|
|||
.await
|
||||
.map(TokenResponse::Granted)
|
||||
.map_err(|err| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details(err)
|
||||
.caused_by(trc::location!())
|
||||
|
@ -114,7 +114,7 @@ impl JMAP {
|
|||
.await
|
||||
.map(TokenResponse::Granted)
|
||||
.map_err(|err| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details(err)
|
||||
.caused_by(trc::location!())
|
||||
|
@ -145,7 +145,7 @@ impl JMAP {
|
|||
.await
|
||||
.map(TokenResponse::Granted)
|
||||
.map_err(|err| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.details(err)
|
||||
.caused_by(trc::location!())
|
||||
|
@ -282,7 +282,7 @@ impl JMAP {
|
|||
) -> trc::Result<(u32, String, u64)> {
|
||||
// Base64 decode token
|
||||
let token = base64_decode(token_.as_bytes()).ok_or_else(|| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.ctx(trc::Key::Reason, "Failed to decode token")
|
||||
.caused_by(trc::location!())
|
||||
|
@ -300,7 +300,7 @@ impl JMAP {
|
|||
.into()
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.ctx(trc::Key::Reason, "Failed to decode token")
|
||||
.caused_by(trc::location!())
|
||||
|
@ -314,7 +314,7 @@ impl JMAP {
|
|||
.unwrap_or(0)
|
||||
.saturating_sub(946684800); // Jan 1, 2000
|
||||
if expiry <= now {
|
||||
return Err(trc::AuthCause::Error
|
||||
return Err(trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.ctx(trc::Key::Reason, "Token expired"));
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ impl JMAP {
|
|||
let password_hash = self
|
||||
.password_hash(account_id)
|
||||
.await
|
||||
.map_err(|err| trc::AuthCause::Error.into_err().ctx(trc::Key::Details, err))?;
|
||||
.map_err(|err| trc::AuthEvent::Error.into_err().ctx(trc::Key::Details, err))?;
|
||||
|
||||
// Build context
|
||||
let key = self.core.jmap.oauth_key.clone();
|
||||
|
@ -352,7 +352,7 @@ impl JMAP {
|
|||
&nonce,
|
||||
)
|
||||
.map_err(|err| {
|
||||
trc::AuthCause::Error
|
||||
trc::AuthEvent::Error
|
||||
.into_err()
|
||||
.ctx(trc::Key::Details, "Failed to decode token")
|
||||
.caused_by(trc::location!())
|
||||
|
|
|
@ -64,12 +64,12 @@ impl JMAP {
|
|||
} else if access_token.is_super_user() {
|
||||
Ok(InFlight::default())
|
||||
} else {
|
||||
Err(trc::LimitCause::ConcurrentRequest.into_err())
|
||||
Err(trc::LimitEvent::ConcurrentRequest.into_err())
|
||||
}
|
||||
} else if access_token.is_super_user() {
|
||||
Ok(InFlight::default())
|
||||
} else {
|
||||
Err(trc::LimitCause::TooManyRequests.into_err())
|
||||
Err(trc::LimitEvent::TooManyRequests.into_err())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ impl JMAP {
|
|||
.caused_by(trc::location!())?
|
||||
.is_some()
|
||||
{
|
||||
return Err(trc::LimitCause::TooManyRequests.into_err());
|
||||
return Err(trc::LimitEvent::TooManyRequests.into_err());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -100,7 +100,7 @@ impl JMAP {
|
|||
} else if access_token.is_super_user() {
|
||||
Ok(InFlight::default())
|
||||
} else {
|
||||
Err(trc::LimitCause::ConcurrentUpload.into_err())
|
||||
Err(trc::LimitEvent::ConcurrentUpload.into_err())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ impl JMAP {
|
|||
.caused_by(trc::location!())?
|
||||
.is_some()
|
||||
{
|
||||
return Err(trc::AuthCause::TooManyAttempts.into_err());
|
||||
return Err(trc::AuthEvent::TooManyAttempts.into_err());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -132,7 +132,7 @@ impl JMAP {
|
|||
.caused_by(trc::location!())?
|
||||
.is_some()
|
||||
{
|
||||
return Err(trc::AuthCause::TooManyAttempts.into_err());
|
||||
return Err(trc::AuthEvent::TooManyAttempts.into_err());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -172,7 +172,7 @@ impl JMAP {
|
|||
|
||||
Ok(value)
|
||||
}
|
||||
MaybeUnparsable::ParseError(_) => Err(trc::JmapCause::UnknownDataType.into_err()),
|
||||
MaybeUnparsable::ParseError(_) => Err(trc::JmapEvent::UnknownDataType.into_err()),
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let req_account_id = request.account_id.document_id();
|
||||
|
|
|
@ -43,7 +43,7 @@ impl JMAP {
|
|||
let account_id = request.account_id.document_id();
|
||||
|
||||
if request.create.len() > self.core.jmap.set_max_objects {
|
||||
return Err(trc::JmapCause::RequestTooLarge.into_err());
|
||||
return Err(trc::JmapEvent::RequestTooLarge.into_err());
|
||||
}
|
||||
|
||||
'outer: for (create_id, upload_object) in request.create {
|
||||
|
@ -211,7 +211,7 @@ impl JMAP {
|
|||
&& used.count + 1 > self.core.jmap.upload_tmp_quota_amount))
|
||||
&& !access_token.is_super_user()
|
||||
{
|
||||
let err = Err(trc::LimitCause::BlobQuota
|
||||
let err = Err(trc::LimitEvent::BlobQuota
|
||||
.into_err()
|
||||
.ctx(trc::Key::Size, self.core.jmap.upload_tmp_quota_size)
|
||||
.ctx(trc::Key::Total, self.core.jmap.upload_tmp_quota_amount));
|
||||
|
|
|
@ -48,7 +48,7 @@ impl JMAP {
|
|||
RequestArguments::Quota => {
|
||||
access_token.assert_is_member(request.account_id)?;
|
||||
|
||||
return Err(trc::JmapCause::CannotCalculateChanges.into_err());
|
||||
return Err(trc::JmapEvent::CannotCalculateChanges.into_err());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ impl JMAP {
|
|||
}
|
||||
query::RequestArguments::Quota => changes::RequestArguments::Quota,
|
||||
_ => {
|
||||
return Err(trc::JmapCause::UnknownMethod
|
||||
return Err(trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details("Unknown method"))
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ impl JMAP {
|
|||
let old_state: State = self.get_state(account_id, collection).await?;
|
||||
if let Some(if_in_state) = if_in_state {
|
||||
if &old_state != if_in_state {
|
||||
return Err(trc::JmapCause::StateMismatch.into_err());
|
||||
return Err(trc::JmapEvent::StateMismatch.into_err());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ impl JMAP {
|
|||
|
||||
pub fn generate_snowflake_id(&self) -> trc::Result<u64> {
|
||||
self.inner.snowflake_id.generate().ok_or_else(|| {
|
||||
trc::StoreCause::Unexpected
|
||||
trc::StoreEvent::UnexpectedError
|
||||
.into_err()
|
||||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Reason, "Failed to generate snowflake id.")
|
||||
|
@ -58,7 +58,7 @@ impl JMAP {
|
|||
|
||||
pub async fn delete_changes(&self, account_id: u32, before: Duration) -> trc::Result<()> {
|
||||
let reference_cid = self.inner.snowflake_id.past_id(before).ok_or_else(|| {
|
||||
trc::StoreCause::Unexpected
|
||||
trc::StoreEvent::UnexpectedError
|
||||
.caused_by(trc::location!())
|
||||
.ctx(trc::Key::Reason, "Failed to generate reference change id.")
|
||||
})?;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue