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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use ockam_core::compat::sync::Arc;
use ockam_core::errcode::{Kind, Origin};
use ockam_core::{Error, Result};
use ockam_vault::VaultForVerifyingSignatures;
use crate::models::{ChangeHistory, Identifier};
use crate::{ChangeHistoryRepository, Identity};
/// This struct supports functions for the creation and import of identities using an IdentityVault
pub struct IdentitiesVerification {
pub(super) repository: Arc<dyn ChangeHistoryRepository>,
pub(super) verifying_vault: Arc<dyn VaultForVerifyingSignatures>,
}
impl IdentitiesVerification {
/// Create a new identities import module
pub fn new(
repository: Arc<dyn ChangeHistoryRepository>,
verifying_vault: Arc<dyn VaultForVerifyingSignatures>,
) -> Self {
Self {
repository,
verifying_vault,
}
}
/// Import and verify identity from its binary format
pub async fn import(
&self,
expected_identifier: Option<&Identifier>,
data: &[u8],
) -> Result<Identifier> {
self.import_from_change_history(expected_identifier, ChangeHistory::import(data)?)
.await
}
/// Import and verify identity from its Change History
/// This action persists the Identity in the storage, use `Identity::import` to avoid that
pub async fn import_from_change_history(
&self,
expected_identifier: Option<&Identifier>,
change_history: ChangeHistory,
) -> Result<Identifier> {
let identity = Identity::import_from_change_history(
expected_identifier,
change_history,
self.verifying_vault.clone(),
)
.await?;
self.update_identity(&identity).await?;
Ok(identity.identifier().clone())
}
/// [`VerifyingVault`]
pub fn verifying_vault(&self) -> Arc<dyn VaultForVerifyingSignatures> {
self.verifying_vault.clone()
}
/// Return the change history of a persisted identity
pub async fn get_identity(&self, identifier: &Identifier) -> Result<Identity> {
Self::get_identity_static(
self.repository.clone(),
self.verifying_vault.clone(),
identifier,
)
.await
}
/// Return the change history of a persisted identity
pub async fn get_identity_static(
repository: Arc<dyn ChangeHistoryRepository>,
verifying_vault: Arc<dyn VaultForVerifyingSignatures>,
identifier: &Identifier,
) -> Result<Identity> {
match repository.get_change_history(identifier).await? {
Some(change_history) => {
let identity = Identity::import_from_change_history(
Some(identifier),
change_history,
verifying_vault,
)
.await?;
Ok(identity)
}
None => Err(Error::new(
Origin::Core,
Kind::NotFound,
format!("identity not found for identifier {}", identifier),
)),
}
}
/// Return the change history of a persisted identity
pub async fn get_change_history(&self, identifier: &Identifier) -> Result<ChangeHistory> {
match self.repository.get_change_history(identifier).await? {
Some(change_history) => Ok(change_history),
None => Err(Error::new(
Origin::Core,
Kind::NotFound,
format!("identity not found for identifier {}", identifier),
)),
}
}
}
impl IdentitiesVerification {
/// Compare Identity that was received by any side-channel (e.g., Secure Channel) to the
/// version we have observed and stored before.
/// - Do nothing if they're equal
/// - Throw an error if the received version is older
/// - Throw an error if the received version has conflict
/// - Update stored Identity if the received version is newer
///
/// All the code is performed in the ChangeHistoryRepository so that checking the identity
/// new change history and the identity old change history + insert the new change history
/// can be done atomically
///
pub async fn update_identity(&self, identity: &Identity) -> Result<()> {
self.repository.update_identity(identity, false).await
}
/// Compare Identity that was received by any side-channel (e.g., Secure Channel) to the
/// version we have observed and stored before.
/// - Do nothing if they're equal
/// - Do nothing if the received version is older
/// - Throw an error if the received version has conflict
/// - Update stored Identity if the received version is newer
///
/// All the code is performed in the ChangeHistoryRepository so that checking the identity
/// new change history and the identity old change history + insert the new change history
/// can be done atomically
///
pub async fn update_identity_ignore_older(&self, identity: &Identity) -> Result<()> {
self.repository.update_identity(identity, true).await
}
}