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::io::Cursor;
use anyhow::{format_err, Result};
use async_trait::async_trait;
use num_traits::FromPrimitive;
use pgp::composed::Deserializable;
use pgp::ser::Serialize;
use pgp::types::{KeyTrait, SecretKeyTrait};
use thiserror::Error;
use crate::config::Config;
use crate::constants::KeyGenType;
use crate::context::Context;
use crate::dc_tools::{time, EmailAddress, InvalidEmailError};
use crate::dc_tools::{time, EmailAddress};
// Re-export key types
pub use crate::pgp::KeyPair;
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.
///
/// This trait is implemented for rPGP's [SignedPublicKey] and
@@ -74,7 +50,8 @@ pub trait DcKey: Serialize + Deserializable + KeyTrait + Clone {
/// the ASCII-armored representation.
fn from_asc(data: &str) -> Result<(Self::KeyType, BTreeMap<String, String>)> {
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.
@@ -225,7 +202,7 @@ async fn generate_keypair(context: &Context) -> Result<KeyPair> {
let addr = context
.get_config(Config::ConfiguredAddr)
.await?
.ok_or(Error::NoConfiguredAddr)?;
.ok_or_else(|| format_err!("No address configured"))?;
let addr = EmailAddress::new(&addr)?;
let _guard = context.generating_key_mutex.lock().await;
@@ -284,24 +261,6 @@ pub enum KeyPairUse {
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.
///
/// This will save the keypair as keys for the given address. The
@@ -318,7 +277,7 @@ pub async fn store_self_keypair(
context: &Context,
keypair: &KeyPair,
default: KeyPairUse,
) -> std::result::Result<(), SaveKeyError> {
) -> Result<()> {
// Everything should really be one transaction, more refactoring
// is needed for that.
let public_key = DcKey::to_bytes(&keypair.public);
@@ -330,13 +289,13 @@ pub async fn store_self_keypair(
paramsv![public_key, secret_key],
)
.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 {
context
.sql
.execute("UPDATE keypairs SET is_default=0;", paramsv![])
.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 {
KeyPairUse::Default => true as i32,
@@ -354,7 +313,7 @@ pub async fn store_self_keypair(
paramsv![addr, is_default, public_key, secret_key, t],
)
.await
.map_err(|err| SaveKeyError::new("failed to insert keypair", err))?;
.map_err(|err| err.context("failed to insert keypair"))?;
Ok(())
}
@@ -364,10 +323,10 @@ pub async fn store_self_keypair(
pub struct Fingerprint(Vec<u8>);
impl Fingerprint {
pub fn new(v: Vec<u8>) -> std::result::Result<Fingerprint, FingerprintError> {
pub fn new(v: Vec<u8>) -> Result<Fingerprint> {
match v.len() {
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.
impl std::str::FromStr for Fingerprint {
type Err = FingerprintError;
type Err = anyhow::Error;
fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
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)]
mod tests {
use super::*;
use crate::test_utils::{alice_keypair, TestContext};
use std::error::Error;
use async_std::sync::Arc;
use once_cell::sync::Lazy;
@@ -676,13 +625,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
.unwrap();
assert_eq!(fp, res);
let err = "1".parse::<Fingerprint>().err().unwrap();
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));
assert!("1".parse::<Fingerprint>().is_err());
}
#[test]

View File

@@ -3,7 +3,7 @@
use anyhow::Result;
use crate::context::Context;
use crate::key::{self, DcKey};
use crate::key::DcKey;
/// An in-memory keyring.
///
@@ -27,14 +27,14 @@ where
}
/// 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();
keyring.load_self(context).await?;
Ok(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?);
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)]
mod tests {
use super::*;

View File

@@ -86,11 +86,7 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Lot {
};
let fingerprint: Fingerprint = match fingerprint.parse() {
Ok(fp) => fp,
Err(err) => {
return Error::new(err)
.context("Failed to parse fingerprint in QR code")
.into()
}
Err(err) => return err.context("Failed to parse fingerprint in QR code").into(),
};
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::events::EventType;
use crate::headerdef::HeaderDef;
use crate::key::{self, DcKey, Fingerprint, SignedPublicKey};
use crate::key::{DcKey, Fingerprint, SignedPublicKey};
use crate::message::Message;
use crate::mimeparser::{MimeMessage, SystemMessage};
use crate::param::Param;
@@ -355,12 +355,6 @@ async fn securejoin(context: &Context, qr: &str) -> Result<ChatId, JoinError> {
#[error("Failed sending handshake message")]
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(
context: &Context,
contact_chat_id: ChatId,

View File

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