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 #[must_use]
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 Private = $private_name;
131 type Signing = $signing_name;
132 }
133 };
134
135 ( @key_type symmetric ) => { $crate::SymmetricCryptoKey };
136 ( @key_type private ) => { $crate::PrivateKey };
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::{TestPrivateKey, 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!(!TestPrivateKey::A(0).is_local());
166 assert!(!TestPrivateKey::B.is_local());
167 assert!(TestPrivateKey::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}