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