diff --git a/src/contact.rs b/src/contact.rs index 75992ab655..fdfecc889f 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -28,7 +28,8 @@ use crate::constants::{Blocked, Chattype, DC_GCL_ADD_SELF, DC_GCL_VERIFIED_ONLY} use crate::context::Context; use crate::events::EventType; use crate::key::{ - load_self_public_key, load_self_public_key_opt, DcKey, Fingerprint, SignedPublicKey, + load_self_public_key, self_fingerprint, self_fingerprint_opt, DcKey, Fingerprint, + SignedPublicKey, }; use crate::log::LogExt; use crate::message::MessageState; @@ -623,8 +624,8 @@ impl Contact { .get_config(Config::ConfiguredAddr) .await? .unwrap_or_default(); - if let Some(public_key) = load_self_public_key_opt(context).await? { - contact.fingerprint = Some(public_key.dc_fingerprint().hex()); + if let Some(self_fp) = self_fingerprint_opt(context).await? { + contact.fingerprint = Some(self_fp.to_string()); } contact.status = context .get_config(Config::Selfstatus) @@ -855,7 +856,7 @@ impl Contact { } if !fingerprint.is_empty() { - let fingerprint_self = load_self_public_key(context).await?.dc_fingerprint().hex(); + let fingerprint_self = self_fingerprint(context).await?; if fingerprint == fingerprint_self { return Ok((ContactId::SELF, sth_modified)); } diff --git a/src/context.rs b/src/context.rs index 7c0e8f8b02..42e9132652 100644 --- a/src/context.rs +++ b/src/context.rs @@ -5,7 +5,7 @@ use std::ffi::OsString; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use std::time::Duration; use anyhow::{bail, ensure, Context as _, Result}; @@ -25,7 +25,7 @@ use crate::debug_logging::DebugLogging; use crate::download::DownloadState; use crate::events::{Event, EventEmitter, EventType, Events}; use crate::imap::{FolderMeaning, Imap, ServerMetadata}; -use crate::key::{load_self_public_key, load_self_secret_key, DcKey as _}; +use crate::key::{load_self_secret_key, self_fingerprint}; use crate::login_param::{ConfiguredLoginParam, EnteredLoginParam}; use crate::message::{self, Message, MessageState, MsgId}; use crate::param::{Param, Params}; @@ -297,6 +297,11 @@ pub struct InnerContext { /// Iroh for realtime peer channels. pub(crate) iroh: Arc>>, + + /// The own fingerprint, if it was computed already. + /// tokio::sync::OnceCell would be possible to use, but overkill for our usecase; + /// the standard library's OnceLock is enough, and it's a lot smaller in memory. + pub(crate) self_fingerprint: OnceLock, } /// The state of ongoing process. @@ -456,6 +461,7 @@ impl Context { push_subscriber, push_subscribed: AtomicBool::new(false), iroh: Arc::new(RwLock::new(None)), + self_fingerprint: OnceLock::new(), }; let ctx = Context { @@ -813,8 +819,8 @@ impl Context { .sql .count("SELECT COUNT(*) FROM public_keys;", ()) .await?; - let fingerprint_str = match load_self_public_key(self).await { - Ok(key) => key.dc_fingerprint().hex(), + let fingerprint_str = match self_fingerprint(self).await { + Ok(fp) => fp.to_string(), Err(err) => format!(""), }; diff --git a/src/key.rs b/src/key.rs index 5afa11bdf1..b6abc7233b 100644 --- a/src/key.rs +++ b/src/key.rs @@ -186,6 +186,38 @@ pub(crate) async fn load_self_public_keyring(context: &Context) -> Result Result<&str> { + if let Some(fp) = context.self_fingerprint.get() { + Ok(fp) + } else { + let fp = load_self_public_key(context).await?.dc_fingerprint().hex(); + Ok(context.self_fingerprint.get_or_init(|| fp)) + } +} + +/// Returns own public key fingerprint in (not human-readable) hex representation. +/// This is the fingerprint format that is used in the database. +/// +/// Returns `None` if no key is generated yet. +/// +/// For performance reasons, the fingerprint is cached after the first invocation. +pub(crate) async fn self_fingerprint_opt(context: &Context) -> Result> { + if let Some(fp) = context.self_fingerprint.get() { + Ok(Some(fp)) + } else if let Some(key) = load_self_public_key_opt(context).await? { + let fp = key.dc_fingerprint().hex(); + Ok(Some(context.self_fingerprint.get_or_init(|| fp))) + } else { + Ok(None) + } +} + pub(crate) async fn load_self_secret_key(context: &Context) -> Result { let private_key = context .sql diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 46bc6948a7..ed4e1a9aac 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -23,7 +23,7 @@ use crate::contact::{Contact, ContactId, Origin}; use crate::context::Context; use crate::e2ee::EncryptHelper; use crate::ephemeral::Timer as EphemeralTimer; -use crate::key::load_self_public_key; +use crate::key::self_fingerprint; use crate::key::{DcKey, SignedPublicKey}; use crate::location; use crate::message::{self, Message, MsgId, Viewtype}; @@ -204,8 +204,7 @@ impl MimeFactory { let encryption_keys; - let self_public_key = load_self_public_key(context).await?; - let self_fingerprint = self_public_key.dc_fingerprint().hex(); + let self_fingerprint = self_fingerprint(context).await?; if chat.is_self_talk() { to.push((from_displayname.to_string(), from_addr.to_string())); @@ -311,7 +310,7 @@ impl MimeFactory { if !fingerprint.is_empty() { member_fingerprints.push(fingerprint); } else if id == ContactId::SELF { - member_fingerprints.push(self_fingerprint.clone()); + member_fingerprints.push(self_fingerprint.to_string()); } else { debug_assert!(member_fingerprints.is_empty(), "If some past member is a PGP-contact, all other past members should be PGP-contacts too"); } @@ -362,7 +361,7 @@ impl MimeFactory { } else if id == ContactId::SELF { // It's fine to have self in past members // if we are leaving the group. - past_member_fingerprints.push(self_fingerprint.clone()); + past_member_fingerprints.push(self_fingerprint.to_string()); } else { debug_assert!(past_member_fingerprints.is_empty(), "If some past member is a PGP-contact, all other past members should be PGP-contacts too"); } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 62921a2a11..11c479521d 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -255,7 +255,7 @@ impl MimeMessage { ); headers.retain(|k, _| { !is_hidden(k) || { - headers_removed.insert(k.clone()); + headers_removed.insert(k.to_string()); false } }); diff --git a/src/receive_imf.rs b/src/receive_imf.rs index ac8e0380b9..54d4bca6cb 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -25,7 +25,7 @@ use crate::ephemeral::{stock_ephemeral_timer_changed, Timer as EphemeralTimer}; use crate::events::EventType; use crate::headerdef::{HeaderDef, HeaderDefMap}; use crate::imap::{markseen_on_imap_table, GENERATED_PREFIX}; -use crate::key::load_self_public_key_opt; +use crate::key::self_fingerprint_opt; use crate::key::{DcKey, Fingerprint, SignedPublicKey}; use crate::log::LogExt; use crate::message::{ @@ -3366,8 +3366,8 @@ async fn lookup_pgp_contact_by_fingerprint( .await? { Ok(Some(contact_id)) - } else if let Some(self_public_key) = load_self_public_key_opt(context).await? { - if self_public_key.dc_fingerprint().hex() == fingerprint { + } else if let Some(self_fp) = self_fingerprint_opt(context).await? { + if self_fp == fingerprint { Ok(Some(ContactId::SELF)) } else { Ok(None) diff --git a/src/securejoin/bob.rs b/src/securejoin/bob.rs index fb3a840f9a..f5c52aa691 100644 --- a/src/securejoin/bob.rs +++ b/src/securejoin/bob.rs @@ -9,7 +9,7 @@ use crate::constants::{Blocked, Chattype}; use crate::contact::Origin; use crate::context::Context; use crate::events::EventType; -use crate::key::{load_self_public_key, DcKey}; +use crate::key::self_fingerprint; use crate::message::{Message, Viewtype}; use crate::mimeparser::{MimeMessage, SystemMessage}; use crate::param::Param; @@ -273,8 +273,8 @@ pub(crate) async fn send_handshake_message( msg.param.set_int(Param::GuaranteeE2ee, 1); // Sends our own fingerprint in the Secure-Join-Fingerprint header. - let bob_fp = load_self_public_key(context).await?.dc_fingerprint(); - msg.param.set(Param::Arg3, bob_fp.hex()); + let bob_fp = self_fingerprint(context).await?; + msg.param.set(Param::Arg3, bob_fp); // Sends the grpid in the Secure-Join-Group header. // diff --git a/src/securejoin/securejoin_tests.rs b/src/securejoin/securejoin_tests.rs index d565fe9f0a..b33f6b66be 100644 --- a/src/securejoin/securejoin_tests.rs +++ b/src/securejoin/securejoin_tests.rs @@ -4,6 +4,7 @@ use super::*; use crate::chat::{remove_contact_from_chat, CantSendReason}; use crate::chatlist::Chatlist; use crate::constants::Chattype; +use crate::key::self_fingerprint; use crate::receive_imf::receive_imf; use crate::stock_str::{self, chat_protection_enabled}; use crate::test_utils::{ @@ -177,13 +178,10 @@ async fn test_setup_contact_ex(case: SetupContactCase) { "vc-request-with-auth" ); assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some()); - let bob_fp = load_self_public_key(&bob.ctx) - .await - .unwrap() - .dc_fingerprint(); + let bob_fp = self_fingerprint(&bob).await.unwrap(); assert_eq!( - *msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), - bob_fp.hex() + msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), + bob_fp ); if case == SetupContactCase::WrongAliceGossip { @@ -498,10 +496,10 @@ async fn test_secure_join() -> Result<()> { "vg-request-with-auth" ); assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some()); - let bob_fp = load_self_public_key(&bob).await?.dc_fingerprint(); + let bob_fp = self_fingerprint(&bob).await?; assert_eq!( - *msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), - bob_fp.hex() + msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), + bob_fp ); // Alice should not yet have Bob verified diff --git a/src/test_utils.rs b/src/test_utils.rs index 23e1cab992..e403ca7e11 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -32,7 +32,7 @@ use crate::contact::{ }; use crate::context::Context; use crate::events::{Event, EventEmitter, EventType, Events}; -use crate::key::{self, load_self_public_key, DcKey, DcSecretKey}; +use crate::key::{self, self_fingerprint, DcKey, DcSecretKey}; use crate::message::{update_msg_state, Message, MessageState, MsgId, Viewtype}; use crate::mimeparser::{MimeMessage, SystemMessage}; use crate::pgp::KeyPair; @@ -770,18 +770,12 @@ impl TestContext { pub async fn add_or_lookup_pgp_contact(&self, other: &TestContext) -> Contact { let primary_self_addr = other.ctx.get_primary_self_addr().await.unwrap(); let addr = ContactAddress::new(&primary_self_addr).unwrap(); - let public_key = load_self_public_key(other).await.unwrap(); - let fingerprint = public_key.dc_fingerprint(); + let fingerprint = self_fingerprint(other).await.unwrap(); - let (contact_id, _modified) = Contact::add_or_lookup_ex( - self, - "", - &addr, - &fingerprint.hex(), - Origin::MailinglistAddress, - ) - .await - .expect("add_or_lookup"); + let (contact_id, _modified) = + Contact::add_or_lookup_ex(self, "", &addr, fingerprint, Origin::MailinglistAddress) + .await + .expect("add_or_lookup"); Contact::get_by_id(&self.ctx, contact_id).await.unwrap() } diff --git a/src/webxdc.rs b/src/webxdc.rs index ecc4d58f97..df96e9937d 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -39,7 +39,7 @@ use crate::constants::Chattype; use crate::contact::ContactId; use crate::context::Context; use crate::events::EventType; -use crate::key::{load_self_public_key, DcKey}; +use crate::key::self_fingerprint; use crate::message::{Message, MessageState, MsgId, Viewtype}; use crate::mimefactory::RECOMMENDED_FILE_SIZE; use crate::mimeparser::SystemMessage; @@ -962,7 +962,7 @@ impl Message { } async fn get_webxdc_self_addr(&self, context: &Context) -> Result { - let fingerprint = load_self_public_key(context).await?.dc_fingerprint().hex(); + let fingerprint = self_fingerprint(context).await?; let data = format!("{}-{}", fingerprint, self.rfc724_mid); let hash = Sha256::digest(data.as_bytes()); Ok(format!("{hash:x}"))