1use tor_error::HasKind;
4
5use dyn_clone::DynClone;
6use tor_persist::slug::BadSlug;
7
8use std::error::Error as StdError;
9use std::fmt;
10use std::sync::Arc;
11
12use crate::raw::RawEntryId;
13use crate::{KeyPath, KeyPathError, KeystoreId};
14
15#[derive(thiserror::Error, Debug, Clone)]
17#[non_exhaustive]
18pub enum Error {
19 #[error("{0}")]
21 Corruption(#[from] KeystoreCorruptionError),
22
23 #[error("{0}")]
25 Keystore(#[from] Arc<dyn KeystoreError>),
26
27 #[error("Key already exists")]
36 KeyAlreadyExists,
37
38 #[error("{0}")]
40 KeyForge(#[from] tor_key_forge::Error),
41
42 #[error("{0}")]
44 InvalidCert(#[from] tor_key_forge::InvalidCertError),
45
46 #[error("Keystore {0} not found")]
50 KeystoreNotFound(KeystoreId),
51
52 #[error("Internal error")]
54 Bug(#[from] tor_error::Bug),
55}
56
57pub trait KeystoreError:
59 HasKind + StdError + DynClone + fmt::Debug + fmt::Display + Send + Sync + 'static
60{
61}
62
63impl HasKind for Error {
64 fn kind(&self) -> tor_error::ErrorKind {
65 use Error as E;
66 use tor_error::ErrorKind as EK;
67
68 match self {
69 E::Keystore(e) => e.kind(),
70 E::Corruption(_) => EK::KeystoreCorrupted,
71 E::KeyAlreadyExists => EK::BadApiUsage, E::KeystoreNotFound(_) => EK::BadApiUsage, E::KeyForge(_) => EK::BadApiUsage,
74 E::InvalidCert(_) => EK::BadApiUsage, E::Bug(e) => e.kind(),
76 }
77 }
78}
79
80#[derive(thiserror::Error, Debug, Clone)]
88#[error("Invalid ArtiPath")]
89#[non_exhaustive]
90pub enum ArtiPathSyntaxError {
91 #[error("{0}")]
93 Slug(#[from] BadSlug),
94
95 #[error("Internal error")]
97 Bug(#[from] tor_error::Bug),
98}
99
100#[derive(thiserror::Error, Debug, Clone)]
102#[error("Keystore corruption")]
103#[non_exhaustive]
104pub enum KeystoreCorruptionError {
105 #[error("{0}")]
107 KeyPath(#[from] KeyPathError),
108
109 #[error("Unrecognized key path {0}")]
111 Unrecognized(KeyPath),
112
113 #[error("Missing certificate for key")]
115 MissingCertificate,
116
117 #[error("Subject key of certificate not found")]
119 MissingSubjectKey,
120
121 #[error("Missing signing key for certificate")]
123 MissingSigningKey,
124}
125
126#[derive(thiserror::Error, PartialEq, Eq, Debug, Clone)]
128#[error("unknown key type: arti_extension={arti_extension}")]
129pub struct UnknownKeyTypeError {
130 pub(crate) arti_extension: String,
132}
133
134#[derive(Clone, Debug, amplify::Getters, thiserror::Error)]
136#[error("Unrecognized keystore entry")]
137pub struct UnrecognizedEntryError {
138 entry: UnrecognizedEntry,
140 #[source]
153 error: Arc<dyn KeystoreError>,
154}
155
156impl UnrecognizedEntryError {
157 pub(crate) fn new(entry: UnrecognizedEntry, error: Arc<dyn KeystoreError>) -> Self {
160 Self { entry, error }
161 }
162}
163
164#[derive(Debug, Clone, PartialEq, amplify::Getters)]
166pub struct UnrecognizedEntry {
167 #[cfg_attr(not(feature = "onion-service-cli-extra"), getter(skip))]
169 raw_id: RawEntryId,
170 keystore_id: KeystoreId,
172}
173
174impl UnrecognizedEntry {
175 pub(crate) fn new(raw_id: RawEntryId, keystore_id: KeystoreId) -> Self {
177 Self {
178 raw_id,
179 keystore_id,
180 }
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 #![allow(clippy::bool_assert_comparison)]
188 #![allow(clippy::clone_on_copy)]
189 #![allow(clippy::dbg_macro)]
190 #![allow(clippy::mixed_attributes_style)]
191 #![allow(clippy::print_stderr)]
192 #![allow(clippy::print_stdout)]
193 #![allow(clippy::single_char_pattern)]
194 #![allow(clippy::unwrap_used)]
195 #![allow(clippy::unchecked_time_subtraction)]
196 #![allow(clippy::useless_vec)]
197 #![allow(clippy::needless_pass_by_value)]
198 use super::*;
200 use tor_error::ErrorKind;
201
202 #[derive(Debug, Copy, Clone, PartialEq, thiserror::Error)]
203 #[error("The source of a test error")]
204 struct TestErrorSource;
205
206 #[derive(Debug, Clone, thiserror::Error)]
207 #[error("A test error")]
208 struct TestError(#[from] TestErrorSource);
209
210 impl KeystoreError for TestError {}
211
212 impl HasKind for TestError {
213 fn kind(&self) -> ErrorKind {
214 ErrorKind::Other
215 }
216 }
217
218 #[test]
219 fn error_source() {
220 let e: Error = (Arc::new(TestError(TestErrorSource)) as Arc<dyn KeystoreError>).into();
221
222 assert_eq!(
223 e.source().unwrap().to_string(),
224 TestError(TestErrorSource).to_string()
225 );
226 }
227}