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
use thiserror::Error;
use wildland_crypto::{
error::KeyDeriveError,
identity::{new_device_identity, Identity as CryptoIdentity},
};
use super::wildland::WildlandIdentity;
#[derive(Debug)]
pub struct MasterIdentity {
crypto_identity: Option<CryptoIdentity>,
}
#[derive(Debug, Error, PartialEq, Eq, Clone)]
pub enum ForestIdentityCreationError {
#[error("Crypto identity is required to create a new forest")]
CryptoIdentityNotFound,
#[error(transparent)]
KeyDeriveError(#[from] KeyDeriveError),
}
impl MasterIdentity {
#[tracing::instrument(level = "debug", skip(crypto_identity))]
pub fn new(crypto_identity: Option<CryptoIdentity>) -> Self {
tracing::debug!("creating new identity");
Self { crypto_identity }
}
#[tracing::instrument(level = "debug", skip(self))]
pub fn create_forest_identity(
&self,
index: u64,
) -> Result<WildlandIdentity, ForestIdentityCreationError> {
let keypair = self
.crypto_identity
.as_ref()
.map(|identity| identity.forest_keypair(index))
.ok_or(ForestIdentityCreationError::CryptoIdentityNotFound)??;
let identity = WildlandIdentity::Forest(index, keypair);
Ok(identity)
}
#[tracing::instrument(level = "debug", skip(self))]
pub fn create_device_identity(&self, name: String) -> WildlandIdentity {
let keypair = new_device_identity();
WildlandIdentity::Device(name, keypair)
}
}
#[cfg(test)]
mod tests {
use crate::{ForestIdentityCreationError, MasterIdentity, WildlandIdentity};
use wildland_crypto::identity::{generate_random_mnemonic, Identity};
fn create_crypto_identity() -> Identity {
generate_random_mnemonic()
.map(|mnemonic| Identity::try_from(&mnemonic).unwrap())
.unwrap()
}
#[test]
fn should_create_forest_identity() {
let crypto_identity = create_crypto_identity();
let master_identity = MasterIdentity::new(Some(crypto_identity));
let forest_identity = master_identity.create_forest_identity(0).unwrap();
assert!(matches!(forest_identity, WildlandIdentity::Forest(_, _)));
assert_eq!(forest_identity.get_identifier(), "0");
assert!(!forest_identity.get_private_key().is_empty());
assert!(!forest_identity.get_public_key().is_empty());
}
#[test]
fn should_not_create_forest_identity_without_crypto_identity() {
let master_identity = MasterIdentity::new(None);
let result = master_identity.create_forest_identity(0);
assert_eq!(
result.unwrap_err(),
ForestIdentityCreationError::CryptoIdentityNotFound
);
}
#[test]
fn should_create_device_identity_with_crypto_identity() {
let crypto_identity = create_crypto_identity();
let master_identity = MasterIdentity::new(Some(crypto_identity));
let device_identity = master_identity.create_device_identity("Device 1".to_string());
assert!(matches!(device_identity, WildlandIdentity::Device(_, _)));
assert_eq!(device_identity.get_identifier(), "Device 1");
assert!(!device_identity.get_private_key().is_empty());
assert!(!device_identity.get_public_key().is_empty());
}
#[test]
fn should_create_device_identity_without_crypto_identity() {
let master_identity = MasterIdentity::new(None);
let device_identity = master_identity.create_device_identity("Device 1".to_string());
assert!(matches!(device_identity, WildlandIdentity::Device(_, _)));
assert_eq!(device_identity.get_identifier(), "Device 1");
assert!(!device_identity.get_private_key().is_empty());
assert!(!device_identity.get_public_key().is_empty());
}
}