crypto: Move the uploaded key count handing into the account.
parent
a7a9ac24ed
commit
18b444aac5
|
@ -189,23 +189,7 @@ impl OlmMachine {
|
||||||
|
|
||||||
/// Should account or one-time keys be uploaded to the server.
|
/// Should account or one-time keys be uploaded to the server.
|
||||||
pub async fn should_upload_keys(&self) -> bool {
|
pub async fn should_upload_keys(&self) -> bool {
|
||||||
if !self.account.shared() {
|
self.account.should_upload_keys().await
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let count = self.account.uploaded_key_count() as u64;
|
|
||||||
|
|
||||||
// If we have a known key count, check that we have more than
|
|
||||||
// max_one_time_Keys() / 2, otherwise tell the client to upload more.
|
|
||||||
let max_keys = self.account.max_one_time_keys().await as u64;
|
|
||||||
// If there are more keys already uploaded than max_key / 2
|
|
||||||
// bail out returning false, this also avoids overflow.
|
|
||||||
if count > (max_keys / 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let key_count = (max_keys / 2) - count;
|
|
||||||
key_count > 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the count of one-time keys that are currently on the server.
|
/// Update the count of one-time keys that are currently on the server.
|
||||||
|
@ -522,36 +506,6 @@ impl OlmMachine {
|
||||||
Ok(changed_devices)
|
Ok(changed_devices)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate new one-time keys.
|
|
||||||
///
|
|
||||||
/// Returns the number of newly generated one-time keys. If no keys can be
|
|
||||||
/// generated returns an empty error.
|
|
||||||
async fn generate_one_time_keys(&self) -> StdResult<u64, ()> {
|
|
||||||
let count = self.account.uploaded_key_count() as u64;
|
|
||||||
// TODO if we store the uploaded key count with the Account all
|
|
||||||
// this logic could go into the account.
|
|
||||||
let max_keys = self.account.max_one_time_keys().await;
|
|
||||||
let max_on_server = (max_keys as u64) / 2;
|
|
||||||
|
|
||||||
if count >= (max_on_server) {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let key_count = (max_on_server) - count;
|
|
||||||
let key_count: usize = key_count.try_into().unwrap_or(max_keys);
|
|
||||||
|
|
||||||
self.account.generate_one_time_keys(key_count).await;
|
|
||||||
Ok(key_count as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate, sign and prepare one-time keys to be uploaded.
|
|
||||||
///
|
|
||||||
/// If no one-time keys need to be uploaded returns an empty error.
|
|
||||||
async fn signed_one_time_keys(&self) -> StdResult<OneTimeKeys, ()> {
|
|
||||||
let _ = self.generate_one_time_keys().await?;
|
|
||||||
Ok(self.account.signed_one_time_keys().await)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Verify a signed JSON object.
|
/// Verify a signed JSON object.
|
||||||
///
|
///
|
||||||
/// The object must have a signatures key associated with an object of the
|
/// The object must have a signatures key associated with an object of the
|
||||||
|
@ -624,21 +578,7 @@ impl OlmMachine {
|
||||||
pub async fn keys_for_upload(
|
pub async fn keys_for_upload(
|
||||||
&self,
|
&self,
|
||||||
) -> StdResult<(Option<DeviceKeys>, Option<OneTimeKeys>), ()> {
|
) -> StdResult<(Option<DeviceKeys>, Option<OneTimeKeys>), ()> {
|
||||||
if !self.should_upload_keys().await {
|
self.account.keys_for_upload().await
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let shared = self.account.shared();
|
|
||||||
|
|
||||||
let device_keys = if !shared {
|
|
||||||
Some(self.account.device_keys().await)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let one_time_keys: Option<OneTimeKeys> = self.signed_one_time_keys().await.ok();
|
|
||||||
|
|
||||||
Ok((device_keys, one_time_keys))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to decrypt an Olm message.
|
/// Try to decrypt an Olm message.
|
||||||
|
@ -1642,7 +1582,7 @@ mod test {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(machine.should_upload_keys().await);
|
assert!(machine.should_upload_keys().await);
|
||||||
assert!(machine.generate_one_time_keys().await.is_ok());
|
assert!(machine.account.generate_one_time_keys().await.is_ok());
|
||||||
|
|
||||||
response
|
response
|
||||||
.one_time_key_counts
|
.one_time_key_counts
|
||||||
|
@ -1651,7 +1591,7 @@ mod test {
|
||||||
.receive_keys_upload_response(&response)
|
.receive_keys_upload_response(&response)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(machine.generate_one_time_keys().await.is_err());
|
assert!(machine.account.generate_one_time_keys().await.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -1707,7 +1647,7 @@ mod test {
|
||||||
let machine = OlmMachine::new(&user_id(), &alice_device_id());
|
let machine = OlmMachine::new(&user_id(), &alice_device_id());
|
||||||
machine.account.update_uploaded_key_count(49);
|
machine.account.update_uploaded_key_count(49);
|
||||||
|
|
||||||
let mut one_time_keys = machine.signed_one_time_keys().await.unwrap();
|
let mut one_time_keys = machine.account.signed_one_time_keys().await.unwrap();
|
||||||
let identity_keys = machine.account.identity_keys();
|
let identity_keys = machine.account.identity_keys();
|
||||||
let ed25519_key = identity_keys.ed25519();
|
let ed25519_key = identity_keys.ed25519();
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ impl Account {
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `new_count` - The new count that was reported by the server.
|
/// * `new_count` - The new count that was reported by the server.
|
||||||
pub fn update_uploaded_key_count(&self, new_count: u64) {
|
pub(crate) fn update_uploaded_key_count(&self, new_count: u64) {
|
||||||
let key_count = i64::try_from(new_count).unwrap_or(i64::MAX);
|
let key_count = i64::try_from(new_count).unwrap_or(i64::MAX);
|
||||||
self.uploaded_signed_key_count
|
self.uploaded_signed_key_count
|
||||||
.store(key_count, Ordering::Relaxed);
|
.store(key_count, Ordering::Relaxed);
|
||||||
|
@ -130,29 +130,96 @@ impl Account {
|
||||||
///
|
///
|
||||||
/// Messages shouldn't be encrypted with the session before it has been
|
/// Messages shouldn't be encrypted with the session before it has been
|
||||||
/// shared.
|
/// shared.
|
||||||
pub fn mark_as_shared(&self) {
|
pub(crate) fn mark_as_shared(&self) {
|
||||||
self.shared.store(true, Ordering::Relaxed);
|
self.shared.store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the one-time keys of the account.
|
/// Get the one-time keys of the account.
|
||||||
///
|
///
|
||||||
/// This can be empty, keys need to be generated first.
|
/// This can be empty, keys need to be generated first.
|
||||||
pub async fn one_time_keys(&self) -> OneTimeKeys {
|
pub(crate) async fn one_time_keys(&self) -> OneTimeKeys {
|
||||||
self.inner.lock().await.parsed_one_time_keys()
|
self.inner.lock().await.parsed_one_time_keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate count number of one-time keys.
|
/// Generate count number of one-time keys.
|
||||||
pub async fn generate_one_time_keys(&self, count: usize) {
|
pub(crate) async fn generate_one_time_keys_helper(&self, count: usize) {
|
||||||
self.inner.lock().await.generate_one_time_keys(count);
|
self.inner.lock().await.generate_one_time_keys(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the maximum number of one-time keys the account can hold.
|
/// Get the maximum number of one-time keys the account can hold.
|
||||||
pub async fn max_one_time_keys(&self) -> usize {
|
pub(crate) async fn max_one_time_keys(&self) -> usize {
|
||||||
self.inner.lock().await.max_number_of_one_time_keys()
|
self.inner.lock().await.max_number_of_one_time_keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a tuple of device and one-time keys that need to be uploaded.
|
||||||
|
///
|
||||||
|
/// Returns an empty error if no keys need to be uploaded.
|
||||||
|
pub(crate) async fn generate_one_time_keys(&self) -> Result<u64, ()> {
|
||||||
|
let count = self.uploaded_key_count() as u64;
|
||||||
|
let max_keys = self.max_one_time_keys().await;
|
||||||
|
let max_on_server = (max_keys as u64) / 2;
|
||||||
|
|
||||||
|
if count >= (max_on_server) {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let key_count = (max_on_server) - count;
|
||||||
|
let key_count: usize = key_count.try_into().unwrap_or(max_keys);
|
||||||
|
|
||||||
|
self.generate_one_time_keys_helper(key_count).await;
|
||||||
|
Ok(key_count as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should account or one-time keys be uploaded to the server.
|
||||||
|
pub(crate) async fn should_upload_keys(&self) -> bool {
|
||||||
|
if !self.shared() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = self.uploaded_key_count() as u64;
|
||||||
|
|
||||||
|
// If we have a known key count, check that we have more than
|
||||||
|
// max_one_time_Keys() / 2, otherwise tell the client to upload more.
|
||||||
|
let max_keys = self.max_one_time_keys().await as u64;
|
||||||
|
// If there are more keys already uploaded than max_key / 2
|
||||||
|
// bail out returning false, this also avoids overflow.
|
||||||
|
if count > (max_keys / 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let key_count = (max_keys / 2) - count;
|
||||||
|
key_count > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a tuple of device and one-time keys that need to be uploaded.
|
||||||
|
///
|
||||||
|
/// Returns an empty error if no keys need to be uploaded.
|
||||||
|
pub(crate) async fn keys_for_upload(
|
||||||
|
&self,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
Option<DeviceKeys>,
|
||||||
|
Option<BTreeMap<AlgorithmAndDeviceId, OneTimeKey>>,
|
||||||
|
),
|
||||||
|
(),
|
||||||
|
> {
|
||||||
|
if !self.should_upload_keys().await {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let device_keys = if !self.shared() {
|
||||||
|
Some(self.device_keys().await)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let one_time_keys = self.signed_one_time_keys().await.ok();
|
||||||
|
|
||||||
|
Ok((device_keys, one_time_keys))
|
||||||
|
}
|
||||||
|
|
||||||
/// Mark the current set of one-time keys as being published.
|
/// Mark the current set of one-time keys as being published.
|
||||||
pub async fn mark_keys_as_published(&self) {
|
pub(crate) async fn mark_keys_as_published(&self) {
|
||||||
self.inner.lock().await.mark_keys_as_published();
|
self.inner.lock().await.mark_keys_as_published();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +274,7 @@ impl Account {
|
||||||
|
|
||||||
/// Sign the device keys of the account and return them so they can be
|
/// Sign the device keys of the account and return them so they can be
|
||||||
/// uploaded.
|
/// uploaded.
|
||||||
pub async fn device_keys(&self) -> DeviceKeys {
|
pub(crate) async fn device_keys(&self) -> DeviceKeys {
|
||||||
let identity_keys = self.identity_keys();
|
let identity_keys = self.identity_keys();
|
||||||
|
|
||||||
let mut keys = BTreeMap::new();
|
let mut keys = BTreeMap::new();
|
||||||
|
@ -257,6 +324,10 @@ impl Account {
|
||||||
///
|
///
|
||||||
/// * `json` - The value that should be converted into a canonical JSON
|
/// * `json` - The value that should be converted into a canonical JSON
|
||||||
/// string.
|
/// string.
|
||||||
|
///
|
||||||
|
/// # Panic
|
||||||
|
///
|
||||||
|
/// Panics if the json value can't be serialized.
|
||||||
pub async fn sign_json(&self, json: &Value) -> String {
|
pub async fn sign_json(&self, json: &Value) -> String {
|
||||||
let canonical_json = cjson::to_string(json)
|
let canonical_json = cjson::to_string(json)
|
||||||
.unwrap_or_else(|_| panic!(format!("Can't serialize {} to canonical JSON", json)));
|
.unwrap_or_else(|_| panic!(format!("Can't serialize {} to canonical JSON", json)));
|
||||||
|
@ -266,7 +337,11 @@ impl Account {
|
||||||
/// Generate, sign and prepare one-time keys to be uploaded.
|
/// Generate, sign and prepare one-time keys to be uploaded.
|
||||||
///
|
///
|
||||||
/// If no one-time keys need to be uploaded returns an empty error.
|
/// If no one-time keys need to be uploaded returns an empty error.
|
||||||
pub async fn signed_one_time_keys(&self) -> BTreeMap<AlgorithmAndDeviceId, OneTimeKey> {
|
pub(crate) async fn signed_one_time_keys(
|
||||||
|
&self,
|
||||||
|
) -> Result<BTreeMap<AlgorithmAndDeviceId, OneTimeKey>, ()> {
|
||||||
|
let _ = self.generate_one_time_keys().await?;
|
||||||
|
|
||||||
let one_time_keys = self.one_time_keys().await;
|
let one_time_keys = self.one_time_keys().await;
|
||||||
let mut one_time_key_map = BTreeMap::new();
|
let mut one_time_key_map = BTreeMap::new();
|
||||||
|
|
||||||
|
@ -298,7 +373,7 @@ impl Account {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
one_time_key_map
|
Ok(one_time_key_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new session with another account given a one-time key.
|
/// Create a new session with another account given a one-time key.
|
||||||
|
@ -311,7 +386,7 @@ impl Account {
|
||||||
///
|
///
|
||||||
/// * `their_one_time_key` - A signed one-time key that the other account
|
/// * `their_one_time_key` - A signed one-time key that the other account
|
||||||
/// created and shared with us.
|
/// created and shared with us.
|
||||||
pub async fn create_outbound_session(
|
pub(crate) async fn create_outbound_session(
|
||||||
&self,
|
&self,
|
||||||
their_identity_key: &str,
|
their_identity_key: &str,
|
||||||
their_one_time_key: &SignedKey,
|
their_one_time_key: &SignedKey,
|
||||||
|
@ -344,7 +419,7 @@ impl Account {
|
||||||
///
|
///
|
||||||
/// * `message` - A pre-key Olm message that was sent to us by the other
|
/// * `message` - A pre-key Olm message that was sent to us by the other
|
||||||
/// account.
|
/// account.
|
||||||
pub async fn create_inbound_session(
|
pub(crate) async fn create_inbound_session(
|
||||||
&self,
|
&self,
|
||||||
their_identity_key: &str,
|
their_identity_key: &str,
|
||||||
message: PreKeyMessage,
|
message: PreKeyMessage,
|
||||||
|
@ -386,7 +461,7 @@ impl Account {
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `room_id` - The ID of the room where the group session will be used.
|
/// * `room_id` - The ID of the room where the group session will be used.
|
||||||
pub async fn create_group_session_pair(
|
pub(crate) async fn create_group_session_pair(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
) -> (OutboundGroupSession, InboundGroupSession) {
|
) -> (OutboundGroupSession, InboundGroupSession) {
|
||||||
|
@ -923,7 +998,7 @@ pub(crate) mod test {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = Account::new(&alice_id(), &alice_device_id());
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = Account::new(&bob_id(), &bob_device_id());
|
||||||
|
|
||||||
bob.generate_one_time_keys(1).await;
|
bob.generate_one_time_keys_helper(1).await;
|
||||||
let one_time_key = bob
|
let one_time_key = bob
|
||||||
.one_time_keys()
|
.one_time_keys()
|
||||||
.await
|
.await
|
||||||
|
@ -975,7 +1050,7 @@ pub(crate) mod test {
|
||||||
assert!(one_time_keys.curve25519().is_empty());
|
assert!(one_time_keys.curve25519().is_empty());
|
||||||
assert_ne!(account.max_one_time_keys().await, 0);
|
assert_ne!(account.max_one_time_keys().await, 0);
|
||||||
|
|
||||||
account.generate_one_time_keys(10).await;
|
account.generate_one_time_keys_helper(10).await;
|
||||||
let one_time_keys = account.one_time_keys().await;
|
let one_time_keys = account.one_time_keys().await;
|
||||||
|
|
||||||
assert!(!one_time_keys.curve25519().is_empty());
|
assert!(!one_time_keys.curve25519().is_empty());
|
||||||
|
@ -999,7 +1074,7 @@ pub(crate) mod test {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = Account::new(&alice_id(), &alice_device_id());
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = Account::new(&bob_id(), &bob_device_id());
|
||||||
let alice_keys = alice.identity_keys();
|
let alice_keys = alice.identity_keys();
|
||||||
alice.generate_one_time_keys(1).await;
|
alice.generate_one_time_keys_helper(1).await;
|
||||||
let one_time_keys = alice.one_time_keys().await;
|
let one_time_keys = alice.one_time_keys().await;
|
||||||
alice.mark_keys_as_published().await;
|
alice.mark_keys_as_published().await;
|
||||||
|
|
||||||
|
|
|
@ -857,7 +857,7 @@ mod test {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = Account::new(&alice_id(), &alice_device_id());
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = Account::new(&bob_id(), &bob_device_id());
|
||||||
|
|
||||||
bob.generate_one_time_keys(1).await;
|
bob.generate_one_time_keys_helper(1).await;
|
||||||
let one_time_key = bob
|
let one_time_key = bob
|
||||||
.one_time_keys()
|
.one_time_keys()
|
||||||
.await
|
.await
|
||||||
|
|
Loading…
Reference in New Issue