mirror of
https://github.com/chatmail/core.git
synced 2026-05-15 12:56:30 +03:00
refactor: improve error handling in securejoin code
Result::Err is reserved for local errors, such as database failures. Not found peerstate in the database is a protocol failure, so just return Ok(false) in mark_peer_as_verified(). This allows to handle more errors with `?`.
This commit is contained in:
@@ -515,25 +515,23 @@ async fn add_parts(
|
|||||||
|
|
||||||
// handshake may mark contacts as verified and must be processed before chats are created
|
// handshake may mark contacts as verified and must be processed before chats are created
|
||||||
if mime_parser.get_header(HeaderDef::SecureJoin).is_some() {
|
if mime_parser.get_header(HeaderDef::SecureJoin).is_some() {
|
||||||
match handle_securejoin_handshake(context, mime_parser, from_id).await {
|
match handle_securejoin_handshake(context, mime_parser, from_id)
|
||||||
Ok(securejoin::HandshakeMessage::Done) => {
|
.await
|
||||||
|
.context("error in Secure-Join message handling")?
|
||||||
|
{
|
||||||
|
securejoin::HandshakeMessage::Done => {
|
||||||
chat_id = Some(DC_CHAT_ID_TRASH);
|
chat_id = Some(DC_CHAT_ID_TRASH);
|
||||||
needs_delete_job = true;
|
needs_delete_job = true;
|
||||||
securejoin_seen = true;
|
securejoin_seen = true;
|
||||||
}
|
}
|
||||||
Ok(securejoin::HandshakeMessage::Ignore) => {
|
securejoin::HandshakeMessage::Ignore => {
|
||||||
chat_id = Some(DC_CHAT_ID_TRASH);
|
chat_id = Some(DC_CHAT_ID_TRASH);
|
||||||
securejoin_seen = true;
|
securejoin_seen = true;
|
||||||
}
|
}
|
||||||
Ok(securejoin::HandshakeMessage::Propagate) => {
|
securejoin::HandshakeMessage::Propagate => {
|
||||||
// process messages as "member added" normally
|
// process messages as "member added" normally
|
||||||
securejoin_seen = false;
|
securejoin_seen = false;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
|
||||||
warn!(context, "Error in Secure-Join message handling: {err:#}.");
|
|
||||||
chat_id = Some(DC_CHAT_ID_TRASH);
|
|
||||||
securejoin_seen = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Peerstate could be updated by handling the Securejoin handshake.
|
// Peerstate could be updated by handling the Securejoin handshake.
|
||||||
let contact = Contact::get_by_id(context, from_id).await?;
|
let contact = Contact::get_by_id(context, from_id).await?;
|
||||||
@@ -809,19 +807,17 @@ async fn add_parts(
|
|||||||
|
|
||||||
// handshake may mark contacts as verified and must be processed before chats are created
|
// handshake may mark contacts as verified and must be processed before chats are created
|
||||||
if mime_parser.get_header(HeaderDef::SecureJoin).is_some() {
|
if mime_parser.get_header(HeaderDef::SecureJoin).is_some() {
|
||||||
match observe_securejoin_on_other_device(context, mime_parser, to_id).await {
|
match observe_securejoin_on_other_device(context, mime_parser, to_id)
|
||||||
Ok(securejoin::HandshakeMessage::Done)
|
.await
|
||||||
| Ok(securejoin::HandshakeMessage::Ignore) => {
|
.context("error in Secure-Join watching")?
|
||||||
|
{
|
||||||
|
securejoin::HandshakeMessage::Done | securejoin::HandshakeMessage::Ignore => {
|
||||||
chat_id = Some(DC_CHAT_ID_TRASH);
|
chat_id = Some(DC_CHAT_ID_TRASH);
|
||||||
}
|
}
|
||||||
Ok(securejoin::HandshakeMessage::Propagate) => {
|
securejoin::HandshakeMessage::Propagate => {
|
||||||
// process messages as "member added" normally
|
// process messages as "member added" normally
|
||||||
chat_id = None;
|
chat_id = None;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
|
||||||
warn!(context, "Error in Secure-Join watching: {err:#}.");
|
|
||||||
chat_id = Some(DC_CHAT_ID_TRASH);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if mime_parser.sync_items.is_some() && self_sent {
|
} else if mime_parser.sync_items.is_some() && self_sent {
|
||||||
chat_id = Some(DC_CHAT_ID_TRASH);
|
chat_id = Some(DC_CHAT_ID_TRASH);
|
||||||
|
|||||||
@@ -415,10 +415,9 @@ pub(crate) async fn handle_securejoin_handshake(
|
|||||||
.await?
|
.await?
|
||||||
.get_addr()
|
.get_addr()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
if mark_peer_as_verified(context, fingerprint.clone(), contact_addr)
|
let fingerprint_found =
|
||||||
.await
|
mark_peer_as_verified(context, fingerprint.clone(), contact_addr).await?;
|
||||||
.is_err()
|
if !fingerprint_found {
|
||||||
{
|
|
||||||
could_not_establish_secure_connection(
|
could_not_establish_secure_connection(
|
||||||
context,
|
context,
|
||||||
contact_id,
|
contact_id,
|
||||||
@@ -446,12 +445,8 @@ pub(crate) async fn handle_securejoin_handshake(
|
|||||||
match chat::get_chat_id_by_grpid(context, field_grpid).await? {
|
match chat::get_chat_id_by_grpid(context, field_grpid).await? {
|
||||||
Some((group_chat_id, _, _)) => {
|
Some((group_chat_id, _, _)) => {
|
||||||
secure_connection_established(context, contact_id, group_chat_id).await?;
|
secure_connection_established(context, contact_id, group_chat_id).await?;
|
||||||
if let Err(err) =
|
chat::add_contact_to_chat_ex(context, group_chat_id, contact_id, true)
|
||||||
chat::add_contact_to_chat_ex(context, group_chat_id, contact_id, true)
|
.await?;
|
||||||
.await
|
|
||||||
{
|
|
||||||
error!(context, "failed to add contact: {}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None => bail!("Chat {} not found", &field_grpid),
|
None => bail!("Chat {} not found", &field_grpid),
|
||||||
}
|
}
|
||||||
@@ -613,18 +608,7 @@ pub(crate) async fn observe_securejoin_on_other_device(
|
|||||||
return Ok(HandshakeMessage::Ignore);
|
return Ok(HandshakeMessage::Ignore);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(err) =
|
peerstate.set_verified(PeerstateKeyType::GossipKey, fingerprint, addr)?;
|
||||||
peerstate.set_verified(PeerstateKeyType::GossipKey, fingerprint, addr)
|
|
||||||
{
|
|
||||||
could_not_establish_secure_connection(
|
|
||||||
context,
|
|
||||||
contact_id,
|
|
||||||
info_chat_id(context, contact_id).await?,
|
|
||||||
&format!("Could not mark peer as verified at step {step}: {err}"),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
return Ok(HandshakeMessage::Ignore);
|
|
||||||
}
|
|
||||||
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
||||||
peerstate.save_to_db(&context.sql).await.unwrap_or_default();
|
peerstate.save_to_db(&context.sql).await.unwrap_or_default();
|
||||||
} else if let Some(fingerprint) =
|
} else if let Some(fingerprint) =
|
||||||
@@ -633,7 +617,7 @@ pub(crate) async fn observe_securejoin_on_other_device(
|
|||||||
// FIXME: Old versions of DC send this header instead of gossips. Remove this
|
// FIXME: Old versions of DC send this header instead of gossips. Remove this
|
||||||
// eventually.
|
// eventually.
|
||||||
let fingerprint = fingerprint.parse()?;
|
let fingerprint = fingerprint.parse()?;
|
||||||
if mark_peer_as_verified(
|
let fingerprint_found = mark_peer_as_verified(
|
||||||
context,
|
context,
|
||||||
fingerprint,
|
fingerprint,
|
||||||
Contact::get_by_id(context, contact_id)
|
Contact::get_by_id(context, contact_id)
|
||||||
@@ -641,9 +625,8 @@ pub(crate) async fn observe_securejoin_on_other_device(
|
|||||||
.get_addr()
|
.get_addr()
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
.is_err()
|
if !fingerprint_found {
|
||||||
{
|
|
||||||
could_not_establish_secure_connection(
|
could_not_establish_secure_connection(
|
||||||
context,
|
context,
|
||||||
contact_id,
|
contact_id,
|
||||||
@@ -733,23 +716,21 @@ async fn could_not_establish_secure_connection(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tries to mark peer with provided key fingerprint as verified.
|
||||||
|
///
|
||||||
|
/// Returns true if such key was found, false otherwise.
|
||||||
async fn mark_peer_as_verified(
|
async fn mark_peer_as_verified(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
fingerprint: Fingerprint,
|
fingerprint: Fingerprint,
|
||||||
verifier: String,
|
verifier: String,
|
||||||
) -> Result<()> {
|
) -> Result<bool> {
|
||||||
if let Some(ref mut peerstate) = Peerstate::from_fingerprint(context, &fingerprint).await? {
|
let Some(ref mut peerstate) = Peerstate::from_fingerprint(context, &fingerprint).await? else {
|
||||||
if let Err(err) = peerstate.set_verified(PeerstateKeyType::PublicKey, fingerprint, verifier)
|
return Ok(false);
|
||||||
{
|
};
|
||||||
error!(context, "Could not mark peer as verified: {}", err);
|
peerstate.set_verified(PeerstateKeyType::PublicKey, fingerprint, verifier)?;
|
||||||
return Err(err);
|
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
||||||
}
|
peerstate.save_to_db(&context.sql).await.unwrap_or_default();
|
||||||
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
Ok(true)
|
||||||
peerstate.save_to_db(&context.sql).await.unwrap_or_default();
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
bail!("no peerstate in db for fingerprint {}", fingerprint.hex());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ******************************************************************************
|
/* ******************************************************************************
|
||||||
|
|||||||
Reference in New Issue
Block a user