mirror of
https://github.com/chatmail/core.git
synced 2026-04-27 18:36:30 +03:00
feat: verify contacts via Autocrypt-Gossip
This mechanism replaces `Chat-Verified` header. New parameter `_verified=1` in `Autocrypt-Gossip` header marks that the sender has the gossiped key verified. Using `_verified=1` instead of `_verified` because it is less likely to cause troubles with existing Autocrypt header parsers. This is also how https://www.rfc-editor.org/rfc/rfc2045 defines parameter syntax.
This commit is contained in:
@@ -1081,6 +1081,17 @@ impl MimeFactory {
|
||||
.is_none_or(|ts| now >= ts + gossip_period || now < ts)
|
||||
};
|
||||
|
||||
let verifier_id: Option<u32> = context
|
||||
.sql
|
||||
.query_get_value(
|
||||
"SELECT verifier FROM contacts WHERE fingerprint=?",
|
||||
(&fingerprint,),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let is_verified =
|
||||
verifier_id.is_some_and(|verifier_id| verifier_id != 0);
|
||||
|
||||
if !should_do_gossip {
|
||||
continue;
|
||||
}
|
||||
@@ -1091,7 +1102,7 @@ impl MimeFactory {
|
||||
// Autocrypt 1.1.0 specification says that
|
||||
// `prefer-encrypt` attribute SHOULD NOT be included.
|
||||
prefer_encrypt: EncryptPreference::NoPreference,
|
||||
verified: false,
|
||||
verified: is_verified,
|
||||
}
|
||||
.to_string();
|
||||
|
||||
|
||||
@@ -742,7 +742,7 @@ pub(crate) async fn receive_imf_inner(
|
||||
let verified_encryption = has_verified_encryption(context, &mime_parser, from_id).await?;
|
||||
|
||||
if verified_encryption == VerifiedEncryption::Verified {
|
||||
mark_recipients_as_verified(context, from_id, &to_ids, &mime_parser).await?;
|
||||
mark_recipients_as_verified(context, from_id, &mime_parser).await?;
|
||||
}
|
||||
|
||||
let received_msg = if let Some(received_msg) = received_msg {
|
||||
@@ -3678,7 +3678,6 @@ async fn has_verified_encryption(
|
||||
async fn mark_recipients_as_verified(
|
||||
context: &Context,
|
||||
from_id: ContactId,
|
||||
to_ids: &[Option<ContactId>],
|
||||
mimeparser: &MimeMessage,
|
||||
) -> Result<()> {
|
||||
let verifier_id = Some(from_id).filter(|&id| id != ContactId::SELF);
|
||||
@@ -3700,18 +3699,6 @@ async fn mark_recipients_as_verified(
|
||||
ChatId::set_protection_for_contact(context, to_id, mimeparser.timestamp_sent).await?;
|
||||
}
|
||||
|
||||
if mimeparser.get_header(HeaderDef::ChatVerified).is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
for to_id in to_ids.iter().filter_map(|&x| x) {
|
||||
if to_id == ContactId::SELF || to_id == from_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
mark_contact_id_as_verified(context, to_id, verifier_id).await?;
|
||||
ChatId::set_protection_for_contact(context, to_id, mimeparser.timestamp_sent).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -859,6 +859,44 @@ async fn test_no_reverification() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tests that if our second device observes
|
||||
/// us gossiping a verification,
|
||||
/// it is not treated as direct verification.
|
||||
///
|
||||
/// Direct verifications should only happen
|
||||
/// as a result of SecureJoin.
|
||||
/// If we see our second device gossiping
|
||||
/// a verification of some contact,
|
||||
/// it may be indirect verification,
|
||||
/// so we should mark the contact as verified,
|
||||
/// but with unknown verifier.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_no_direct_verification_via_bcc() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let alice2 = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
|
||||
mark_as_verified(alice, bob).await;
|
||||
|
||||
let alice_chat_id = alice.create_chat_id(bob).await;
|
||||
let alice_sent_msg = alice.send_text(alice_chat_id, "Hello!").await;
|
||||
alice2.recv_msg(&alice_sent_msg).await;
|
||||
|
||||
// Alice 2 observes Alice 1 gossiping verification for Bob.
|
||||
// Alice 2 does not know if Alice 1 has verified Bob directly though.
|
||||
let alice2_bob_contact = alice2.add_or_lookup_contact(bob).await;
|
||||
assert_eq!(alice2_bob_contact.is_verified(alice2).await?, true);
|
||||
|
||||
// There is some verifier, but it is unknown to Alice's second device.
|
||||
assert_eq!(
|
||||
alice2_bob_contact.get_verifier_id(alice2).await?,
|
||||
Some(None)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ============== Helper Functions ==============
|
||||
|
||||
async fn assert_verified(this: &TestContext, other: &TestContext, protected: ProtectionStatus) {
|
||||
|
||||
Reference in New Issue
Block a user