compose/pgp: add encrypt_for_self flag

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
pull/490/head
Manos Pitsidianakis 4 weeks ago
parent c82341f3af
commit 23395491db
No known key found for this signature in database
GPG Key ID: 7729C7707F7E09D0

@ -42,5 +42,5 @@ use crate::conf::{*, data_types::*};
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct TagsSettingsOverride { # [serde (deserialize_with = "tag_color_de")] # [serde (default)] pub colors : Option < IndexMap < TagHash , Color > > , # [serde (deserialize_with = "tag_set_de" , alias = "ignore-tags")] # [serde (default)] pub ignore_tags : Option < IndexSet < TagHash > > } impl Default for TagsSettingsOverride { fn default () -> Self { Self { colors : None , ignore_tags : None } } } # [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct TagsSettingsOverride { # [serde (deserialize_with = "tag_color_de")] # [serde (default)] pub colors : Option < IndexMap < TagHash , Color > > , # [serde (deserialize_with = "tag_set_de" , alias = "ignore-tags")] # [serde (default)] pub ignore_tags : Option < IndexSet < TagHash > > } impl Default for TagsSettingsOverride { fn default () -> Self { Self { colors : None , ignore_tags : None } } }
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct PGPSettingsOverride { # [doc = " auto verify signed e-mail according to RFC3156"] # [doc = " Default: true"] # [serde (alias = "auto-verify-signatures")] # [serde (default)] pub auto_verify_signatures : Option < ActionFlag > , # [doc = " auto decrypt encrypted e-mail"] # [doc = " Default: true"] # [serde (alias = "auto-decrypt")] # [serde (default)] pub auto_decrypt : Option < ActionFlag > , # [doc = " always sign sent e-mail"] # [doc = " Default: false"] # [serde (alias = "auto-sign")] # [serde (default)] pub auto_sign : Option < ActionFlag > , # [doc = " Auto encrypt sent e-mail"] # [doc = " Default: false"] # [serde (alias = "auto-encrypt")] # [serde (default)] pub auto_encrypt : Option < ActionFlag > , # [doc = " Default: None"] # [serde (alias = "sign-key")] # [serde (default)] pub sign_key : Option < Option < String > > , # [doc = " Default: None"] # [serde (alias = "decrypt-key")] # [serde (default)] pub decrypt_key : Option < Option < String > > , # [doc = " Default: None"] # [serde (alias = "encrypt-key")] # [serde (default)] pub encrypt_key : Option < Option < String > > , # [doc = " Allow remote lookups"] # [doc = " Default: False"] # [serde (alias = "allow-remote-lookups")] # [serde (default)] pub allow_remote_lookup : Option < ActionFlag > , # [doc = " Remote lookup mechanisms."] # [doc = " Default: \"local,wkd\""] # [cfg_attr (feature = "gpgme" , serde (alias = "remote-lookup-mechanisms"))] # [cfg (feature = "gpgme")] # [serde (default)] pub remote_lookup_mechanisms : Option < melib :: gpgme :: LocateKey > , # [cfg (not (feature = "gpgme"))] # [cfg_attr (not (feature = "gpgme") , serde (alias = "remote-lookup-mechanisms"))] # [serde (default)] pub remote_lookup_mechanisms : Option < String > } impl Default for PGPSettingsOverride { fn default () -> Self { Self { auto_verify_signatures : None , auto_decrypt : None , auto_sign : None , auto_encrypt : None , sign_key : None , decrypt_key : None , encrypt_key : None , allow_remote_lookup : None , remote_lookup_mechanisms : None } } } # [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct PGPSettingsOverride { # [doc = " auto verify signed e-mail according to RFC3156"] # [doc = " Default: true"] # [serde (alias = "auto-verify-signatures")] # [serde (default)] pub auto_verify_signatures : Option < ActionFlag > , # [doc = " auto decrypt encrypted e-mail"] # [doc = " Default: true"] # [serde (alias = "auto-decrypt")] # [serde (default)] pub auto_decrypt : Option < ActionFlag > , # [doc = " always sign sent e-mail"] # [doc = " Default: false"] # [serde (alias = "auto-sign")] # [serde (default)] pub auto_sign : Option < ActionFlag > , # [doc = " Auto encrypt sent e-mail"] # [doc = " Default: false"] # [serde (alias = "auto-encrypt")] # [serde (default)] pub auto_encrypt : Option < ActionFlag > , # [doc = " Default: None"] # [serde (alias = "sign-key")] # [serde (default)] pub sign_key : Option < Option < String > > , # [doc = " Default: None"] # [serde (alias = "decrypt-key")] # [serde (default)] pub decrypt_key : Option < Option < String > > , # [doc = " Default: None"] # [serde (alias = "encrypt-key")] # [serde (default)] pub encrypt_key : Option < Option < String > > , # [doc = " Default: true"] # [serde (alias = "encrypt-for-self")] # [serde (default)] pub encrypt_for_self : Option < bool > , # [doc = " Allow remote lookups"] # [doc = " Default: False"] # [serde (alias = "allow-remote-lookups")] # [serde (default)] pub allow_remote_lookup : Option < ActionFlag > , # [doc = " Remote lookup mechanisms."] # [doc = " Default: \"local,wkd\""] # [cfg_attr (feature = "gpgme" , serde (alias = "remote-lookup-mechanisms"))] # [cfg (feature = "gpgme")] # [serde (default)] pub remote_lookup_mechanisms : Option < melib :: gpgme :: LocateKey > , # [cfg (not (feature = "gpgme"))] # [cfg_attr (not (feature = "gpgme") , serde (alias = "remote-lookup-mechanisms"))] # [serde (default)] pub remote_lookup_mechanisms : Option < String > } impl Default for PGPSettingsOverride { fn default () -> Self { Self { auto_verify_signatures : None , auto_decrypt : None , auto_sign : None , auto_encrypt : None , sign_key : None , decrypt_key : None , encrypt_key : None , encrypt_for_self : None , allow_remote_lookup : None , remote_lookup_mechanisms : None } } }

@ -60,6 +60,10 @@ pub struct PGPSettings {
#[serde(default = "none", alias = "encrypt-key")] #[serde(default = "none", alias = "encrypt-key")]
pub encrypt_key: Option<String>, pub encrypt_key: Option<String>,
/// Default: true
#[serde(default = "true_val", alias = "encrypt-for-self")]
pub encrypt_for_self: bool,
/// Allow remote lookups /// Allow remote lookups
/// Default: False /// Default: False
#[serde( #[serde(
@ -99,6 +103,7 @@ impl Default for PGPSettings {
auto_decrypt: true.into(), auto_decrypt: true.into(),
auto_sign: false.into(), auto_sign: false.into(),
auto_encrypt: false.into(), auto_encrypt: false.into(),
encrypt_for_self: true,
sign_key: None, sign_key: None,
decrypt_key: None, decrypt_key: None,
encrypt_key: None, encrypt_key: None,

@ -21,18 +21,21 @@
//! Entities that handle Mail specific functions. //! Entities that handle Mail specific functions.
use std::{future::Future, pin::Pin};
use indexmap::IndexMap; use indexmap::IndexMap;
use melib::{ use melib::{
backends::{AccountHash, Mailbox, MailboxHash}, backends::{AccountHash, Mailbox, MailboxHash},
email::{attachment_types::*, attachments::*}, email::{attachment_types::*, attachments::*},
text::{TextProcessing, Truncate},
thread::ThreadNodeHash, thread::ThreadNodeHash,
}; };
use uuid::Uuid;
use super::*; use super::*;
use crate::{
melib::text::{TextProcessing, Truncate}, pub type AttachmentBoxFuture = Pin<Box<dyn Future<Output = Result<AttachmentBuilder>> + Send>>;
uuid::Uuid, pub type AttachmentFilterBox = Box<dyn FnOnce(AttachmentBuilder) -> AttachmentBoxFuture + Send>;
};
pub mod listing; pub mod listing;
pub use crate::listing::*; pub use crate::listing::*;

@ -888,6 +888,8 @@ impl Component for Composer {
self.gpg_state.sign_mail = self.gpg_state.sign_mail =
Some(*account_settings!(context[self.account_hash].pgp.auto_sign)); Some(*account_settings!(context[self.account_hash].pgp.auto_sign));
} }
self.gpg_state.encrypt_for_self =
*account_settings!(context[self.account_hash].pgp.encrypt_for_self);
if !self.draft.headers().contains_key(HeaderName::FROM) if !self.draft.headers().contains_key(HeaderName::FROM)
|| self.draft.headers()[HeaderName::FROM].is_empty() || self.draft.headers()[HeaderName::FROM].is_empty()
{ {
@ -2564,16 +2566,7 @@ pub fn send_draft_async(
let format_flowed = *account_settings!(context[account_hash].composing.format_flowed); let format_flowed = *account_settings!(context[account_hash].composing.format_flowed);
let event_sender = context.main_loop_handler.sender.clone(); let event_sender = context.main_loop_handler.sender.clone();
#[cfg(feature = "gpgme")] #[cfg(feature = "gpgme")]
#[allow(clippy::type_complexity)] let mut filters_stack: Vec<AttachmentFilterBox> = vec![];
let mut filters_stack: Vec<
Box<
dyn FnOnce(
AttachmentBuilder,
)
-> Pin<Box<dyn Future<Output = Result<AttachmentBuilder>> + Send>>
+ Send,
>,
> = vec![];
#[cfg(feature = "gpgme")] #[cfg(feature = "gpgme")]
if gpg_state.sign_mail.unwrap_or(ActionFlag::False).is_true() if gpg_state.sign_mail.unwrap_or(ActionFlag::False).is_true()
&& !gpg_state && !gpg_state
@ -2623,13 +2616,14 @@ pub fn send_draft_async(
let send_mail = account_settings!(context[account_hash].send_mail).clone(); let send_mail = account_settings!(context[account_hash].send_mail).clone();
let send_cb = context.accounts[&account_hash].send_async(send_mail); let send_cb = context.accounts[&account_hash].send_async(send_mail);
let mut content_type = ContentType::default(); let mut content_type = ContentType::default();
if format_flowed { if let (
if let ContentType::Text { true,
ContentType::Text {
ref mut parameters, .. ref mut parameters, ..
} = content_type },
{ ) = (format_flowed, &mut content_type)
parameters.push((b"format".to_vec(), b"flowed".to_vec())); {
} parameters.push((b"format".to_vec(), b"flowed".to_vec()));
} }
let mut body: AttachmentBuilder = Attachment::new( let mut body: AttachmentBuilder = Attachment::new(
content_type, content_type,

@ -23,7 +23,6 @@ use std::{
collections::{hash_map::DefaultHasher, BTreeMap}, collections::{hash_map::DefaultHasher, BTreeMap},
future::Future, future::Future,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
pin::Pin,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -38,6 +37,8 @@ use melib::{
parser::BytesExt, parser::BytesExt,
}; };
use super::AttachmentBoxFuture;
pub async fn decrypt(raw: Vec<u8>) -> Result<(melib_pgp::DecryptionMetadata, Vec<u8>)> { pub async fn decrypt(raw: Vec<u8>) -> Result<(melib_pgp::DecryptionMetadata, Vec<u8>)> {
let mut ctx = Context::new()?; let mut ctx = Context::new()?;
let cipher = ctx.new_data_mem(&raw)?; let cipher = ctx.new_data_mem(&raw)?;
@ -88,31 +89,47 @@ pub fn sign_filter(
Box::pin(async move { Box::pin(async move {
if let Some(default_key) = default_key { if let Some(default_key) = default_key {
let mut ctx = Context::new()?; let mut ctx = Context::new()?;
let data = ctx.new_data_mem(&melib_pgp::convert_attachment_to_rfc_spec( ctx.set_auto_key_locate(LocateKey::LOCAL)?;
a.into_raw().as_bytes(), let keys = ctx.keylist(false, Some(default_key.clone()))?.await?;
))?; if keys.is_empty() {
let sig_attachment = Attachment::new( return Err(Error::new(format!(
ContentType::PGPSignature, "Could not locate sign key with ID `{}`",
Default::default(), default_key
ctx.sign(sign_keys, data)?.await?, )));
); }
let a: AttachmentBuilder = a.into(); sign_keys.extend(keys);
let parts = vec![a, sig_attachment.into()]; }
let boundary = ContentType::make_boundary(&parts); if sign_keys.is_empty() {
Ok(Attachment::new( return Err(Error::new(
ContentType::Multipart { "No key was selected for signing; please select one.",
boundary: boundary.into_bytes(), ));
kind: MultipartType::Signed, }
parts: parts.into_iter().map(|a| a.into()).collect::<Vec<_>>(), let a: Attachment = a.into();
parameters: vec![], let mut ctx = Context::new()?;
}, let data = ctx.new_data_mem(&melib_pgp::convert_attachment_to_rfc_spec(
Default::default(), a.into_raw().as_bytes(),
vec![], ))?;
) let sig_attachment = Attachment::new(
.into()) ContentType::PGPSignature,
}) Default::default(),
}, ctx.sign(sign_keys, data)?.await?,
) );
let a: AttachmentBuilder = a.into();
let parts = vec![a, sig_attachment.into()];
let boundary = ContentType::make_boundary(&parts);
Ok(Attachment::new(
ContentType::Multipart {
boundary: boundary.into_bytes(),
kind: MultipartType::Signed,
parts: parts.into_iter().map(|a| a.into()).collect::<Vec<_>>(),
parameters: vec![],
},
Default::default(),
vec![],
)
.into())
})
})
} }
pub fn encrypt_filter( pub fn encrypt_filter(
@ -166,37 +183,62 @@ pub fn encrypt_filter(
} }
if let Some(encrypt_for_self) = encrypt_for_self { if let Some(encrypt_for_self) = encrypt_for_self {
let mut ctx = Context::new()?; let mut ctx = Context::new()?;
let data = ctx.new_data_mem( ctx.set_auto_key_locate(LocateKey::LOCAL)?;
a.into_raw().as_bytes() let keys = ctx
)?; .keylist(false, Some(encrypt_for_self.to_string()))?
.await?;
let sig_attachment = { if keys.is_empty() {
let mut a = Attachment::new( return Err(Error::new(format!(
ContentType::OctetStream { name: None, parameters: vec![] }, "Could not locate personal encryption key for address `{}`",
Default::default(), encrypt_for_self
ctx.encrypt(sign_keys, encrypt_keys, data)?.await?, )));
); }
a.content_disposition = ContentDisposition::from(br#"attachment; filename="msg.asc""#); for key in keys {
a if !encrypt_keys.contains(&key) {
}; encrypt_keys.push(key);
let mut a: AttachmentBuilder = AttachmentBuilder::new(b"Version: 1\n"); }
}
}
let a: Attachment = a.into();
log::trace!(
"main attachment is {:?} sign_keys = {:?} encrypt_keys = {:?}",
&a,
&sign_keys,
&encrypt_keys
);
let mut ctx = Context::new()?;
let data = ctx.new_data_mem(a.into_raw().as_bytes())?;
a.set_content_type_from_bytes(b"application/pgp-encrypted"); let enc_attachment = {
a.set_content_disposition(ContentDisposition::from(b"attachment")); let mut a = Attachment::new(
let parts = vec![a, sig_attachment.into()]; ContentType::OctetStream {
let boundary = ContentType::make_boundary(&parts); name: None,
Ok(Attachment::new(
ContentType::Multipart {
boundary: boundary.into_bytes(),
kind: MultipartType::Encrypted,
parts: parts.into_iter().map(|a| a.into()).collect::<Vec<_>>(),
parameters: vec![], parameters: vec![],
}, },
Default::default(), Default::default(),
vec![], ctx.encrypt(sign_keys, encrypt_keys, data)?.await?,
) );
.into()) a.content_disposition =
}) ContentDisposition::from(br#"attachment; filename="msg.asc""#);
}, a
) };
let mut a: AttachmentBuilder = AttachmentBuilder::new(b"Version: 1\n");
a.set_content_type_from_bytes(b"application/pgp-encrypted");
a.set_content_disposition(ContentDisposition::from(b"attachment"));
let parts = vec![a, enc_attachment.into()];
let boundary = ContentType::make_boundary(&parts);
Ok(Attachment::new(
ContentType::Multipart {
boundary: boundary.into_bytes(),
kind: MultipartType::Encrypted,
parts: parts.into_iter().map(|a| a.into()).collect::<Vec<_>>(),
parameters: vec![],
},
Default::default(),
vec![],
)
.into())
})
})
} }

Loading…
Cancel
Save