200 lines
5.8 KiB
Rust
200 lines
5.8 KiB
Rust
// Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use std::fmt;
|
|
use std::time::Instant;
|
|
|
|
use olm_rs::account::{IdentityKeys, OlmAccount, OneTimeKeys};
|
|
use olm_rs::errors::{OlmAccountError, OlmSessionError};
|
|
use olm_rs::session::{OlmMessage, OlmSession, PreKeyMessage};
|
|
use olm_rs::PicklingMode;
|
|
|
|
pub struct Account {
|
|
inner: OlmAccount,
|
|
pub(crate) shared: bool,
|
|
}
|
|
|
|
impl fmt::Debug for Account {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(
|
|
f,
|
|
"Olm Account: {:?}, shared: {}",
|
|
self.identity_keys(),
|
|
self.shared
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Marking this as Send is safe because nothing will modify the pointer under
|
|
/// us from the C side. Sync on the other hand is unsafe since libolm doesn't do
|
|
/// any synchronization. We're wrapping the whole Olm machine inside a Mutex to
|
|
/// get Sync for it
|
|
unsafe impl Send for Account {}
|
|
unsafe impl Send for Session {}
|
|
|
|
impl Account {
|
|
/// Create a new account.
|
|
pub fn new() -> Self {
|
|
Account {
|
|
inner: OlmAccount::new(),
|
|
shared: false,
|
|
}
|
|
}
|
|
|
|
/// Get the public parts of the identity keys for the account.
|
|
pub fn identity_keys(&self) -> IdentityKeys {
|
|
self.inner.parsed_identity_keys()
|
|
}
|
|
|
|
/// Has the account been shared with the server.
|
|
pub fn shared(&self) -> bool {
|
|
self.shared
|
|
}
|
|
|
|
/// Get the one-time keys of the account.
|
|
///
|
|
/// This can be empty, keys need to be generated first.
|
|
pub fn one_time_keys(&self) -> OneTimeKeys {
|
|
self.inner.parsed_one_time_keys()
|
|
}
|
|
|
|
/// Generate count number of one-time keys.
|
|
pub fn generate_one_time_keys(&self, count: usize) {
|
|
self.inner.generate_one_time_keys(count);
|
|
}
|
|
|
|
/// Get the maximum number of one-time keys the account can hold.
|
|
pub fn max_one_time_keys(&self) -> usize {
|
|
self.inner.max_number_of_one_time_keys()
|
|
}
|
|
|
|
/// Mark the current set of one-time keys as being published.
|
|
pub fn mark_keys_as_published(&self) {
|
|
self.inner.mark_keys_as_published();
|
|
}
|
|
|
|
pub fn sign(&self, string: &str) -> String {
|
|
self.inner.sign(string)
|
|
}
|
|
|
|
pub fn pickle(&self, pickling_mode: PicklingMode) -> String {
|
|
self.inner.pickle(pickling_mode)
|
|
}
|
|
|
|
pub fn from_pickle(
|
|
pickle: String,
|
|
pickling_mode: PicklingMode,
|
|
shared: bool,
|
|
) -> Result<Self, OlmAccountError> {
|
|
let acc = OlmAccount::unpickle(pickle, pickling_mode)?;
|
|
Ok(Account { inner: acc, shared })
|
|
}
|
|
|
|
pub fn create_inbound_session_from(
|
|
&self,
|
|
their_identity_key: &str,
|
|
message: PreKeyMessage,
|
|
) -> Result<Session, OlmSessionError> {
|
|
let session = self
|
|
.inner
|
|
.create_inbound_session_from(their_identity_key, message)?;
|
|
|
|
let now = Instant::now();
|
|
|
|
Ok(Session {
|
|
inner: session,
|
|
creation_time: now.clone(),
|
|
last_use_time: now,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Account {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.identity_keys() == other.identity_keys() && self.shared == other.shared
|
|
}
|
|
}
|
|
|
|
pub struct Session {
|
|
inner: OlmSession,
|
|
creation_time: Instant,
|
|
last_use_time: Instant,
|
|
}
|
|
|
|
impl Session {
|
|
pub fn decrypt(&mut self, message: OlmMessage) -> Result<String, OlmSessionError> {
|
|
let plaintext = self.inner.decrypt(message)?;
|
|
self.last_use_time = Instant::now();
|
|
Ok(plaintext)
|
|
}
|
|
|
|
pub fn matches(
|
|
&self,
|
|
their_identity_key: &str,
|
|
message: PreKeyMessage,
|
|
) -> Result<bool, OlmSessionError> {
|
|
self.inner
|
|
.matches_inbound_session_from(their_identity_key, message)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use crate::crypto::olm::Account;
|
|
|
|
#[test]
|
|
fn account_creation() {
|
|
let account = Account::new();
|
|
let identyty_keys = account.identity_keys();
|
|
|
|
assert!(!account.shared());
|
|
assert!(!identyty_keys.ed25519().is_empty());
|
|
assert_ne!(identyty_keys.values().len(), 0);
|
|
assert_ne!(identyty_keys.keys().len(), 0);
|
|
assert_ne!(identyty_keys.iter().len(), 0);
|
|
assert!(identyty_keys.contains_key("ed25519"));
|
|
assert_eq!(
|
|
identyty_keys.ed25519(),
|
|
identyty_keys.get("ed25519").unwrap()
|
|
);
|
|
assert!(!identyty_keys.curve25519().is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn one_time_keys_creation() {
|
|
let account = Account::new();
|
|
let one_time_keys = account.one_time_keys();
|
|
|
|
assert!(one_time_keys.curve25519().is_empty());
|
|
assert_ne!(account.max_one_time_keys(), 0);
|
|
|
|
account.generate_one_time_keys(10);
|
|
let one_time_keys = account.one_time_keys();
|
|
|
|
assert!(!one_time_keys.curve25519().is_empty());
|
|
assert_ne!(one_time_keys.values().len(), 0);
|
|
assert_ne!(one_time_keys.keys().len(), 0);
|
|
assert_ne!(one_time_keys.iter().len(), 0);
|
|
assert!(one_time_keys.contains_key("curve25519"));
|
|
assert_eq!(one_time_keys.curve25519().keys().len(), 10);
|
|
assert_eq!(
|
|
one_time_keys.curve25519(),
|
|
one_time_keys.get("curve25519").unwrap()
|
|
);
|
|
|
|
account.mark_keys_as_published();
|
|
let one_time_keys = account.one_time_keys();
|
|
assert!(one_time_keys.curve25519().is_empty());
|
|
}
|
|
}
|