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