1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Error type for all errors returned to code outside of this crate.

use std::path::PathBuf;
use thiserror::Error;
use tokio::sync::mpsc::error::SendError;
use tonic::Status;
use utilities::crypto::error::CryptoError;

#[derive(Debug, Error)]
pub enum LockKeeperError {
    #[error(transparent)]
    Crypto(#[from] CryptoError),

    // Conversion errors
    #[error("Unknown secret type: {}", .0)]
    UnknownSecretType(String),
    #[error("Invalid secret type")]
    InvalidSecretType,
    #[error("Invalid KeyId length")]
    InvalidKeyIdLength,

    // Request errors
    #[error("Invalid client action")]
    InvalidClientAction,
    #[error("Network message missing required metadata")]
    MetadataNotFound,

    // Channel errors
    #[error("Invalid message")]
    InvalidMessage,
    #[error("No message received")]
    NoMessageReceived,
    #[error("Already authenticated")]
    AlreadyAuthenticated,
    #[error("This message should be send over an authenticated channel")]
    ShouldBeAuthenticated,

    // TLS errors
    #[error("Invalid private key")]
    InvalidPrivateKey,

    // Server side encryption error
    #[error("Invalid remote storage key")]
    InvalidRemoteStorageKey,

    // Wrapped errors
    #[error(transparent)]
    Hex(#[from] hex::FromHexError),
    /// Generic kitchen sink IO error. Use [LockKeeperError::FileIo] if
    /// the IO error is specifically related to working with files.
    #[error(transparent)]
    Io(#[from] std::io::Error),
    /// IO error specific to file IO failing. Allows us to include the file that
    /// failed as part of the error.
    #[error("File IO error. Cause: {0}. On file: {1}")]
    FileIo(std::io::Error, PathBuf),
    #[error("OPAQUE protocol error: {}", .0)]
    OpaqueProtocol(opaque_ke::errors::ProtocolError),
    #[error(transparent)]
    SerdeJson(#[from] serde_json::Error),
    #[error("tokio Sender error: {}", .0)]
    TokioSender(String),
    #[error(transparent)]
    TonicMetadata(#[from] tonic::metadata::errors::InvalidMetadataValueBytes),
    #[error(transparent)]
    TonicStatus(#[from] tonic::Status),
}

impl From<opaque_ke::errors::ProtocolError> for LockKeeperError {
    fn from(error: opaque_ke::errors::ProtocolError) -> Self {
        Self::OpaqueProtocol(error)
    }
}

impl<T> From<SendError<T>> for LockKeeperError {
    fn from(error: SendError<T>) -> Self {
        Self::TokioSender(error.to_string())
    }
}

impl From<LockKeeperError> for Status {
    fn from(error: LockKeeperError) -> Self {
        match error {
            // Errors that are safe to return to the client
            LockKeeperError::InvalidMessage
            | LockKeeperError::MetadataNotFound
            | LockKeeperError::UnknownSecretType(_)
            | LockKeeperError::InvalidSecretType => Status::invalid_argument(error.to_string()),
            LockKeeperError::NoMessageReceived => Status::deadline_exceeded(error.to_string()),

            // Errors that the client should not see
            LockKeeperError::FileIo(_, _)
            | LockKeeperError::InvalidClientAction
            | LockKeeperError::AlreadyAuthenticated
            | LockKeeperError::ShouldBeAuthenticated
            | LockKeeperError::Crypto(_)
            | LockKeeperError::Hex(_)
            | LockKeeperError::Io(_)
            | LockKeeperError::InvalidKeyIdLength
            | LockKeeperError::InvalidPrivateKey
            | LockKeeperError::InvalidRemoteStorageKey
            | LockKeeperError::OpaqueProtocol(_)
            | LockKeeperError::SerdeJson(_)
            | LockKeeperError::TokioSender(_)
            | LockKeeperError::TonicMetadata(_)
            | LockKeeperError::TonicStatus(_) => Status::internal("Internal server error"),
        }
    }
}