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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
//! Entity is an abstraction over Profiles and Vaults, easing the use of these primitives in
//! authentication and authorization APIs.
#![deny(
  // prevented by big_array
  //  missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unused_import_braces,
    unused_qualifications,
    // warnings
)]

pub use change::*;
pub use channel::*;
pub use contact::*;
pub use credential::*;
pub use entity::*;
pub use error::*;
pub use identifiers::*;
pub use key_attributes::*;
use ockam_channel::SecureChannelVault;
use ockam_core::{lib::HashMap, Address, Message, Result};
use ockam_node::{block_future, Context};
use ockam_vault::{Hasher, KeyIdVault, SecretVault, Signer, Verifier};
pub use profile::*;
pub use profile_state::*;
pub use traits::*;
pub use worker::*;

use crate::EntityError;

pub struct Handle {
    ctx: Context,
    address: Address,
}

impl Clone for Handle {
    fn clone(&self) -> Self {
        block_future(&self.ctx.runtime(), async move {
            Handle {
                ctx: self
                    .ctx
                    .new_context(Address::random(0))
                    .await
                    .expect("new_context failed"),
                address: self.address.clone(),
            }
        })
    }
}

impl Handle {
    pub fn new(ctx: Context, address: Address) -> Self {
        Handle { ctx, address }
    }

    pub async fn async_cast<M: Message + Send + 'static>(&self, msg: M) -> Result<()> {
        self.ctx.send(self.address.clone(), msg).await
    }

    pub fn cast<M: Message + Send + 'static>(&self, msg: M) -> Result<()> {
        block_future(
            &self.ctx.runtime(),
            async move { self.async_cast(msg).await },
        )
    }

    pub async fn async_call<I: Message + Send + 'static, O: Message + Send + 'static>(
        &self,
        msg: I,
    ) -> Result<O> {
        let mut ctx = self
            .ctx
            .new_context(Address::random(0))
            .await
            .expect("new_context failed");
        ctx.send(self.address.clone(), msg).await?;
        let msg = ctx.receive::<O>().await?;
        Ok(msg.take().body())
    }

    pub fn call<I: Message + Send + 'static, O: Message + Send + 'static>(
        &self,
        msg: I,
    ) -> Result<O> {
        block_future(
            &self.ctx.runtime(),
            async move { self.async_call(msg).await },
        )
    }
}

mod authentication;
mod change;
pub mod change_history;
mod channel;
mod contact;
mod credential;
mod entity;
mod error;
mod identifiers;
mod key_attributes;
mod profile;
mod profile_state;
mod proof;
mod traits;
mod worker;

/// Traits required for a Vault implementation suitable for use in a Profile
pub trait ProfileVault:
    SecretVault + SecureChannelVault + KeyIdVault + Hasher + Signer + Verifier + Clone + Send + 'static
{
}

impl<D> ProfileVault for D where
    D: SecretVault
        + SecureChannelVault
        + KeyIdVault
        + Hasher
        + Signer
        + Verifier
        + Clone
        + Send
        + 'static
{
}

/// Profile event attributes
pub type ProfileEventAttributes = HashMap<String, String>;
/// Contacts Database
pub type Contacts = HashMap<ProfileIdentifier, Contact>;

pub use signature_bbs_plus::{PublicKey as BbsPublicKey, SecretKey as BbsSecretKey};
pub use signature_bls::{PublicKey as BlsPublicKey, SecretKey as BlsSecretKey};

pub struct ProfileSerializationUtil;

impl ProfileSerializationUtil {
    /// Serialize [`Contact`] in binary form for storing/transferring over the network
    pub fn serialize_contact(contact: &Contact) -> Result<Vec<u8>> {
        serde_bare::to_vec(&contact).map_err(|_| EntityError::BareError.into())
    }

    /// Deserialize [`Contact`] from binary form
    pub fn deserialize_contact(contact: &[u8]) -> Result<Contact> {
        let contact: Contact =
            serde_bare::from_slice(contact).map_err(|_| EntityError::BareError)?;

        Ok(contact)
    }

    /// Serialize [`ProfileChangeEvent`]s to binary form for storing/transferring over the network
    pub fn serialize_change_events(change_events: &[ProfileChangeEvent]) -> Result<Vec<u8>> {
        serde_bare::to_vec(&change_events).map_err(|_| EntityError::BareError.into())
    }

    /// Deserialize [`ProfileChangeEvent`]s from binary form
    pub fn deserialize_change_events(change_events: &[u8]) -> Result<Vec<ProfileChangeEvent>> {
        let change_events: Vec<ProfileChangeEvent> =
            serde_bare::from_slice(change_events).map_err(|_| EntityError::BareError)?;

        Ok(change_events)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use ockam_core::Error;
    use ockam_vault_sync_core::Vault;

    fn test_error<S: Into<String>>(msg: S) -> Result<()> {
        Err(Error::new(0, msg.into()))
    }

    fn test_basic_profile_key_ops<P: Identity>(profile: &mut P) -> Result<()> {
        if !profile.verify_changes()? {
            return test_error("verify_changes failed");
        }

        let secret1 = profile.get_profile_secret_key()?;
        let public1 = profile.get_profile_public_key()?;

        profile.create_key("Truck management")?;

        if !profile.verify_changes()? {
            return test_error("verify_changes failed");
        }

        let secret2 = profile.get_secret_key("Truck management")?;
        let public2 = profile.get_public_key("Truck management")?;

        if secret1 == secret2 {
            return test_error("secret did not change after create_key");
        }

        if public1 == public2 {
            return test_error("public did not change after create_key");
        }

        profile.rotate_profile_key()?;

        if !profile.verify_changes()? {
            return test_error("verify_changes failed");
        }

        let secret3 = profile.get_profile_secret_key()?;
        let public3 = profile.get_profile_public_key()?;

        profile.rotate_profile_key()?;

        if !profile.verify_changes()? {
            return test_error("verify_changes failed");
        }

        if secret1 == secret3 {
            return test_error("secret did not change after rotate_key");
        }

        if public1 == public3 {
            return test_error("public did not change after rotate_key");
        }

        Ok(())
    }

    fn test_update_contact_after_change<P: Identity>(alice: &mut P, bob: &mut P) -> Result<()> {
        let contact_alice = alice.as_contact()?;
        let alice_id = contact_alice.identifier().clone();
        if !bob.verify_and_add_contact(contact_alice)? {
            return test_error("bob failed to add alice");
        }

        alice.rotate_profile_key()?;
        let alice_changes = alice.get_changes()?;
        let last_change = alice_changes.last().unwrap().clone();

        if !bob.verify_and_update_contact(&alice_id, &[last_change])? {
            return test_error("bob failed to update alice");
        }
        Ok(())
    }

    #[test]
    fn async_tests() {
        let (mut ctx, mut executor) = ockam_node::start_node();
        executor
            .execute(async move {
                let alice_vault = Vault::create(&ctx).expect("failed to create vault");
                let bob_vault = Vault::create(&ctx).expect("failed to create vault");

                let mut entity_alice = Entity::create(&ctx, &alice_vault).unwrap();
                let mut entity_bob = Entity::create(&ctx, &bob_vault).unwrap();

                let mut alice = entity_alice.current_profile().unwrap();
                let mut bob = entity_bob.current_profile().unwrap();

                let mut results = vec![];
                results.push(test_basic_profile_key_ops(&mut alice));
                results.push(test_update_contact_after_change(&mut alice, &mut bob));
                ctx.stop().await.unwrap();

                for r in results {
                    match r {
                        Err(e) => panic!("{}", e.domain().clone()),
                        _ => (),
                    }
                }
            })
            .unwrap();
    }
}