Skip to content

Commit

Permalink
test(olm): Add mutation tests for account
Browse files Browse the repository at this point in the history
Relates to: matrix-org#78

Signed-off-by: Johannes Marbach <[email protected]>
  • Loading branch information
Johennes committed Mar 25, 2024
1 parent cefd49c commit 9aa9e47
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 2 deletions.
13 changes: 13 additions & 0 deletions src/olm/account/fallback_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,17 @@ mod test {

assert_eq!(secret_bytes, fetched_key.to_bytes());
}

#[test]
fn fallback_key_publishing() {
let mut fallback_keys = FallbackKeys::new();
assert_eq!(fallback_keys.key_id, 0);

fallback_keys.generate_fallback_key();
assert_eq!(fallback_keys.key_id, 1);
assert!(fallback_keys.unpublished_fallback_key().is_some());

fallback_keys.mark_as_published();
assert!(fallback_keys.unpublished_fallback_key().is_none());
}
}
108 changes: 107 additions & 1 deletion src/olm/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,12 +676,16 @@ mod libolm {
#[cfg(test)]
mod test {
use anyhow::{bail, Context, Result};
use matrix_pickle::Encode;
use olm_rs::{account::OlmAccount, session::OlmMessage as LibolmOlmMessage};

use super::{Account, InboundCreationResult, SessionConfig, SessionCreationError};
use super::{
libolm::Pickle, Account, InboundCreationResult, SessionConfig, SessionCreationError,
};
use crate::{
cipher::Mac,
olm::{
account::PUBLIC_MAX_ONE_TIME_KEYS,
messages::{OlmMessage, PreKeyMessage},
AccountPickle,
},
Expand All @@ -690,6 +694,49 @@ mod test {

const PICKLE_KEY: [u8; 32] = [0u8; 32];

#[test]
fn max_number_of_one_time_keys_matches_global_constant() {
assert_eq!(Account::new().max_number_of_one_time_keys(), PUBLIC_MAX_ONE_TIME_KEYS);
}

#[test]
#[cfg(feature = "low-level-api")]
fn generate_and_remove_one_time_key() {
let mut alice = Account::new();
assert_eq!(alice.stored_one_time_key_count(), 0);

alice.generate_one_time_keys(1);
assert_eq!(alice.stored_one_time_key_count(), 1);

let public_key = alice
.one_time_keys()
.values()
.next()
.copied()
.expect("Should have an unpublished one-time key");
let secret_key_bytes = alice
.find_one_time_key(&public_key)
.expect("Should find secret key for public one-time key")
.to_bytes();
let removed_key_bytes = alice
.remove_one_time_key(public_key)
.expect("Should be able to remove one-time key")
.to_bytes();

assert_eq!(removed_key_bytes, secret_key_bytes);
assert_eq!(alice.stored_one_time_key_count(), 0);
}

#[test]
fn generate_and_forget_fallback_keys() {
let mut alice = Account::default();
assert!(!alice.forget_fallback_key());
alice.generate_fallback_key();
assert!(!alice.forget_fallback_key());
alice.generate_fallback_key();
assert!(alice.forget_fallback_key());
}

#[test]
fn vodozemac_libolm_communication() -> Result<()> {
// vodozemac account
Expand Down Expand Up @@ -773,7 +820,9 @@ mod test {
.1,
);

assert!(!bob.one_time_keys().is_empty());
bob.mark_keys_as_published();
assert!(bob.one_time_keys().is_empty());

let message = "It's a secret to everybody";
let olm_message = alice_session.encrypt(message);
Expand Down Expand Up @@ -957,6 +1006,63 @@ mod test {
Ok(())
}

#[test]
fn pickle_cycle_with_one_fallback_key() {
let mut alice = Account::new();
alice.generate_fallback_key();

let mut encoded = Vec::<u8>::new();
let pickle = Pickle::from(&alice);
let size = pickle.encode(&mut encoded).expect("Should encode pickle");
assert_eq!(size, encoded.len());

let account =
Account::from_decrypted_libolm_pickle(&encoded).expect("Should unpickle account");

let key_bytes = alice
.fallback_key()
.values()
.next()
.expect("Should have a fallback key before encoding")
.to_bytes();
let decoded_key_bytes = account
.fallback_key()
.values()
.next()
.expect("Should have a fallback key after decoding")
.to_bytes();
assert_eq!(key_bytes, decoded_key_bytes);
}

#[test]
fn pickle_cycle_with_two_fallback_keys() {
let mut alice = Account::new();
alice.generate_fallback_key();
alice.generate_fallback_key();

let mut encoded = Vec::<u8>::new();
let pickle = Pickle::from(&alice);
let size = pickle.encode(&mut encoded).expect("Should encode pickle");
assert_eq!(size, encoded.len());

let account =
Account::from_decrypted_libolm_pickle(&encoded).expect("Should unpickle account");

let key_bytes = alice
.fallback_key()
.values()
.next()
.expect("Should have a fallback key before encoding")
.to_bytes();
let decoded_key_bytes = account
.fallback_key()
.values()
.next()
.expect("Should have a fallback key after decoding")
.to_bytes();
assert_eq!(key_bytes, decoded_key_bytes);
}

#[test]
#[cfg(feature = "libolm-compat")]
fn signing_with_expanded_key() -> Result<()> {
Expand Down
20 changes: 19 additions & 1 deletion src/olm/account/one_time_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,22 @@ mod test {
assert!(store.private_keys.is_empty());

store.generate(OneTimeKeys::MAX_ONE_TIME_KEYS);
assert_eq!(store.private_keys.len(), OneTimeKeys::MAX_ONE_TIME_KEYS);
assert_eq!(store.unpublished_public_keys.len(), OneTimeKeys::MAX_ONE_TIME_KEYS);
assert_eq!(store.private_keys.len(), OneTimeKeys::MAX_ONE_TIME_KEYS);
assert_eq!(store.key_ids_by_key.len(), OneTimeKeys::MAX_ONE_TIME_KEYS);

store
.private_keys
.keys()
.for_each(|key_id| assert!(!store.is_secret_key_published(key_id)));

store.mark_as_published();
assert!(store.unpublished_public_keys.is_empty());
assert_eq!(store.private_keys.len(), OneTimeKeys::MAX_ONE_TIME_KEYS);
assert_eq!(store.key_ids_by_key.len(), OneTimeKeys::MAX_ONE_TIME_KEYS);

store.private_keys.keys().for_each(|key_id| assert!(store.is_secret_key_published(key_id)));

let oldest_key_id =
store.private_keys.keys().next().copied().expect("Couldn't get the first key ID");
assert_eq!(oldest_key_id, KeyId(0));
Expand All @@ -210,6 +217,17 @@ mod test {
assert_eq!(store.private_keys.len(), OneTimeKeys::MAX_ONE_TIME_KEYS);
assert_eq!(store.key_ids_by_key.len(), OneTimeKeys::MAX_ONE_TIME_KEYS);

store
.private_keys
.keys()
.take(OneTimeKeys::MAX_ONE_TIME_KEYS - 10)
.for_each(|key_id| assert!(store.is_secret_key_published(key_id)));
store
.private_keys
.keys()
.skip(OneTimeKeys::MAX_ONE_TIME_KEYS - 10)
.for_each(|key_id| assert!(!store.is_secret_key_published(key_id)));

let oldest_key_id =
store.private_keys.keys().next().copied().expect("Couldn't get the first key ID");

Expand Down

0 comments on commit 9aa9e47

Please sign in to comment.