bitwarden_crypto/traits/
key_id.rs1use std::{fmt::Debug, hash::Hash};
2
3use zeroize::ZeroizeOnDrop;
4
5use crate::{AsymmetricCryptoKey, CryptoKey, SigningKey, SymmetricCryptoKey};
6
7pub trait KeyId:
19 Debug + Clone + Copy + Hash + Eq + PartialEq + Ord + PartialOrd + Send + Sync + 'static
20{
21 #[allow(missing_docs)]
22 type KeyValue: CryptoKey + Send + Sync + ZeroizeOnDrop;
23
24 fn is_local(&self) -> bool;
27
28 fn new_local(id: LocalId) -> Self;
30}
31
32pub trait KeyIds {
35 #[allow(missing_docs)]
36 type Symmetric: KeyId<KeyValue = SymmetricCryptoKey>;
37 #[allow(missing_docs)]
38 type Asymmetric: KeyId<KeyValue = AsymmetricCryptoKey>;
39 type Signing: KeyId<KeyValue = SigningKey>;
41}
42
43#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
46pub struct LocalId(pub(crate) uuid::Uuid);
47
48impl LocalId {
49 pub(crate) fn new() -> Self {
50 LocalId(uuid::Uuid::new_v4())
51 }
52}
53
54#[macro_export]
84macro_rules! key_ids {
85 ( $(
86 #[$meta_type:tt]
87 $vis:vis enum $name:ident {
88 $(
89 $( #[$variant_tag:tt] )?
90 $variant:ident $( ( $inner:ty ) )?
91 ),*
92 $(,)?
93 }
94 )+
95 $ids_vis:vis $ids_name:ident => $symm_name:ident, $asymm_name:ident, $signing_name:ident;
96 ) => {
97
98 use $crate::LocalId;
99
100 $(
101 #[derive(std::fmt::Debug, Clone, Copy, std::hash::Hash, Eq, PartialEq, Ord, PartialOrd)]
102 #[allow(missing_docs)]
103 $vis enum $name { $(
104 $variant $( ($inner) )?,
105 )* }
106
107 impl $crate::KeyId for $name {
108 type KeyValue = key_ids!(@key_type $meta_type);
109
110 fn is_local(&self) -> bool {
111 use $name::*;
112 match self { $(
113 key_ids!(@variant_match $variant $( ( $inner ) )?) =>
114 key_ids!(@variant_value $( $variant_tag )? ),
115 )* }
116 }
117
118 fn new_local(id: LocalId) -> Self {
119 $(
120 { key_ids!(@new_local $variant id $( $variant_tag )? ) }
121 )*
122 }
123 }
124 )+
125
126 #[allow(missing_docs)]
127 $ids_vis struct $ids_name;
128 impl $crate::KeyIds for $ids_name {
129 type Symmetric = $symm_name;
130 type Asymmetric = $asymm_name;
131 type Signing = $signing_name;
132 }
133 };
134
135 ( @key_type symmetric ) => { $crate::SymmetricCryptoKey };
136 ( @key_type asymmetric ) => { $crate::AsymmetricCryptoKey };
137 ( @key_type signing ) => { $crate::SigningKey };
138
139 ( @variant_match $variant:ident ( $inner:ty ) ) => { $variant (_) };
140 ( @variant_match $variant:ident ) => { $variant };
141
142 ( @variant_value local ) => { true };
143 ( @variant_value ) => { false };
144
145 ( @new_local $variant:ident $id:ident local ) => { Self::$variant($id) };
146 ( @new_local $variant:ident $id:ident ) => {{}};
147}
148
149#[cfg(test)]
150pub(crate) mod tests {
151
152 use crate::{
153 KeyId, LocalId,
154 traits::tests::{TestAsymmKey, TestSigningKey, TestSymmKey},
155 };
156
157 #[test]
158 fn test_local() {
159 let local = LocalId::new();
160
161 assert!(!TestSymmKey::A(0).is_local());
162 assert!(!TestSymmKey::B((4, 10)).is_local());
163 assert!(TestSymmKey::C(local).is_local());
164
165 assert!(!TestAsymmKey::A(0).is_local());
166 assert!(!TestAsymmKey::B.is_local());
167 assert!(TestAsymmKey::C(local).is_local());
168
169 assert!(!TestSigningKey::A(0).is_local());
170 assert!(!TestSigningKey::B.is_local());
171 assert!(TestSigningKey::C(local).is_local());
172 }
173}