rust-sdk: Add initial crytpto code.
parent
f8b76c6af3
commit
d3903811c6
12
Cargo.toml
12
Cargo.toml
|
@ -10,6 +10,10 @@ readme = "README.md"
|
|||
repository = "https://github.com/matrix-org/matrix-rust-sdk"
|
||||
version = "0.1.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
encryption = ["olm-rs", "serde/derive", "serde_json"]
|
||||
|
||||
[dependencies]
|
||||
js_int = "0.1.2"
|
||||
futures = "0.3.4"
|
||||
|
@ -22,13 +26,11 @@ ruma-events = "0.15.0"
|
|||
log = "0.4.8"
|
||||
|
||||
ruma-identifiers = "0.14.1"
|
||||
serde_json = "1.0.48"
|
||||
serde_urlencoded = "0.6.1"
|
||||
url = "2.1.1"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.104"
|
||||
features = ["derive"]
|
||||
olm-rs = { git = "https://gitlab.gnome.org/jhaye/olm-rs/", optional = true}
|
||||
serde = { version = "1.0.104", optional = true, features = ["derive"] }
|
||||
serde_json = { version = "*", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "0.2.11", features = ["full"] }
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// 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.
|
||||
|
||||
// TODO remove this.
|
||||
#[allow(dead_code)]
|
||||
|
||||
mod olm;
|
|
@ -0,0 +1,191 @@
|
|||
// 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 olm_rs::account::OlmAccount;
|
||||
use std::collections::{hash_map::Iter, hash_map::Keys, hash_map::Values, HashMap};
|
||||
|
||||
use serde;
|
||||
use serde::Deserialize;
|
||||
|
||||
|
||||
/// Struct representing the parsed result of `OlmAccount::identity_keys()`.
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
pub struct IdentityKeys {
|
||||
#[serde(flatten)]
|
||||
keys: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl IdentityKeys {
|
||||
/// Get the public part of the ed25519 key of the account.
|
||||
pub fn ed25519(&self) -> &str {
|
||||
&self.keys["ed25519"]
|
||||
}
|
||||
|
||||
/// Get the public part of the curve25519 key of the account.
|
||||
pub fn curve25519(&self) -> &str {
|
||||
&self.keys["curve25519"]
|
||||
}
|
||||
|
||||
/// Get a reference to the key of the given key type.
|
||||
pub fn get(&self, key_type: &str) -> Option<&str> {
|
||||
let ret = self.keys.get(key_type);
|
||||
ret.map(|x| &**x)
|
||||
}
|
||||
|
||||
/// An iterator visiting all public keys of the account.
|
||||
pub fn values(&self) -> Values<String, String> {
|
||||
self.keys.values()
|
||||
}
|
||||
|
||||
/// An iterator visiting all key types of the account.
|
||||
pub fn keys(&self) -> Keys<String, String> {
|
||||
self.keys.keys()
|
||||
}
|
||||
|
||||
/// An iterator visiting all key-type, key pairs of the account.
|
||||
pub fn iter(&self) -> Iter<String, String> {
|
||||
self.keys.iter()
|
||||
}
|
||||
|
||||
/// Returns true if the account contains a key with the given key type.
|
||||
pub fn contains_key(&self, key_type: &str) -> bool {
|
||||
self.keys.contains_key(key_type)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
/// Struct representing the the one-time keys.
|
||||
/// The keys can be accessed in a map-like fashion.
|
||||
pub struct OneTimeKeys {
|
||||
#[serde(flatten)]
|
||||
keys: HashMap<String, HashMap<String, String>>,
|
||||
}
|
||||
|
||||
impl OneTimeKeys {
|
||||
/// Get the HashMap containing the curve25519 one-time keys.
|
||||
/// This is the same as using `get("curve25519").unwrap()`
|
||||
pub fn curve25519(&self) -> &HashMap<String, String> {
|
||||
&self.keys["curve25519"]
|
||||
}
|
||||
|
||||
/// Get a reference to the hashmap corresponding to given key type.
|
||||
pub fn get(&self, key_type: &str) -> Option<&HashMap<String, String>> {
|
||||
self.keys.get(key_type)
|
||||
}
|
||||
|
||||
/// An iterator visiting all one-time key hashmaps in an arbitrary order.
|
||||
pub fn values(&self) -> Values<String, HashMap<String, String>> {
|
||||
self.keys.values()
|
||||
}
|
||||
|
||||
/// An iterator visiting all one-time key types in an arbitrary order.
|
||||
pub fn keys(&self) -> Keys<String, HashMap<String, String>> {
|
||||
self.keys.keys()
|
||||
}
|
||||
|
||||
/// An iterator visiting all one-time key types and their respective
|
||||
/// key hashmaps in an arbitrary order.
|
||||
pub fn iter(&self) -> Iter<String, HashMap<String, String>> {
|
||||
self.keys.iter()
|
||||
}
|
||||
|
||||
/// Returns `true` if the struct contains the given key type.
|
||||
/// This does not mean that there are any keys for the given key type.
|
||||
pub fn contains_key(&self, key_type: &str) -> bool {
|
||||
self.keys.contains_key(key_type)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Account {
|
||||
inner: OlmAccount,
|
||||
shared: bool,
|
||||
}
|
||||
|
||||
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 {
|
||||
serde_json::from_str(&self.inner.identity_keys()).expect("Can't parse the 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 {
|
||||
serde_json::from_str(&self.inner.one_time_keys()).expect("Can't parse the 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()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[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());
|
||||
}
|
||||
}
|
20
src/error.rs
20
src/error.rs
|
@ -21,8 +21,6 @@ use std::fmt::{Display, Formatter, Result as FmtResult};
|
|||
use reqwest::Error as ReqwestError;
|
||||
use ruma_api::error::FromHttpResponseError as RumaResponseError;
|
||||
use ruma_api::error::IntoHttpError as RumaIntoHttpError;
|
||||
use serde_json::Error as SerdeJsonError;
|
||||
use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError;
|
||||
use url::ParseError;
|
||||
|
||||
/// An error that can occur during client operations.
|
||||
|
@ -37,8 +35,6 @@ impl Display for Error {
|
|||
InnerError::Uri(_) => "Provided string could not be converted into a URI.",
|
||||
InnerError::RumaResponseError(_) => "An error occurred converting between ruma_client_api and hyper types.",
|
||||
InnerError::IntoHttpError(_) => "An error occurred converting between ruma_client_api and hyper types.",
|
||||
InnerError::SerdeJson(_) => "A serialization error occurred.",
|
||||
InnerError::SerdeUrlEncodedSerialize(_) => "An error occurred serializing data to a query string.",
|
||||
};
|
||||
|
||||
write!(f, "{}", message)
|
||||
|
@ -60,10 +56,6 @@ pub(crate) enum InnerError {
|
|||
RumaResponseError(RumaResponseError),
|
||||
/// An error converting between ruma_client_api types and Hyper types.
|
||||
IntoHttpError(RumaIntoHttpError),
|
||||
/// An error when serializing or deserializing a JSON value.
|
||||
SerdeJson(SerdeJsonError),
|
||||
/// An error when serializing a query string value.
|
||||
SerdeUrlEncodedSerialize(SerdeUrlEncodedSerializeError),
|
||||
}
|
||||
|
||||
impl From<ParseError> for Error {
|
||||
|
@ -84,18 +76,6 @@ impl From<RumaIntoHttpError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<SerdeJsonError> for Error {
|
||||
fn from(error: SerdeJsonError) -> Self {
|
||||
Self(InnerError::SerdeJson(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SerdeUrlEncodedSerializeError> for Error {
|
||||
fn from(error: SerdeUrlEncodedSerializeError) -> Self {
|
||||
Self(InnerError::SerdeUrlEncodedSerialize(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ReqwestError> for Error {
|
||||
fn from(error: ReqwestError) -> Self {
|
||||
Self(InnerError::Reqwest(error))
|
||||
|
|
|
@ -27,6 +27,9 @@ mod base_client;
|
|||
mod error;
|
||||
mod session;
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
mod crypto;
|
||||
|
||||
pub use async_client::{AsyncClient, AsyncClientConfig, SyncSettings};
|
||||
pub use base_client::{Client, Room};
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
use ruma_identifiers::UserId;
|
||||
|
||||
/// A user session, containing an access token and information about the associated user account.
|
||||
#[derive(Clone, Debug, serde::Deserialize, Eq, Hash, PartialEq, serde::Serialize)]
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Session {
|
||||
/// The access token used for this session.
|
||||
pub access_token: String,
|
||||
|
|
Loading…
Reference in New Issue