mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 17:36:29 +03:00
Use anyhow for key.rs error handling
This commit is contained in:
83
src/key.rs
83
src/key.rs
@@ -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]
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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::*;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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")]
|
||||||
|
|||||||
Reference in New Issue
Block a user