rusthound_ce/
errors.rs

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Errors management
use ldap3::LdapError;
use std::error::Error as StdError;
use std::fmt;
//use std::num::ParseIntError;
use std::sync::Arc;

/// This is a shorthand for `rusthound`-based error results
pub type Result<T> = std::result::Result<T, Error>;
pub type Cause = Arc<dyn StdError + Send + Sync>;
pub type BoxError = Box<dyn std::error::Error + Send + Sync>;

/// RustHound error's type
pub struct Error {
    kind: Kind,
    cause: Option<Cause>,
    desc: Option<String>,
}

#[derive(Debug)]
pub enum Kind {
    /// Connection
    Connection(Connection),
    /// LdapError
    LdapError,
    /// Parse Error
    ParseError,
    /// Other
    Other,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Connection {
    Login,
    Host,
}

impl Error {
    /// Construct an error from scratch
    /// You can chain this method to `with`, as shown below.
    /// ```
    /// Error::new(Kind::Other).with()
    /// ```
    pub fn new(kind: Kind) -> Error {
        Error {
            kind,
            cause: None,
            desc: None,
        }
    }

    /// Specify a cause
    pub fn with<C: StdError + Send + Sync + 'static>(mut self, cause: C) -> Error {
        self.cause = Some(Arc::new(cause));
        self
    }

    pub fn desc<D: Into<String>>(mut self, desc: D) -> Error {
        self.desc = Some(desc.into());
        self
    }

    /// Get error kind
    pub fn kind(&self) -> &Kind {
        &self.kind
    }

    pub fn new_login() -> Error {
        Error::new(Kind::Connection(Connection::Login))
    }

    pub fn new_host() -> Error {
        Error::new(Kind::Connection(Connection::Host))
    }

    pub fn new_ldap_error(error: LdapError) -> Error {
        Error::new(Kind::LdapError).with(error)
    }

    /// Internally used for Display trait
    fn kind_description(&self) -> &str {
        match self.kind {
            Kind::Connection(Connection::Login) => "[!] LDAP Connection Failed, Invalid Credentials.\n",
            Kind::Connection(Connection::Host) => "[!] LDAP Connection Failed, No Route To Host.\n",
            Kind::LdapError => &"LDAP Error.\n",
            Kind::ParseError => &"Parsing Json Error.\n",
            Kind::Other => "[!] Other Error\n",
        }
    }

    /// Backtrace error source to find a cause matching given type
    pub fn find_source<E: StdError + 'static>(&self) -> Option<&E> {
        let mut source = self.source();
        while let Some(err) = source {
            if let Some(ref original) = err.downcast_ref() {
                return Some(original);
            }
            source = err.source();
        }
        // Not found
        None
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.kind_description())?;
        if let Some(ref desc) = self.desc {
            write!(f, ": {}", desc)?;
        }
        if let Some(ref cause) = self.cause {
            write!(f, ": {:?}", cause)?;
        }
        Ok(())
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.kind_description())?;
        if let Some(ref desc) = self.desc {
            write!(f, ": {}", desc)?;
        }
        if let Some(ref cause) = self.cause {
            write!(f, ": {}", cause)?;
        }
        Ok(())
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        self.cause
            .as_ref()
            .map(|cause| &**cause as &(dyn StdError + 'static))
    }
}

/// Converting from `LdapsearchError`
impl From<LdapError> for Error {
    fn from(err: LdapError) -> Error {
        Error::new(Kind::LdapError).with(err)
    }
}