Use anyhow for key.rs error handling

This commit is contained in:
link2xt
2021-06-19 03:19:04 +03:00
parent a47c0486ae
commit 8ea773628d
6 changed files with 19 additions and 94 deletions

View File

@@ -4,46 +4,22 @@ use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::io::Cursor; use std::io::Cursor;
use anyhow::{format_err, Result};
use async_trait::async_trait; use async_trait::async_trait;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use pgp::composed::Deserializable; use pgp::composed::Deserializable;
use pgp::ser::Serialize; use pgp::ser::Serialize;
use pgp::types::{KeyTrait, SecretKeyTrait}; use pgp::types::{KeyTrait, SecretKeyTrait};
use thiserror::Error;
use crate::config::Config; use crate::config::Config;
use crate::constants::KeyGenType; use crate::constants::KeyGenType;
use crate::context::Context; use crate::context::Context;
use crate::dc_tools::{time, EmailAddress, InvalidEmailError}; use crate::dc_tools::{time, EmailAddress};
// Re-export key types // Re-export key types
pub use crate::pgp::KeyPair; pub use crate::pgp::KeyPair;
pub use pgp::composed::{SignedPublicKey, SignedSecretKey}; pub use pgp::composed::{SignedPublicKey, SignedSecretKey};
/// Error type for deltachat key handling.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("Could not decode base64")]
Base64Decode(#[from] base64::DecodeError),
#[error("rPGP error: {}", _0)]
Pgp(#[from] pgp::errors::Error),
#[error("Failed to generate PGP key: {}", _0)]
Keygen(#[from] crate::pgp::PgpKeygenError),
#[error("Failed to save generated key: {}", _0)]
StoreKey(#[from] SaveKeyError),
#[error("No address configured")]
NoConfiguredAddr,
#[error("Configured address is invalid: {}", _0)]
InvalidConfiguredAddr(#[from] InvalidEmailError),
#[error("no data provided")]
Empty,
#[error("{0}")]
Other(#[from] anyhow::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
/// Convenience trait for working with keys. /// Convenience trait for working with keys.
/// ///
/// This trait is implemented for rPGP's [SignedPublicKey] and /// This trait is implemented for rPGP's [SignedPublicKey] and
@@ -74,7 +50,8 @@ pub trait DcKey: Serialize + Deserializable + KeyTrait + Clone {
/// the ASCII-armored representation. /// the ASCII-armored representation.
fn from_asc(data: &str) -> Result<(Self::KeyType, BTreeMap<String, String>)> { fn from_asc(data: &str) -> Result<(Self::KeyType, BTreeMap<String, String>)> {
let bytes = data.as_bytes(); let bytes = data.as_bytes();
Self::KeyType::from_armor_single(Cursor::new(bytes)).map_err(Error::Pgp) Self::KeyType::from_armor_single(Cursor::new(bytes))
.map_err(|err| format_err!("rPGP error: {}", err))
} }
/// Load the users' default key from the database. /// Load the users' default key from the database.
@@ -225,7 +202,7 @@ async fn generate_keypair(context: &Context) -> Result<KeyPair> {
let addr = context let addr = context
.get_config(Config::ConfiguredAddr) .get_config(Config::ConfiguredAddr)
.await? .await?
.ok_or(Error::NoConfiguredAddr)?; .ok_or_else(|| format_err!("No address configured"))?;
let addr = EmailAddress::new(&addr)?; let addr = EmailAddress::new(&addr)?;
let _guard = context.generating_key_mutex.lock().await; let _guard = context.generating_key_mutex.lock().await;
@@ -284,24 +261,6 @@ pub enum KeyPairUse {
ReadOnly, ReadOnly,
} }
/// Error saving a keypair to the database.
#[derive(Debug, thiserror::Error)]
#[error("SaveKeyError: {message}")]
pub struct SaveKeyError {
message: String,
#[source]
cause: anyhow::Error,
}
impl SaveKeyError {
fn new(message: impl Into<String>, cause: impl Into<anyhow::Error>) -> Self {
Self {
message: message.into(),
cause: cause.into(),
}
}
}
/// Store the keypair as an owned keypair for addr in the database. /// Store the keypair as an owned keypair for addr in the database.
/// ///
/// This will save the keypair as keys for the given address. The /// This will save the keypair as keys for the given address. The
@@ -318,7 +277,7 @@ pub async fn store_self_keypair(
context: &Context, context: &Context,
keypair: &KeyPair, keypair: &KeyPair,
default: KeyPairUse, default: KeyPairUse,
) -> std::result::Result<(), SaveKeyError> { ) -> Result<()> {
// Everything should really be one transaction, more refactoring // Everything should really be one transaction, more refactoring
// is needed for that. // is needed for that.
let public_key = DcKey::to_bytes(&keypair.public); let public_key = DcKey::to_bytes(&keypair.public);
@@ -330,13 +289,13 @@ pub async fn store_self_keypair(
paramsv![public_key, secret_key], paramsv![public_key, secret_key],
) )
.await .await
.map_err(|err| SaveKeyError::new("failed to remove old use of key", err))?; .map_err(|err| err.context("failed to remove old use of key"))?;
if default == KeyPairUse::Default { if default == KeyPairUse::Default {
context context
.sql .sql
.execute("UPDATE keypairs SET is_default=0;", paramsv![]) .execute("UPDATE keypairs SET is_default=0;", paramsv![])
.await .await
.map_err(|err| SaveKeyError::new("failed to clear default", err))?; .map_err(|err| err.context("failed to clear default"))?;
} }
let is_default = match default { let is_default = match default {
KeyPairUse::Default => true as i32, KeyPairUse::Default => true as i32,
@@ -354,7 +313,7 @@ pub async fn store_self_keypair(
paramsv![addr, is_default, public_key, secret_key, t], paramsv![addr, is_default, public_key, secret_key, t],
) )
.await .await
.map_err(|err| SaveKeyError::new("failed to insert keypair", err))?; .map_err(|err| err.context("failed to insert keypair"))?;
Ok(()) Ok(())
} }
@@ -364,10 +323,10 @@ pub async fn store_self_keypair(
pub struct Fingerprint(Vec<u8>); pub struct Fingerprint(Vec<u8>);
impl Fingerprint { impl Fingerprint {
pub fn new(v: Vec<u8>) -> std::result::Result<Fingerprint, FingerprintError> { pub fn new(v: Vec<u8>) -> Result<Fingerprint> {
match v.len() { match v.len() {
20 => Ok(Fingerprint(v)), 20 => Ok(Fingerprint(v)),
_ => Err(FingerprintError::WrongLength), _ => Err(format_err!("Wrong fingerprint length")),
} }
} }
@@ -406,7 +365,7 @@ impl fmt::Display for Fingerprint {
/// Parse a human-readable or otherwise formatted fingerprint. /// Parse a human-readable or otherwise formatted fingerprint.
impl std::str::FromStr for Fingerprint { impl std::str::FromStr for Fingerprint {
type Err = FingerprintError; type Err = anyhow::Error;
fn from_str(input: &str) -> std::result::Result<Self, Self::Err> { fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
let hex_repr: String = input let hex_repr: String = input
@@ -420,21 +379,11 @@ impl std::str::FromStr for Fingerprint {
} }
} }
#[derive(Debug, Error)]
pub enum FingerprintError {
#[error("Invalid hex characters")]
NotHex(#[from] hex::FromHexError),
#[error("Incorrect fingerprint lengths")]
WrongLength,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::test_utils::{alice_keypair, TestContext}; use crate::test_utils::{alice_keypair, TestContext};
use std::error::Error;
use async_std::sync::Arc; use async_std::sync::Arc;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@@ -676,13 +625,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
.unwrap(); .unwrap();
assert_eq!(fp, res); assert_eq!(fp, res);
let err = "1".parse::<Fingerprint>().err().unwrap(); assert!("1".parse::<Fingerprint>().is_err());
match err {
FingerprintError::NotHex(_) => (),
_ => panic!("Wrong error"),
}
let src_err = err.source().unwrap().downcast_ref::<hex::FromHexError>();
assert_eq!(src_err, Some(&hex::FromHexError::OddLength));
} }
#[test] #[test]

View File

@@ -3,7 +3,7 @@
use anyhow::Result; use anyhow::Result;
use crate::context::Context; use crate::context::Context;
use crate::key::{self, DcKey}; use crate::key::DcKey;
/// An in-memory keyring. /// An in-memory keyring.
/// ///
@@ -27,14 +27,14 @@ where
} }
/// Create a new keyring with the the user's secret key loaded. /// Create a new keyring with the the user's secret key loaded.
pub async fn new_self(context: &Context) -> Result<Keyring<T>, key::Error> { pub async fn new_self(context: &Context) -> Result<Keyring<T>> {
let mut keyring: Keyring<T> = Keyring::new(); let mut keyring: Keyring<T> = Keyring::new();
keyring.load_self(context).await?; keyring.load_self(context).await?;
Ok(keyring) Ok(keyring)
} }
/// Load the user's key into the keyring. /// Load the user's key into the keyring.
pub async fn load_self(&mut self, context: &Context) -> Result<(), key::Error> { pub async fn load_self(&mut self, context: &Context) -> Result<()> {
self.add(T::load_self(context).await?); self.add(T::load_self(context).await?);
Ok(()) Ok(())
} }

View File

@@ -493,12 +493,6 @@ impl Peerstate {
} }
} }
impl From<crate::key::FingerprintError> for rusqlite::Error {
fn from(_source: crate::key::FingerprintError) -> Self {
Self::InvalidColumnType(0, "Invalid fingerprint".into(), rusqlite::types::Type::Text)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@@ -86,11 +86,7 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Lot {
}; };
let fingerprint: Fingerprint = match fingerprint.parse() { let fingerprint: Fingerprint = match fingerprint.parse() {
Ok(fp) => fp, Ok(fp) => fp,
Err(err) => { Err(err) => return err.context("Failed to parse fingerprint in QR code").into(),
return Error::new(err)
.context("Failed to parse fingerprint in QR code")
.into()
}
}; };
let param: BTreeMap<&str, &str> = fragment let param: BTreeMap<&str, &str> = fragment

View File

@@ -17,7 +17,7 @@ use crate::context::Context;
use crate::e2ee::ensure_secret_key_exists; use crate::e2ee::ensure_secret_key_exists;
use crate::events::EventType; use crate::events::EventType;
use crate::headerdef::HeaderDef; use crate::headerdef::HeaderDef;
use crate::key::{self, DcKey, Fingerprint, SignedPublicKey}; use crate::key::{DcKey, Fingerprint, SignedPublicKey};
use crate::message::Message; use crate::message::Message;
use crate::mimeparser::{MimeMessage, SystemMessage}; use crate::mimeparser::{MimeMessage, SystemMessage};
use crate::param::Param; use crate::param::Param;
@@ -355,12 +355,6 @@ async fn securejoin(context: &Context, qr: &str) -> Result<ChatId, JoinError> {
#[error("Failed sending handshake message")] #[error("Failed sending handshake message")]
pub struct SendMsgError(#[from] anyhow::Error); pub struct SendMsgError(#[from] anyhow::Error);
impl From<key::Error> for SendMsgError {
fn from(source: key::Error) -> Self {
Self(anyhow::Error::new(source))
}
}
async fn send_handshake_msg( async fn send_handshake_msg(
context: &Context, context: &Context,
contact_chat_id: ChatId, contact_chat_id: ChatId,

View File

@@ -9,7 +9,7 @@ use std::convert::TryFrom;
use anyhow::Result; use anyhow::Result;
use crate::key::{Fingerprint, FingerprintError}; use crate::key::Fingerprint;
use crate::lot::{Lot, LotState}; use crate::lot::{Lot, LotState};
/// Represents the data from a QR-code scan. /// Represents the data from a QR-code scan.
@@ -103,8 +103,6 @@ impl TryFrom<Lot> for QrInvite {
pub enum QrError { pub enum QrError {
#[error("Unsupported protocol in QR-code")] #[error("Unsupported protocol in QR-code")]
UnsupportedProtocol, UnsupportedProtocol,
#[error("Failed to read fingerprint")]
InvalidFingerprint(#[from] FingerprintError),
#[error("Missing fingerprint")] #[error("Missing fingerprint")]
MissingFingerprint, MissingFingerprint,
#[error("Missing invitenumber")] #[error("Missing invitenumber")]