deltachat/
peerstate.rs

1//! # [Autocrypt Peer State](https://autocrypt.org/level1.html#peer-state-management) module.
2
3use std::mem;
4
5use anyhow::{Context as _, Error, Result};
6use deltachat_contact_tools::{addr_cmp, ContactAddress};
7use num_traits::FromPrimitive;
8
9use crate::aheader::{Aheader, EncryptPreference};
10use crate::chat::{self, Chat};
11use crate::chatlist::Chatlist;
12use crate::config::Config;
13use crate::constants::Chattype;
14use crate::contact::{Contact, Origin};
15use crate::context::Context;
16use crate::events::EventType;
17use crate::key::{DcKey, Fingerprint, SignedPublicKey};
18use crate::log::{info, warn};
19use crate::message::Message;
20use crate::mimeparser::SystemMessage;
21use crate::sql::Sql;
22use crate::{chatlist_events, stock_str};
23
24/// Type of the public key stored inside the peerstate.
25#[derive(Debug)]
26pub enum PeerstateKeyType {
27    /// Public key sent in the `Autocrypt-Gossip` header.
28    GossipKey,
29
30    /// Public key sent in the `Autocrypt` header.
31    PublicKey,
32}
33
34/// Peerstate represents the state of an Autocrypt peer.
35#[derive(Debug, PartialEq, Eq, Clone)]
36pub struct Peerstate {
37    /// E-mail address of the contact.
38    pub addr: String,
39
40    /// Timestamp of the latest peerstate update.
41    ///
42    /// Updated when a message is received from a contact,
43    /// either with or without `Autocrypt` header.
44    pub last_seen: i64,
45
46    /// Timestamp of the latest `Autocrypt` header reception.
47    pub last_seen_autocrypt: i64,
48
49    /// Encryption preference of the contact.
50    pub prefer_encrypt: EncryptPreference,
51
52    /// Public key of the contact received in `Autocrypt` header.
53    pub public_key: Option<SignedPublicKey>,
54
55    /// Fingerprint of the contact public key.
56    pub public_key_fingerprint: Option<Fingerprint>,
57
58    /// Public key of the contact received in `Autocrypt-Gossip` header.
59    pub gossip_key: Option<SignedPublicKey>,
60
61    /// Timestamp of the latest `Autocrypt-Gossip` header reception.
62    ///
63    /// It is stored to avoid applying outdated gossiped key
64    /// from delayed or reordered messages.
65    pub gossip_timestamp: i64,
66
67    /// Fingerprint of the contact gossip key.
68    pub gossip_key_fingerprint: Option<Fingerprint>,
69
70    /// Public key of the contact at the time it was verified,
71    /// either directly or via gossip from the verified contact.
72    pub verified_key: Option<SignedPublicKey>,
73
74    /// Fingerprint of the verified public key.
75    pub verified_key_fingerprint: Option<Fingerprint>,
76
77    /// The address that introduced this verified key.
78    pub verifier: Option<String>,
79
80    /// Secondary public verified key of the contact.
81    /// It could be a contact gossiped by another verified contact in a shared group
82    /// or a key that was previously used as a verified key.
83    pub secondary_verified_key: Option<SignedPublicKey>,
84
85    /// Fingerprint of the secondary verified public key.
86    pub secondary_verified_key_fingerprint: Option<Fingerprint>,
87
88    /// The address that introduced secondary verified key.
89    pub secondary_verifier: Option<String>,
90
91    /// Row ID of the key in the `keypairs` table
92    /// that we think the peer knows as verified.
93    pub backward_verified_key_id: Option<i64>,
94
95    /// True if it was detected
96    /// that the fingerprint of the key used in chats with
97    /// opportunistic encryption was changed after Peerstate creation.
98    pub fingerprint_changed: bool,
99}
100
101impl Peerstate {
102    /// Creates a peerstate from the `Autocrypt` header.
103    pub fn from_header(header: &Aheader, message_time: i64) -> Self {
104        Self::from_public_key(
105            &header.addr,
106            message_time,
107            header.prefer_encrypt,
108            &header.public_key,
109        )
110    }
111
112    /// Creates a peerstate from the given public key.
113    pub fn from_public_key(
114        addr: &str,
115        last_seen: i64,
116        prefer_encrypt: EncryptPreference,
117        public_key: &SignedPublicKey,
118    ) -> Self {
119        Peerstate {
120            addr: addr.to_string(),
121            last_seen,
122            last_seen_autocrypt: last_seen,
123            prefer_encrypt,
124            public_key: Some(public_key.clone()),
125            public_key_fingerprint: Some(public_key.dc_fingerprint()),
126            gossip_key: None,
127            gossip_key_fingerprint: None,
128            gossip_timestamp: 0,
129            verified_key: None,
130            verified_key_fingerprint: None,
131            verifier: None,
132            secondary_verified_key: None,
133            secondary_verified_key_fingerprint: None,
134            secondary_verifier: None,
135            backward_verified_key_id: None,
136            fingerprint_changed: false,
137        }
138    }
139
140    /// Create a peerstate from the `Autocrypt-Gossip` header.
141    pub fn from_gossip(gossip_header: &Aheader, message_time: i64) -> Self {
142        Peerstate {
143            addr: gossip_header.addr.clone(),
144            last_seen: 0,
145            last_seen_autocrypt: 0,
146
147            // Non-standard extension. According to Autocrypt 1.1.0 gossip headers SHOULD NOT
148            // contain encryption preference.
149            //
150            // Delta Chat includes encryption preference to ensure new users introduced to a group
151            // learn encryption preferences of other members immediately and don't send unencrypted
152            // messages to a group where everyone prefers encryption.
153            prefer_encrypt: gossip_header.prefer_encrypt,
154            public_key: None,
155            public_key_fingerprint: None,
156            gossip_key: Some(gossip_header.public_key.clone()),
157            gossip_key_fingerprint: Some(gossip_header.public_key.dc_fingerprint()),
158            gossip_timestamp: message_time,
159            verified_key: None,
160            verified_key_fingerprint: None,
161            verifier: None,
162            secondary_verified_key: None,
163            secondary_verified_key_fingerprint: None,
164            secondary_verifier: None,
165            backward_verified_key_id: None,
166            fingerprint_changed: false,
167        }
168    }
169
170    /// Loads peerstate corresponding to the given address from the database.
171    pub async fn from_addr(context: &Context, addr: &str) -> Result<Option<Peerstate>> {
172        if context.is_self_addr(addr).await? {
173            return Ok(None);
174        }
175        let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
176                     gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
177                     verified_key, verified_key_fingerprint, \
178                     verifier, \
179                     secondary_verified_key, secondary_verified_key_fingerprint, \
180                     secondary_verifier, \
181                     backward_verified_key_id \
182                     FROM acpeerstates \
183                     WHERE addr=? COLLATE NOCASE LIMIT 1;";
184        Self::from_stmt(context, query, (addr,)).await
185    }
186
187    /// Loads peerstate corresponding to the given fingerprint from the database.
188    pub async fn from_fingerprint(
189        context: &Context,
190        fingerprint: &Fingerprint,
191    ) -> Result<Option<Peerstate>> {
192        // NOTE: If it's our key fingerprint, this returns None currently.
193        let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
194                     gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
195                     verified_key, verified_key_fingerprint, \
196                     verifier, \
197                     secondary_verified_key, secondary_verified_key_fingerprint, \
198                     secondary_verifier, \
199                     backward_verified_key_id \
200                     FROM acpeerstates  \
201                     WHERE public_key_fingerprint=? \
202                     OR gossip_key_fingerprint=? \
203                     ORDER BY public_key_fingerprint=? DESC LIMIT 1;";
204        let fp = fingerprint.hex();
205        Self::from_stmt(context, query, (&fp, &fp, &fp)).await
206    }
207
208    /// Loads peerstate by address or verified fingerprint.
209    ///
210    /// If the address is different but verified fingerprint is the same,
211    /// peerstate with corresponding verified fingerprint is preferred.
212    pub async fn from_verified_fingerprint_or_addr(
213        context: &Context,
214        fingerprint: &Fingerprint,
215        addr: &str,
216    ) -> Result<Option<Peerstate>> {
217        if context.is_self_addr(addr).await? {
218            return Ok(None);
219        }
220        let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
221                     gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
222                     verified_key, verified_key_fingerprint, \
223                     verifier, \
224                     secondary_verified_key, secondary_verified_key_fingerprint, \
225                     secondary_verifier, \
226                     backward_verified_key_id \
227                     FROM acpeerstates  \
228                     WHERE verified_key_fingerprint=? \
229                     OR addr=? COLLATE NOCASE \
230                     ORDER BY verified_key_fingerprint=? DESC, addr=? COLLATE NOCASE DESC, \
231                     last_seen DESC LIMIT 1;";
232        let fp = fingerprint.hex();
233        Self::from_stmt(context, query, (&fp, addr, &fp, addr)).await
234    }
235
236    async fn from_stmt(
237        context: &Context,
238        query: &str,
239        params: impl rusqlite::Params + Send,
240    ) -> Result<Option<Peerstate>> {
241        let peerstate = context
242            .sql
243            .query_row_optional(query, params, |row| {
244                let res = Peerstate {
245                    addr: row.get("addr")?,
246                    last_seen: row.get("last_seen")?,
247                    last_seen_autocrypt: row.get("last_seen_autocrypt")?,
248                    prefer_encrypt: EncryptPreference::from_i32(row.get("prefer_encrypted")?)
249                        .unwrap_or_default(),
250                    public_key: row
251                        .get("public_key")
252                        .ok()
253                        .and_then(|blob: Vec<u8>| SignedPublicKey::from_slice(&blob).ok()),
254                    public_key_fingerprint: row
255                        .get::<_, Option<String>>("public_key_fingerprint")?
256                        .map(|s| s.parse::<Fingerprint>())
257                        .transpose()
258                        .unwrap_or_default(),
259                    gossip_key: row
260                        .get("gossip_key")
261                        .ok()
262                        .and_then(|blob: Vec<u8>| SignedPublicKey::from_slice(&blob).ok()),
263                    gossip_key_fingerprint: row
264                        .get::<_, Option<String>>("gossip_key_fingerprint")?
265                        .map(|s| s.parse::<Fingerprint>())
266                        .transpose()
267                        .unwrap_or_default(),
268                    gossip_timestamp: row.get("gossip_timestamp")?,
269                    verified_key: row
270                        .get("verified_key")
271                        .ok()
272                        .and_then(|blob: Vec<u8>| SignedPublicKey::from_slice(&blob).ok()),
273                    verified_key_fingerprint: row
274                        .get::<_, Option<String>>("verified_key_fingerprint")?
275                        .map(|s| s.parse::<Fingerprint>())
276                        .transpose()
277                        .unwrap_or_default(),
278                    verifier: {
279                        let verifier: Option<String> = row.get("verifier")?;
280                        verifier.filter(|s| !s.is_empty())
281                    },
282                    secondary_verified_key: row
283                        .get("secondary_verified_key")
284                        .ok()
285                        .and_then(|blob: Vec<u8>| SignedPublicKey::from_slice(&blob).ok()),
286                    secondary_verified_key_fingerprint: row
287                        .get::<_, Option<String>>("secondary_verified_key_fingerprint")?
288                        .map(|s| s.parse::<Fingerprint>())
289                        .transpose()
290                        .unwrap_or_default(),
291                    secondary_verifier: {
292                        let secondary_verifier: Option<String> = row.get("secondary_verifier")?;
293                        secondary_verifier.filter(|s| !s.is_empty())
294                    },
295                    backward_verified_key_id: row.get("backward_verified_key_id")?,
296                    fingerprint_changed: false,
297                };
298
299                Ok(res)
300            })
301            .await?;
302        Ok(peerstate)
303    }
304
305    /// Re-calculate `self.public_key_fingerprint` and `self.gossip_key_fingerprint`.
306    /// If one of them was changed, `self.fingerprint_changed` is set to `true`.
307    ///
308    /// Call this after you changed `self.public_key` or `self.gossip_key`.
309    pub fn recalc_fingerprint(&mut self) {
310        if let Some(ref public_key) = self.public_key {
311            let old_public_fingerprint = self.public_key_fingerprint.take();
312            self.public_key_fingerprint = Some(public_key.dc_fingerprint());
313
314            if old_public_fingerprint.is_some()
315                && old_public_fingerprint != self.public_key_fingerprint
316            {
317                self.fingerprint_changed = true;
318            }
319        }
320
321        if let Some(ref gossip_key) = self.gossip_key {
322            let old_gossip_fingerprint = self.gossip_key_fingerprint.take();
323            self.gossip_key_fingerprint = Some(gossip_key.dc_fingerprint());
324
325            if old_gossip_fingerprint.is_none()
326                || self.gossip_key_fingerprint.is_none()
327                || old_gossip_fingerprint != self.gossip_key_fingerprint
328            {
329                // Warn about gossip key change only if there is no public key obtained from
330                // Autocrypt header, which overrides gossip key.
331                if old_gossip_fingerprint.is_some() && self.public_key_fingerprint.is_none() {
332                    self.fingerprint_changed = true;
333                }
334            }
335        }
336    }
337
338    /// Reset Autocrypt peerstate.
339    ///
340    /// Used when it is detected that the contact no longer uses Autocrypt.
341    pub fn degrade_encryption(&mut self, message_time: i64) {
342        self.prefer_encrypt = EncryptPreference::Reset;
343        self.last_seen = message_time;
344    }
345
346    /// Updates peerstate according to the given `Autocrypt` header.
347    pub fn apply_header(&mut self, context: &Context, header: &Aheader, message_time: i64) {
348        if !addr_cmp(&self.addr, &header.addr) {
349            return;
350        }
351
352        if message_time >= self.last_seen {
353            self.last_seen = message_time;
354            self.last_seen_autocrypt = message_time;
355            if (header.prefer_encrypt == EncryptPreference::Mutual
356                || header.prefer_encrypt == EncryptPreference::NoPreference)
357                && header.prefer_encrypt != self.prefer_encrypt
358            {
359                self.prefer_encrypt = header.prefer_encrypt;
360            }
361
362            if self.public_key.as_ref() != Some(&header.public_key) {
363                self.public_key = Some(header.public_key.clone());
364                self.recalc_fingerprint();
365            }
366        } else {
367            warn!(
368                context,
369                "Ignoring outdated Autocrypt header because message_time={} < last_seen={}.",
370                message_time,
371                self.last_seen
372            );
373        }
374    }
375
376    /// Updates peerstate according to the given `Autocrypt-Gossip` header.
377    pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: i64) {
378        if self.addr.to_lowercase() != gossip_header.addr.to_lowercase() {
379            return;
380        }
381
382        if message_time >= self.gossip_timestamp {
383            self.gossip_timestamp = message_time;
384            if self.gossip_key.as_ref() != Some(&gossip_header.public_key) {
385                self.gossip_key = Some(gossip_header.public_key.clone());
386                self.recalc_fingerprint();
387            }
388
389            // This is non-standard.
390            //
391            // According to Autocrypt 1.1.0 gossip headers SHOULD NOT
392            // contain encryption preference, but we include it into
393            // Autocrypt-Gossip and apply it one way (from
394            // "nopreference" to "mutual").
395            //
396            // This is compatible to standard clients, because they
397            // can't distinguish it from the case where we have
398            // contacted the client in the past and received this
399            // preference via Autocrypt header.
400            if self.last_seen_autocrypt == 0
401                && self.prefer_encrypt == EncryptPreference::NoPreference
402                && gossip_header.prefer_encrypt == EncryptPreference::Mutual
403            {
404                self.prefer_encrypt = EncryptPreference::Mutual;
405            }
406        };
407    }
408
409    /// Converts the peerstate into the contact public key.
410    ///
411    /// Similar to [`Self::peek_key`], but consumes the peerstate and returns owned key.
412    pub fn take_key(mut self, verified: bool) -> Option<SignedPublicKey> {
413        if verified {
414            self.verified_key.take()
415        } else {
416            self.public_key.take().or_else(|| self.gossip_key.take())
417        }
418    }
419
420    /// Returns a reference to the contact public key.
421    ///
422    /// `verified` determines the required verification status of the key.
423    /// If verified key is requested, returns the verified key,
424    /// otherwise returns the Autocrypt key.
425    ///
426    /// Returned key is suitable for sending in `Autocrypt-Gossip` header.
427    ///
428    /// Returns `None` if there is no suitable public key.
429    pub fn peek_key(&self, verified: bool) -> Option<&SignedPublicKey> {
430        if verified {
431            self.verified_key.as_ref()
432        } else {
433            self.public_key.as_ref().or(self.gossip_key.as_ref())
434        }
435    }
436
437    /// Returns a reference to the contact's public key fingerprint.
438    ///
439    /// Similar to [`Self::peek_key`], but returns the fingerprint instead of the key.
440    fn peek_key_fingerprint(&self, verified: bool) -> Option<&Fingerprint> {
441        if verified {
442            self.verified_key_fingerprint.as_ref()
443        } else {
444            self.public_key_fingerprint
445                .as_ref()
446                .or(self.gossip_key_fingerprint.as_ref())
447        }
448    }
449
450    /// Returns true if the key used for opportunistic encryption in the 1:1 chat
451    /// is the same as the verified key.
452    ///
453    /// Note that verified groups always use the verified key no matter if the
454    /// opportunistic key matches or not.
455    pub(crate) fn is_using_verified_key(&self) -> bool {
456        let verified = self.peek_key_fingerprint(true);
457
458        verified.is_some() && verified == self.peek_key_fingerprint(false)
459    }
460
461    pub(crate) async fn is_backward_verified(&self, context: &Context) -> Result<bool> {
462        let Some(backward_verified_key_id) = self.backward_verified_key_id else {
463            return Ok(false);
464        };
465
466        let self_key_id = context.get_config_i64(Config::KeyId).await?;
467
468        let backward_verified = backward_verified_key_id == self_key_id;
469        Ok(backward_verified)
470    }
471
472    /// Set this peerstate to verified;
473    /// make sure to call `self.save_to_db` to save these changes.
474    ///
475    /// Params:
476    ///
477    /// * key: The new verified key.
478    /// * fingerprint: Only set to verified if the key's fingerprint matches this.
479    /// * verifier:
480    ///   The address which introduces the given contact.
481    ///   If we are verifying the contact, use that contacts address.
482    pub fn set_verified(
483        &mut self,
484        key: SignedPublicKey,
485        fingerprint: Fingerprint,
486        verifier: String,
487    ) -> Result<()> {
488        if key.dc_fingerprint() == fingerprint {
489            self.verified_key = Some(key);
490            self.verified_key_fingerprint = Some(fingerprint);
491            self.verifier = Some(verifier);
492            Ok(())
493        } else {
494            Err(Error::msg(format!(
495                "{fingerprint} is not peer's key fingerprint",
496            )))
497        }
498    }
499
500    /// Sets the gossiped key as the secondary verified key.
501    ///
502    /// If gossiped key is the same as the current verified key,
503    /// do nothing to avoid overwriting secondary verified key
504    /// which may be different.
505    pub fn set_secondary_verified_key(&mut self, gossip_key: SignedPublicKey, verifier: String) {
506        let fingerprint = gossip_key.dc_fingerprint();
507        if self.verified_key_fingerprint.as_ref() != Some(&fingerprint) {
508            self.secondary_verified_key = Some(gossip_key);
509            self.secondary_verified_key_fingerprint = Some(fingerprint);
510            self.secondary_verifier = Some(verifier);
511        }
512    }
513
514    /// Saves the peerstate to the database.
515    pub async fn save_to_db(&self, sql: &Sql) -> Result<()> {
516        self.save_to_db_ex(sql, None).await
517    }
518
519    /// Saves the peerstate to the database.
520    ///
521    /// * `old_addr`: Old address of the peerstate in case of an AEAP transition.
522    pub(crate) async fn save_to_db_ex(&self, sql: &Sql, old_addr: Option<&str>) -> Result<()> {
523        let trans_fn = |t: &mut rusqlite::Transaction| {
524            let verified_key_fingerprint =
525                self.verified_key_fingerprint.as_ref().map(|fp| fp.hex());
526            if let Some(old_addr) = old_addr {
527                // We are doing an AEAP transition to the new address and the SQL INSERT below will
528                // save the existing peerstate as belonging to this new address. We now need to
529                // "unverify" the peerstate that belongs to the current address in case if the
530                // contact later wants to move back to the current address. Otherwise the old entry
531                // will be just found and updated instead of doing AEAP. We can't just delete the
532                // existing peerstate as this would break encryption to it. This is critical for
533                // non-verified groups -- if we can't encrypt to the old address, we can't securely
534                // remove it from the group (to add the new one instead).
535                //
536                // NB: We check that `verified_key_fingerprint` hasn't changed to protect from
537                // possible races.
538                t.execute(
539                    "UPDATE acpeerstates
540                     SET verified_key=NULL, verified_key_fingerprint='', verifier=''
541                     WHERE addr=? AND verified_key_fingerprint=?",
542                    (old_addr, &verified_key_fingerprint),
543                )?;
544            }
545            t.execute(
546                "INSERT INTO acpeerstates (
547                    last_seen,
548                    last_seen_autocrypt,
549                    prefer_encrypted,
550                    public_key,
551                    gossip_timestamp,
552                    gossip_key,
553                    public_key_fingerprint,
554                    gossip_key_fingerprint,
555                    verified_key,
556                    verified_key_fingerprint,
557                    verifier,
558                    secondary_verified_key,
559                    secondary_verified_key_fingerprint,
560                    secondary_verifier,
561                    backward_verified_key_id,
562                    addr)
563                    VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
564                    ON CONFLICT (addr)
565                    DO UPDATE SET
566                    last_seen = excluded.last_seen,
567                    last_seen_autocrypt = excluded.last_seen_autocrypt,
568                    prefer_encrypted = excluded.prefer_encrypted,
569                    public_key = excluded.public_key,
570                    gossip_timestamp = excluded.gossip_timestamp,
571                    gossip_key = excluded.gossip_key,
572                    public_key_fingerprint = excluded.public_key_fingerprint,
573                    gossip_key_fingerprint = excluded.gossip_key_fingerprint,
574                    verified_key = excluded.verified_key,
575                    verified_key_fingerprint = excluded.verified_key_fingerprint,
576                    verifier = excluded.verifier,
577                    secondary_verified_key = excluded.secondary_verified_key,
578                    secondary_verified_key_fingerprint = excluded.secondary_verified_key_fingerprint,
579                    secondary_verifier = excluded.secondary_verifier,
580                    backward_verified_key_id = excluded.backward_verified_key_id",
581                (
582                    self.last_seen,
583                    self.last_seen_autocrypt,
584                    self.prefer_encrypt as i64,
585                    self.public_key.as_ref().map(|k| k.to_bytes()),
586                    self.gossip_timestamp,
587                    self.gossip_key.as_ref().map(|k| k.to_bytes()),
588                    self.public_key_fingerprint.as_ref().map(|fp| fp.hex()),
589                    self.gossip_key_fingerprint.as_ref().map(|fp| fp.hex()),
590                    self.verified_key.as_ref().map(|k| k.to_bytes()),
591                    &verified_key_fingerprint,
592                    self.verifier.as_deref().unwrap_or(""),
593                    self.secondary_verified_key.as_ref().map(|k| k.to_bytes()),
594                    self.secondary_verified_key_fingerprint
595                        .as_ref()
596                        .map(|fp| fp.hex()),
597                    self.secondary_verifier.as_deref().unwrap_or(""),
598                    self.backward_verified_key_id,
599                    &self.addr,
600                ),
601            )?;
602            Ok(())
603        };
604        sql.transaction(trans_fn).await
605    }
606
607    /// Returns the address that verified the contact
608    pub fn get_verifier(&self) -> Option<&str> {
609        self.verifier.as_deref()
610    }
611
612    /// Add an info message to all the chats with this contact, informing about
613    /// a [`PeerstateChange`].
614    ///
615    /// Also, in the case of an address change (AEAP), replace the old address
616    /// with the new address in all chats.
617    async fn handle_setup_change(
618        &self,
619        context: &Context,
620        timestamp: i64,
621        change: PeerstateChange,
622    ) -> Result<()> {
623        if context.is_self_addr(&self.addr).await? {
624            // Do not try to search all the chats with self.
625            return Ok(());
626        }
627
628        let contact_id = context
629            .sql
630            .query_get_value(
631                "SELECT id FROM contacts WHERE addr=? COLLATE NOCASE;",
632                (&self.addr,),
633            )
634            .await?
635            .with_context(|| format!("contact with peerstate.addr {:?} not found", &self.addr))?;
636
637        let chats = Chatlist::try_load(context, 0, None, Some(contact_id)).await?;
638        let msg = match &change {
639            PeerstateChange::FingerprintChange => {
640                stock_str::contact_setup_changed(context, &self.addr).await
641            }
642            PeerstateChange::Aeap(new_addr) => {
643                let old_contact = Contact::get_by_id(context, contact_id).await?;
644                stock_str::aeap_addr_changed(
645                    context,
646                    old_contact.get_display_name(),
647                    &self.addr,
648                    new_addr,
649                )
650                .await
651            }
652        };
653        for (chat_id, msg_id) in chats.iter() {
654            let timestamp_sort = if let Some(msg_id) = msg_id {
655                let lastmsg = Message::load_from_db(context, *msg_id).await?;
656                lastmsg.timestamp_sort
657            } else {
658                chat_id.created_timestamp(context).await?
659            };
660
661            if let PeerstateChange::Aeap(new_addr) = &change {
662                let chat = Chat::load_from_db(context, *chat_id).await?;
663
664                if chat.typ == Chattype::Group && !chat.is_protected() {
665                    // Don't add an info_msg to the group, in order not to make the user think
666                    // that the address was automatically replaced in the group.
667                    continue;
668                }
669
670                // For security reasons, for now, we only do the AEAP transition if the fingerprint
671                // is verified (that's what from_verified_fingerprint_or_addr() does).
672                // In order to not have inconsistent group membership state, we then only do the
673                // transition in verified groups and in broadcast lists.
674                if (chat.typ == Chattype::Group && chat.is_protected())
675                    || chat.typ == Chattype::Broadcast
676                {
677                    match ContactAddress::new(new_addr) {
678                        Ok(new_addr) => {
679                            let (new_contact_id, _) = Contact::add_or_lookup(
680                                context,
681                                "",
682                                &new_addr,
683                                Origin::IncomingUnknownFrom,
684                            )
685                            .await?;
686                            context
687                                .sql
688                                .transaction(|transaction| {
689                                    transaction.execute(
690                                        "UPDATE chats_contacts
691                                         SET remove_timestamp=MAX(add_timestamp+1, ?)
692                                         WHERE chat_id=? AND contact_id=?",
693                                        (timestamp, chat_id, contact_id),
694                                    )?;
695                                    transaction.execute(
696                                        "INSERT INTO chats_contacts
697                                         (chat_id, contact_id, add_timestamp)
698                                         VALUES (?1, ?2, ?3)
699                                         ON CONFLICT (chat_id, contact_id)
700                                         DO UPDATE SET add_timestamp=MAX(remove_timestamp, ?3)",
701                                        (chat_id, new_contact_id, timestamp),
702                                    )?;
703                                    Ok(())
704                                })
705                                .await?;
706
707                            context.emit_event(EventType::ChatModified(*chat_id));
708                        }
709                        Err(err) => {
710                            warn!(
711                                context,
712                                "New address {:?} is not valid, not doing AEAP: {:#}.",
713                                new_addr,
714                                err
715                            )
716                        }
717                    }
718                }
719            }
720
721            chat::add_info_msg_with_cmd(
722                context,
723                *chat_id,
724                &msg,
725                SystemMessage::Unknown,
726                timestamp_sort,
727                Some(timestamp),
728                None,
729                None,
730                None,
731            )
732            .await?;
733        }
734
735        chatlist_events::emit_chatlist_changed(context);
736        // update the chats the contact is part of
737        chatlist_events::emit_chatlist_items_changed_for_contact(context, contact_id);
738        Ok(())
739    }
740
741    /// Adds a warning to all the chats corresponding to peerstate if fingerprint has changed.
742    pub(crate) async fn handle_fingerprint_change(
743        &self,
744        context: &Context,
745        timestamp: i64,
746    ) -> Result<()> {
747        if self.fingerprint_changed {
748            self.handle_setup_change(context, timestamp, PeerstateChange::FingerprintChange)
749                .await?;
750        }
751        Ok(())
752    }
753}
754
755/// Do an AEAP transition, if necessary.
756/// AEAP stands for "Automatic Email Address Porting."
757///
758/// In `drafts/aeap_mvp.md` there is a "big picture" overview over AEAP.
759pub(crate) async fn maybe_do_aeap_transition(
760    context: &Context,
761    mime_parser: &mut crate::mimeparser::MimeMessage,
762) -> Result<()> {
763    let Some(peerstate) = &mime_parser.peerstate else {
764        return Ok(());
765    };
766
767    // If the from addr is different from the peerstate address we know,
768    // we may want to do an AEAP transition.
769    if !addr_cmp(&peerstate.addr, &mime_parser.from.addr) {
770        // Check if it's a chat message; we do this to avoid
771        // some accidental transitions if someone writes from multiple
772        // addresses with an MUA.
773        if !mime_parser.has_chat_version() {
774            info!(
775                context,
776                "Not doing AEAP from {} to {} because the message is not a chat message.",
777                &peerstate.addr,
778                &mime_parser.from.addr
779            );
780            return Ok(());
781        }
782
783        // Check if the message is encrypted and signed correctly. If it's not encrypted, it's
784        // probably from a new contact sharing the same key.
785        if mime_parser.signatures.is_empty() {
786            info!(
787                context,
788                "Not doing AEAP from {} to {} because the message is not encrypted and signed.",
789                &peerstate.addr,
790                &mime_parser.from.addr
791            );
792            return Ok(());
793        }
794
795        // Check if the From: address was also in the signed part of the email.
796        // Without this check, an attacker could replay a message from Alice
797        // to Bob. Then Bob's device would do an AEAP transition from Alice's
798        // to the attacker's address, allowing for easier phishing.
799        if !mime_parser.from_is_signed {
800            info!(
801                context,
802                "Not doing AEAP from {} to {} because From: is not signed.",
803                &peerstate.addr,
804                &mime_parser.from.addr
805            );
806            return Ok(());
807        }
808
809        // DC avoids sending messages with the same timestamp, that's why messages
810        // with equal timestamps are ignored here unlike in `Peerstate::apply_header()`.
811        if mime_parser.timestamp_sent <= peerstate.last_seen {
812            info!(
813                context,
814                "Not doing AEAP from {} to {} because {} < {}.",
815                &peerstate.addr,
816                &mime_parser.from.addr,
817                mime_parser.timestamp_sent,
818                peerstate.last_seen
819            );
820            return Ok(());
821        }
822
823        info!(
824            context,
825            "Doing AEAP transition from {} to {}.", &peerstate.addr, &mime_parser.from.addr
826        );
827
828        let peerstate = mime_parser.peerstate.as_mut().context("no peerstate??")?;
829        // Add info messages to chats with this (verified) contact
830        //
831        peerstate
832            .handle_setup_change(
833                context,
834                mime_parser.timestamp_sent,
835                PeerstateChange::Aeap(mime_parser.from.addr.clone()),
836            )
837            .await?;
838
839        let old_addr = mem::take(&mut peerstate.addr);
840        peerstate.addr.clone_from(&mime_parser.from.addr);
841        let header = mime_parser.autocrypt_header.as_ref().context(
842            "Internal error: Tried to do an AEAP transition without an autocrypt header??",
843        )?;
844        peerstate.apply_header(context, header, mime_parser.timestamp_sent);
845
846        peerstate
847            .save_to_db_ex(&context.sql, Some(&old_addr))
848            .await?;
849    }
850
851    Ok(())
852}
853
854/// Type of the peerstate change.
855///
856/// Changes to the peerstate are notified to the user via a message
857/// explaining the happened change.
858enum PeerstateChange {
859    /// The contact's public key fingerprint changed, likely because
860    /// the contact uses a new device and didn't transfer their key.
861    FingerprintChange,
862    /// The contact changed their address to the given new address
863    /// (Automatic Email Address Porting).
864    Aeap(String),
865}
866
867#[cfg(test)]
868mod tests {
869    use super::*;
870    use crate::test_utils::alice_keypair;
871
872    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
873    async fn test_peerstate_save_to_db() {
874        let ctx = crate::test_utils::TestContext::new().await;
875        let addr = "hello@mail.com";
876
877        let pub_key = alice_keypair().public;
878
879        let peerstate = Peerstate {
880            addr: addr.into(),
881            last_seen: 10,
882            last_seen_autocrypt: 11,
883            prefer_encrypt: EncryptPreference::Mutual,
884            public_key: Some(pub_key.clone()),
885            public_key_fingerprint: Some(pub_key.dc_fingerprint()),
886            gossip_key: Some(pub_key.clone()),
887            gossip_timestamp: 12,
888            gossip_key_fingerprint: Some(pub_key.dc_fingerprint()),
889            verified_key: Some(pub_key.clone()),
890            verified_key_fingerprint: Some(pub_key.dc_fingerprint()),
891            verifier: None,
892            secondary_verified_key: None,
893            secondary_verified_key_fingerprint: None,
894            secondary_verifier: None,
895            backward_verified_key_id: None,
896            fingerprint_changed: false,
897        };
898
899        assert!(
900            peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(),
901            "failed to save to db"
902        );
903
904        let peerstate_new = Peerstate::from_addr(&ctx.ctx, addr)
905            .await
906            .expect("failed to load peerstate from db")
907            .expect("no peerstate found in the database");
908
909        assert_eq!(peerstate, peerstate_new);
910        let peerstate_new2 = Peerstate::from_fingerprint(&ctx.ctx, &pub_key.dc_fingerprint())
911            .await
912            .expect("failed to load peerstate from db")
913            .expect("no peerstate found in the database");
914        assert_eq!(peerstate, peerstate_new2);
915    }
916
917    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
918    async fn test_peerstate_double_create() {
919        let ctx = crate::test_utils::TestContext::new().await;
920        let addr = "hello@mail.com";
921        let pub_key = alice_keypair().public;
922
923        let peerstate = Peerstate {
924            addr: addr.into(),
925            last_seen: 10,
926            last_seen_autocrypt: 11,
927            prefer_encrypt: EncryptPreference::Mutual,
928            public_key: Some(pub_key.clone()),
929            public_key_fingerprint: Some(pub_key.dc_fingerprint()),
930            gossip_key: None,
931            gossip_timestamp: 12,
932            gossip_key_fingerprint: None,
933            verified_key: None,
934            verified_key_fingerprint: None,
935            verifier: None,
936            secondary_verified_key: None,
937            secondary_verified_key_fingerprint: None,
938            secondary_verifier: None,
939            backward_verified_key_id: None,
940            fingerprint_changed: false,
941        };
942
943        assert!(
944            peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(),
945            "failed to save"
946        );
947        assert!(
948            peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(),
949            "double-call with create failed"
950        );
951    }
952
953    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
954    async fn test_peerstate_with_empty_gossip_key_save_to_db() {
955        let ctx = crate::test_utils::TestContext::new().await;
956        let addr = "hello@mail.com";
957
958        let pub_key = alice_keypair().public;
959
960        let peerstate = Peerstate {
961            addr: addr.into(),
962            last_seen: 10,
963            last_seen_autocrypt: 11,
964            prefer_encrypt: EncryptPreference::Mutual,
965            public_key: Some(pub_key.clone()),
966            public_key_fingerprint: Some(pub_key.dc_fingerprint()),
967            gossip_key: None,
968            gossip_timestamp: 12,
969            gossip_key_fingerprint: None,
970            verified_key: None,
971            verified_key_fingerprint: None,
972            verifier: None,
973            secondary_verified_key: None,
974            secondary_verified_key_fingerprint: None,
975            secondary_verifier: None,
976            backward_verified_key_id: None,
977            fingerprint_changed: false,
978        };
979
980        assert!(
981            peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(),
982            "failed to save"
983        );
984
985        let peerstate_new = Peerstate::from_addr(&ctx.ctx, addr)
986            .await
987            .expect("failed to load peerstate from db");
988
989        assert_eq!(Some(peerstate), peerstate_new);
990    }
991
992    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
993    async fn test_peerstate_load_db_defaults() {
994        let ctx = crate::test_utils::TestContext::new().await;
995        let addr = "hello@mail.com";
996
997        // Old code created peerstates with this code and updated
998        // other values later.  If UPDATE failed, other columns had
999        // default values, in particular fingerprints were set to
1000        // empty strings instead of NULL. This should not be the case
1001        // anymore, but the regression test still checks that defaults
1002        // can be loaded without errors.
1003        ctx.ctx
1004            .sql
1005            .execute("INSERT INTO acpeerstates (addr) VALUES(?)", (addr,))
1006            .await
1007            .expect("Failed to write to the database");
1008
1009        let peerstate = Peerstate::from_addr(&ctx.ctx, addr)
1010            .await
1011            .expect("Failed to load peerstate from db")
1012            .expect("Loaded peerstate is empty");
1013
1014        // Check that default values for fingerprints are treated like
1015        // NULL.
1016        assert_eq!(peerstate.public_key_fingerprint, None);
1017        assert_eq!(peerstate.gossip_key_fingerprint, None);
1018        assert_eq!(peerstate.verified_key_fingerprint, None);
1019    }
1020
1021    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
1022    async fn test_peerstate_degrade_reordering() {
1023        let ctx = crate::test_utils::TestContext::new().await;
1024
1025        let addr = "example@example.org";
1026        let pub_key = alice_keypair().public;
1027        let header = Aheader::new(addr.to_string(), pub_key, EncryptPreference::Mutual);
1028
1029        let mut peerstate = Peerstate {
1030            addr: addr.to_string(),
1031            last_seen: 0,
1032            last_seen_autocrypt: 0,
1033            prefer_encrypt: EncryptPreference::NoPreference,
1034            public_key: None,
1035            public_key_fingerprint: None,
1036            gossip_key: None,
1037            gossip_timestamp: 0,
1038            gossip_key_fingerprint: None,
1039            verified_key: None,
1040            verified_key_fingerprint: None,
1041            verifier: None,
1042            secondary_verified_key: None,
1043            secondary_verified_key_fingerprint: None,
1044            secondary_verifier: None,
1045            backward_verified_key_id: None,
1046            fingerprint_changed: false,
1047        };
1048
1049        peerstate.apply_header(&ctx, &header, 100);
1050        assert_eq!(peerstate.prefer_encrypt, EncryptPreference::Mutual);
1051
1052        peerstate.degrade_encryption(300);
1053        assert_eq!(peerstate.prefer_encrypt, EncryptPreference::Reset);
1054
1055        // This has message time 200, while encryption was degraded at timestamp 300.
1056        // Because of reordering, header should not be applied.
1057        peerstate.apply_header(&ctx, &header, 200);
1058        assert_eq!(peerstate.prefer_encrypt, EncryptPreference::Reset);
1059
1060        // Same header will be applied in the future.
1061        peerstate.apply_header(&ctx, &header, 300);
1062        assert_eq!(peerstate.prefer_encrypt, EncryptPreference::Mutual);
1063    }
1064}