Sign encrypted mails.
- Husk now not only encrypts outgoing emails (if possible) but also adds a signature. - Rework the internal handling of the signing key. - Integrate the signing into the workflow of the daemon. - Add a configuration option for a subject replacement.
This commit is contained in:
Generated
+6
-10
@@ -2586,8 +2586,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sequoia-keystore"
|
name = "sequoia-keystore"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://gitlab.com/sequoia-pgp/sequoia-keystore?branch=malte%2Fsoftkey-refresh#cc77f2ea46ab1c3ca1ace0c16848a4137e67bdf7"
|
||||||
checksum = "50e5887d0c3c5f0df1d1cab937ef7a5c398111ddfd911c714f28c904438f229c"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-generic",
|
"async-generic",
|
||||||
@@ -2603,7 +2602,7 @@ dependencies = [
|
|||||||
"sequoia-keystore-gpg-agent",
|
"sequoia-keystore-gpg-agent",
|
||||||
"sequoia-keystore-softkeys",
|
"sequoia-keystore-softkeys",
|
||||||
"sequoia-openpgp",
|
"sequoia-openpgp",
|
||||||
"thiserror 2.0.18",
|
"thiserror 1.0.69",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
]
|
]
|
||||||
@@ -2611,8 +2610,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sequoia-keystore-backend"
|
name = "sequoia-keystore-backend"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://gitlab.com/sequoia-pgp/sequoia-keystore?branch=malte%2Fsoftkey-refresh#cc77f2ea46ab1c3ca1ace0c16848a4137e67bdf7"
|
||||||
checksum = "c55b047f9b6412c34dc7a26a42f278205cbf1e29516feab1228edccca215f500"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -2621,15 +2619,14 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"sequoia-openpgp",
|
"sequoia-openpgp",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror 2.0.18",
|
"thiserror 1.0.69",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sequoia-keystore-gpg-agent"
|
name = "sequoia-keystore-gpg-agent"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://gitlab.com/sequoia-pgp/sequoia-keystore?branch=malte%2Fsoftkey-refresh#cc77f2ea46ab1c3ca1ace0c16848a4137e67bdf7"
|
||||||
checksum = "7ad901f1f1d88b38f5f5738d5bf2b80136ec44e94a40716193be0bbf3314df2b"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -2646,8 +2643,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sequoia-keystore-softkeys"
|
name = "sequoia-keystore-softkeys"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://gitlab.com/sequoia-pgp/sequoia-keystore?branch=malte%2Fsoftkey-refresh#cc77f2ea46ab1c3ca1ace0c16848a4137e67bdf7"
|
||||||
checksum = "9e5c4944848f748ce22875020e9cff9e604d52c563aef8e19053f5abe037139e"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|||||||
+2
-1
@@ -21,7 +21,8 @@ log = "0.4.30"
|
|||||||
log4rs = "1.3.0"
|
log4rs = "1.3.0"
|
||||||
sequoia-cert-store = "0.7.3"
|
sequoia-cert-store = "0.7.3"
|
||||||
sequoia-directories = "0.1.0"
|
sequoia-directories = "0.1.0"
|
||||||
sequoia-keystore = "0.7.2"
|
#sequoia-keystore = "0.7.2"
|
||||||
|
sequoia-keystore = { git = "https://gitlab.com/sequoia-pgp/sequoia-keystore", branch = "malte/softkey-refresh" }
|
||||||
sequoia-net = "0.30.1"
|
sequoia-net = "0.30.1"
|
||||||
sequoia-openpgp = "2.3.0"
|
sequoia-openpgp = "2.3.0"
|
||||||
sequoia-wot = "0.15.0"
|
sequoia-wot = "0.15.0"
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ send_test_mail() { # email_address
|
|||||||
chown $USER:mail /var/mail/$USER
|
chown $USER:mail /var/mail/$USER
|
||||||
chmod 600 /var/mail/$USER
|
chmod 600 /var/mail/$USER
|
||||||
|
|
||||||
echo "test mail" | sendmail $1
|
echo -e "Subject: testmail\n\ntest mail" | sendmail $1
|
||||||
inotifywait -qq -t 3 -e close_write /var/mail/$USER
|
inotifywait -qq -t 3 -e close_write /var/mail/$USER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
# source some functions
|
||||||
|
. common.sh
|
||||||
|
|
||||||
|
test_header "Signing"
|
||||||
|
|
||||||
|
# sq key generate --shared-key --without-password --email 'signing@example.com' --output /tmp/signing.pgp --rev-cert /tmp/signing.rev
|
||||||
|
|
||||||
|
SIGN_FPR=$(sq key generate --own-key --without-password --name "Signing Key" 2>&1 | grep "Fingerprint:" | cut -d ':' -f 2)
|
||||||
|
|
||||||
|
cd $HUSK_DIR
|
||||||
|
|
||||||
|
$HUSK_BIN --config config/config.toml signkey set --cert $SIGN_FPR
|
||||||
|
SIGN_FPR=$($HUSK_BIN --config config/config.toml signkey show | cut -d ':' -f 2 | tr -d ' ')
|
||||||
|
echo "found signing key $SIGN_FPR"
|
||||||
|
|
||||||
|
create_unix_user juliette
|
||||||
|
JULIETTE_FPR=$(sq key generate --own-key --without-password --name "Juliette" --email "juliette@example.com" 2>&1 | grep "Fingerprint:" | cut -d ':' -f 2)
|
||||||
|
sq pki vouch add --certifier-userid "CA" --cert $JULIETTE_FPR --all > /dev/null 2>&1
|
||||||
|
|
||||||
|
# send a mail, husk should encrypt it
|
||||||
|
echo "send mail to juliette@example.com"
|
||||||
|
send_test_mail juliette@example.com
|
||||||
|
|
||||||
|
if [ -f /var/mail/juliette ] ; then
|
||||||
|
if grep -q "BEGIN PGP MESSAGE" /var/mail/juliette ; then
|
||||||
|
|
||||||
|
FOUND_FPR=$(sq packet dump /var/mail/juliette | grep "Issuer Fingerprint:" | cut -d ':' -f 2 | tr -d ' ')
|
||||||
|
|
||||||
|
if [ "$SIGN_FPR" != "$FOUND_FPR" ] ; then
|
||||||
|
echo "Found wrong fingerprint '$FOUND_FPR' - expected '$SIGN_FPR'"
|
||||||
|
RESULT_CODE=1
|
||||||
|
else
|
||||||
|
RESULT_CODE=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "no encryption detected"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "no mail detected"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
+14
-4
@@ -1,6 +1,7 @@
|
|||||||
//! signkey subcommand
|
//! signkey subcommand
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use sequoia_cert_store::Store;
|
||||||
use sequoia_openpgp::serialize::SerializeInto;
|
use sequoia_openpgp::serialize::SerializeInto;
|
||||||
|
|
||||||
use crate::cli::cli_args::{SignkeyCommand, SignkeySubcommand};
|
use crate::cli::cli_args::{SignkeyCommand, SignkeySubcommand};
|
||||||
@@ -19,16 +20,25 @@ pub async fn dispatch(cmd: SignkeyCommand, config: HuskConfigContainer) -> Resul
|
|||||||
if let Some(key) = context.signing_key {
|
if let Some(key) = context.signing_key {
|
||||||
println!("Fingerprint: {}", key.fingerprint());
|
println!("Fingerprint: {}", key.fingerprint());
|
||||||
} else {
|
} else {
|
||||||
println!("No active signing key available.");
|
eprintln!("No active signing key available.");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SignkeySubcommand::Dump => {
|
SignkeySubcommand::Dump => {
|
||||||
let context = HuskContext::new(&config.into())?;
|
let context = HuskContext::new(&config.into())?;
|
||||||
if let Some(key) = context.signing_key {
|
if let Some(key) = context.signing_key {
|
||||||
let armored = key.armored().to_vec()?;
|
|
||||||
println!("{}", String::from_utf8(armored)?);
|
if let Ok(cert) = &context.cert_store.lookup_by_cert_fpr(&key.fingerprint()) {
|
||||||
|
if let Ok(cert) = cert.to_cert() {
|
||||||
|
let armored = cert.armored().to_vec()?;
|
||||||
|
println!("{}", String::from_utf8_lossy(&armored[..]));
|
||||||
|
} else {
|
||||||
|
eprintln!("Certificate {} is damaged", cert.fingerprint());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("Cannot find certificate for key {}", key.fingerprint());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("No active signing key available.");
|
eprintln!("No active signing key available.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-26
@@ -17,10 +17,11 @@ use sequoia_net::{KeyServer, wkd, dane};
|
|||||||
use sequoia_directories::Home;
|
use sequoia_directories::Home;
|
||||||
use sequoia_keystore::Keystore;
|
use sequoia_keystore::Keystore;
|
||||||
use sequoia_keystore::Context;
|
use sequoia_keystore::Context;
|
||||||
|
use sequoia_keystore::Key;
|
||||||
use sequoia_openpgp::packet::prelude::SignatureBuilder;
|
use sequoia_openpgp::packet::prelude::SignatureBuilder;
|
||||||
use sequoia_openpgp::parse::{PacketParser, PacketParserResult, Parse};
|
use sequoia_openpgp::parse::{PacketParser, PacketParserResult, Parse};
|
||||||
use sequoia_openpgp::policy::StandardPolicy;
|
use sequoia_openpgp::policy::StandardPolicy;
|
||||||
use sequoia_openpgp::serialize::stream::{Message, Armorer, Encryptor, LiteralWriter};
|
use sequoia_openpgp::serialize::stream::{Message, Armorer, Encryptor, Signer, LiteralWriter};
|
||||||
use sequoia_openpgp::{Fingerprint, Cert, Packet};
|
use sequoia_openpgp::{Fingerprint, Cert, Packet};
|
||||||
use sequoia_openpgp::cert::raw::RawCertParser;
|
use sequoia_openpgp::cert::raw::RawCertParser;
|
||||||
use sequoia_openpgp::types::SignatureType;
|
use sequoia_openpgp::types::SignatureType;
|
||||||
@@ -422,10 +423,21 @@ pub fn encrypt(context: &HuskContext<'_>, body: &[u8], recipients: &Vec<Recipien
|
|||||||
let mut sink = Vec::new();
|
let mut sink = Vec::new();
|
||||||
let message = Message::new(&mut sink);
|
let message = Message::new(&mut sink);
|
||||||
let message = Armorer::new(message).build()?;
|
let message = Armorer::new(message).build()?;
|
||||||
let message = Encryptor::for_recipients(message, keys).build()?;
|
let mut message = Encryptor::for_recipients(message, keys).build()?;
|
||||||
let mut message = LiteralWriter::new(message).build()?;
|
if let Some(key) = &context.signing_key {
|
||||||
message.write_all(body)?;
|
log::debug!("use signing key {}", key.fingerprint());
|
||||||
message.finalize()?;
|
message = Signer::new(message, key.clone())?.build()?;
|
||||||
|
}
|
||||||
|
message = LiteralWriter::new(message).build()?;
|
||||||
|
|
||||||
|
// XXX: error handling!!!
|
||||||
|
std::thread::scope(|s| {
|
||||||
|
s.spawn(|| -> anyhow::Result<()> {
|
||||||
|
message.write_all(body)?;
|
||||||
|
message.finalize()?;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Bytes::from(sink))
|
Ok(Bytes::from(sink))
|
||||||
} else {
|
} else {
|
||||||
@@ -599,7 +611,7 @@ pub fn can_sign(cert: &ValidCert) -> bool {
|
|||||||
|
|
||||||
|
|
||||||
/// Get Husks signing key
|
/// Get Husks signing key
|
||||||
pub fn get_signing_key(sequoia_home: Home, cert_store: &CertStore<'_>, policy: &StandardPolicy<'_>, local_trust_root: &Cert) -> anyhow::Result<Option<Cert>> {
|
pub fn get_signing_key(sequoia_home: Home, cert_store: &CertStore<'_>, policy: &StandardPolicy<'_>, local_trust_root: &Cert) -> anyhow::Result<Option<Key>> {
|
||||||
|
|
||||||
let local_trust_root = local_trust_root.with_policy(policy, None)?;
|
let local_trust_root = local_trust_root.with_policy(policy, None)?;
|
||||||
let local_trust_fpr = local_trust_root.fingerprint();
|
let local_trust_fpr = local_trust_root.fingerprint();
|
||||||
@@ -607,33 +619,31 @@ pub fn get_signing_key(sequoia_home: Home, cert_store: &CertStore<'_>, policy: &
|
|||||||
let mut newest = None;
|
let mut newest = None;
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
|
|
||||||
if let Some(keys) = get_all_keys(sequoia_home) {
|
let keys = get_all_keys(sequoia_home);
|
||||||
for key in keys {
|
for key in keys {
|
||||||
if let Ok(cert) = cert_store.lookup_by_cert_fpr(&key) {
|
if let Ok(cert) = cert_store.lookup_by_cert_fpr(&key.fingerprint()) {
|
||||||
if let Ok(vc) = cert.with_policy(policy, None) {
|
if let Ok(vc) = cert.with_policy(policy, None) {
|
||||||
if let Some(time) = contains_signing_key(&vc, &local_trust_fpr) {
|
if let Some(time) = contains_signing_key(&vc, &local_trust_fpr) {
|
||||||
if let Some(othertime) = newest {
|
if let Some(othertime) = newest {
|
||||||
if time > othertime {
|
if time > othertime {
|
||||||
newest = Some(time);
|
|
||||||
result = Some(vc.cert().clone());
|
|
||||||
}
|
|
||||||
} else { // first detected key
|
|
||||||
newest = Some(time);
|
newest = Some(time);
|
||||||
result = Some(vc.cert().clone());
|
result = Some(key.clone());
|
||||||
}
|
}
|
||||||
|
} else { // first detected key
|
||||||
|
newest = Some(time);
|
||||||
|
result = Some(key.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `vc` is a certificate marked as a Husk signing key, return the
|
/// If `vc` is a certificate marked as a Husk signing key, return the
|
||||||
/// creation time of the signature - else return `None`.
|
/// creation time of the signature - else return `None`.
|
||||||
pub fn contains_signing_key(vc: &ValidCert, local_root_fpr: &Fingerprint) -> Option<SystemTime> {
|
pub fn contains_signing_key(vc: &ValidCert, local_root_fpr: &Fingerprint) -> Option<SystemTime> {
|
||||||
|
log::debug!("check {} for signing key", vc.fingerprint());
|
||||||
for uid in vc.userids() {
|
for uid in vc.userids() {
|
||||||
for sig in uid.certifications() {
|
for sig in uid.certifications() {
|
||||||
if sig.issuer_fingerprints().any(|i| i == local_root_fpr)
|
if sig.issuer_fingerprints().any(|i| i == local_root_fpr)
|
||||||
@@ -641,6 +651,7 @@ pub fn contains_signing_key(vc: &ValidCert, local_root_fpr: &Fingerprint) -> Opt
|
|||||||
|
|
||||||
// ignore signatures without creation time
|
// ignore signatures without creation time
|
||||||
if let Some(time) = sig.signature_creation_time() {
|
if let Some(time) = sig.signature_creation_time() {
|
||||||
|
log::debug!("found");
|
||||||
return Some(time);
|
return Some(time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -651,7 +662,7 @@ pub fn contains_signing_key(vc: &ValidCert, local_root_fpr: &Fingerprint) -> Opt
|
|||||||
|
|
||||||
/// Get all keys from all backends
|
/// Get all keys from all backends
|
||||||
// XXX: Maybe the softkeys backend is sufficient
|
// XXX: Maybe the softkeys backend is sufficient
|
||||||
pub fn get_all_keys(sequoia_home: Home) -> Option<Vec<Fingerprint>> {
|
pub fn get_all_keys(sequoia_home: Home) -> Vec<Key> {
|
||||||
|
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
std::thread::scope(|s| {
|
std::thread::scope(|s| {
|
||||||
@@ -660,14 +671,14 @@ pub fn get_all_keys(sequoia_home: Home) -> Option<Vec<Fingerprint>> {
|
|||||||
.home(sequoia_home.data_dir(sequoia_directories::Component::Keystore))
|
.home(sequoia_home.data_dir(sequoia_directories::Component::Keystore))
|
||||||
.build() {
|
.build() {
|
||||||
if let Ok(mut keystore) = Keystore::connect(&keystore_base) {
|
if let Ok(mut keystore) = Keystore::connect(&keystore_base) {
|
||||||
|
|
||||||
if let Ok(mut backends) = keystore.backends() {
|
if let Ok(mut backends) = keystore.backends() {
|
||||||
for backend in &mut backends {
|
for backend in &mut backends {
|
||||||
|
log::debug!("scanning backend {:?}", backend.id());
|
||||||
if let Ok(devices) = backend.devices() {
|
if let Ok(devices) = backend.devices() {
|
||||||
for mut device in devices {
|
for mut device in devices {
|
||||||
if let Ok(keys) = device.keys() {
|
if let Ok(keys) = device.keys() {
|
||||||
keys.iter().for_each(|k| {
|
keys.iter().for_each(|k| {
|
||||||
result.push(k.fingerprint());
|
result.push(k.clone());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -678,7 +689,7 @@ pub fn get_all_keys(sequoia_home: Home) -> Option<Vec<Fingerprint>> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Some(result)
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -821,6 +832,7 @@ jk6lh01Ej9QTGQ==
|
|||||||
signing_key: None,
|
signing_key: None,
|
||||||
introducers: Vec::new(),
|
introducers: Vec::new(),
|
||||||
keyservers: Vec::new(),
|
keyservers: Vec::new(),
|
||||||
|
subject_replacement: "...".into(),
|
||||||
mail: MailContext::new()
|
mail: MailContext::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -836,7 +848,7 @@ jk6lh01Ej9QTGQ==
|
|||||||
softkeys.import(&signing_key)?;
|
softkeys.import(&signing_key)?;
|
||||||
|
|
||||||
let keys= get_all_keys(home.clone());
|
let keys= get_all_keys(home.clone());
|
||||||
eprintln!("{:?}", keys);
|
for key in keys { eprintln!("{}", key.fingerprint()); }
|
||||||
|
|
||||||
super::set_signing_key(&context, &valid_signing_cert)?;
|
super::set_signing_key(&context, &valid_signing_cert)?;
|
||||||
|
|
||||||
|
|||||||
+29
-1
@@ -9,13 +9,14 @@ use toml;
|
|||||||
use log4rs;
|
use log4rs;
|
||||||
|
|
||||||
use crate::types::errors::HuskError;
|
use crate::types::errors::HuskError;
|
||||||
use crate::types::defaults::CONSOLE_LOGGING;
|
use crate::types::defaults::{CONSOLE_LOGGING, SUBJECT_REPLACEMENT};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct HuskConfig {
|
pub struct HuskConfig {
|
||||||
pub connection: String,
|
pub connection: String,
|
||||||
pub sequoia_home: String,
|
pub sequoia_home: String,
|
||||||
pub keyservers: Option<Vec<String>>,
|
pub keyservers: Option<Vec<String>>,
|
||||||
|
pub subject_replacement: Option<String>,
|
||||||
logging: Option<toml::Value>,
|
logging: Option<toml::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +69,13 @@ impl HuskConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_subject_replacement(&self) -> String {
|
||||||
|
if let Some(replacement) = &self.subject_replacement {
|
||||||
|
replacement.clone()
|
||||||
|
} else {
|
||||||
|
SUBJECT_REPLACEMENT.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type HuskConfigContainer = Arc<Mutex<HuskConfig>>;
|
pub type HuskConfigContainer = Arc<Mutex<HuskConfig>>;
|
||||||
@@ -79,3 +87,23 @@ impl From<HuskConfigContainer> for HuskConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::types::defaults;
|
||||||
|
|
||||||
|
use super::HuskConfig;
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subject_line() {
|
||||||
|
let config = HuskConfig {
|
||||||
|
connection: "".into(),
|
||||||
|
sequoia_home: "".into(),
|
||||||
|
keyservers: None,
|
||||||
|
subject_replacement: None,
|
||||||
|
logging: None
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(config.get_subject_replacement(), defaults::SUBJECT_REPLACEMENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -241,6 +241,11 @@ impl Daemon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Change the subject
|
||||||
|
let _ = cx.actions.change_header(
|
||||||
|
"Subject",
|
||||||
|
1,
|
||||||
|
Some(context.subject_replacement.clone())).await;
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{}", e);
|
log::error!("{}", e);
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
//! Defaults
|
//! Defaults
|
||||||
|
|
||||||
pub const CONFIG_FILE_LOCATION: &'static str = "/etc/husk/config.toml";
|
pub const CONFIG_FILE_LOCATION: &str = "/etc/husk/config.toml";
|
||||||
|
|
||||||
|
/// If encrypting a mail, the subject is moved into the encrypted body
|
||||||
|
/// and replaced by `SUBJECT_REPLACEMENT` (unless configured otherwise).
|
||||||
|
pub const SUBJECT_REPLACEMENT: &str = "...";
|
||||||
|
|
||||||
/// Default logging configuration.
|
/// Default logging configuration.
|
||||||
pub const CONSOLE_LOGGING: &'static str = "
|
pub const CONSOLE_LOGGING: &str = "
|
||||||
[appenders.console]
|
[appenders.console]
|
||||||
kind = \"console\"
|
kind = \"console\"
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use sequoia_openpgp::policy::StandardPolicy;
|
|||||||
use sequoia_openpgp::Cert;
|
use sequoia_openpgp::Cert;
|
||||||
use sequoia_cert_store::CertStore;
|
use sequoia_cert_store::CertStore;
|
||||||
use sequoia_directories::Home;
|
use sequoia_directories::Home;
|
||||||
|
use sequoia_keystore::Key;
|
||||||
|
|
||||||
use crate::config::HuskConfig;
|
use crate::config::HuskConfig;
|
||||||
use crate::common::crypto;
|
use crate::common::crypto;
|
||||||
@@ -26,9 +27,10 @@ pub struct HuskContext<'hc> {
|
|||||||
pub policy: StandardPolicy<'hc>,
|
pub policy: StandardPolicy<'hc>,
|
||||||
pub cert_store: CertStore<'hc>,
|
pub cert_store: CertStore<'hc>,
|
||||||
pub local_trust_root: Cert,
|
pub local_trust_root: Cert,
|
||||||
pub signing_key: Option<Cert>,
|
pub signing_key: Option<Key>,
|
||||||
pub introducers: Vec<Introducer>,
|
pub introducers: Vec<Introducer>,
|
||||||
pub keyservers: Vec<String>,
|
pub keyservers: Vec<String>,
|
||||||
|
pub subject_replacement: String,
|
||||||
pub mail: MailContext<'hc>,
|
pub mail: MailContext<'hc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,9 +50,13 @@ impl<'hc> HuskContext<'hc> {
|
|||||||
|
|
||||||
let signing_key = match crypto::get_signing_key(sequoia_home, &cert_store, &policy, &local_trust_root) {
|
let signing_key = match crypto::get_signing_key(sequoia_home, &cert_store, &policy, &local_trust_root) {
|
||||||
Ok(Some(cert)) => Some(cert),
|
Ok(Some(cert)) => Some(cert),
|
||||||
_ => {
|
Ok(None) => {
|
||||||
log::warn!("No signing key found");
|
log::warn!("No signing key found");
|
||||||
None
|
None
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Error while fetching signing key: {}", e);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -61,6 +67,7 @@ impl<'hc> HuskContext<'hc> {
|
|||||||
signing_key,
|
signing_key,
|
||||||
introducers,
|
introducers,
|
||||||
keyservers: config.get_keyservers(),
|
keyservers: config.get_keyservers(),
|
||||||
|
subject_replacement: config.get_subject_replacement(),
|
||||||
mail: MailContext::new(),
|
mail: MailContext::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user