Introduce a Base64 type and use it where applicable
This commit is contained in:
parent
1bdeebbd00
commit
4c859c5aeb
@ -19,7 +19,7 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{DeviceKeyId, UserId};
|
use ruma_identifiers::{DeviceKeyId, UserId};
|
||||||
use ruma_serde::Raw;
|
use ruma_serde::{Base64, Raw};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A wrapper around a mapping of session IDs to key data.
|
/// A wrapper around a mapping of session IDs to key data.
|
||||||
@ -46,7 +46,7 @@ pub enum BackupAlgorithm {
|
|||||||
#[serde(rename = "m.megolm_backup.v1.curve25519-aes-sha2")]
|
#[serde(rename = "m.megolm_backup.v1.curve25519-aes-sha2")]
|
||||||
MegolmBackupV1Curve25519AesSha2 {
|
MegolmBackupV1Curve25519AesSha2 {
|
||||||
/// The curve25519 public key used to encrypt the backups, encoded in unpadded base64.
|
/// The curve25519 public key used to encrypt the backups, encoded in unpadded base64.
|
||||||
public_key: String,
|
public_key: Base64,
|
||||||
|
|
||||||
/// Signatures of the auth_data as Signed JSON.
|
/// Signatures of the auth_data as Signed JSON.
|
||||||
signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,
|
signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,
|
||||||
@ -109,13 +109,13 @@ impl From<KeyBackupDataInit> for KeyBackupData {
|
|||||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
pub struct SessionData {
|
pub struct SessionData {
|
||||||
/// Unpadded base64-encoded public half of the ephemeral key.
|
/// Unpadded base64-encoded public half of the ephemeral key.
|
||||||
pub ephemeral: String,
|
pub ephemeral: Base64,
|
||||||
|
|
||||||
/// Ciphertext, encrypted using AES-CBC-256 with PKCS#7 padding, encoded in base64.
|
/// Ciphertext, encrypted using AES-CBC-256 with PKCS#7 padding, encoded in base64.
|
||||||
pub ciphertext: String,
|
pub ciphertext: Base64,
|
||||||
|
|
||||||
/// First 8 bytes of MAC key, encoded in base64.
|
/// First 8 bytes of MAC key, encoded in base64.
|
||||||
pub mac: String,
|
pub mac: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The algorithm used for storing backups.
|
/// The algorithm used for storing backups.
|
||||||
@ -126,13 +126,13 @@ pub struct SessionData {
|
|||||||
#[allow(clippy::exhaustive_structs)]
|
#[allow(clippy::exhaustive_structs)]
|
||||||
pub struct SessionDataInit {
|
pub struct SessionDataInit {
|
||||||
/// Unpadded base64-encoded public half of the ephemeral key.
|
/// Unpadded base64-encoded public half of the ephemeral key.
|
||||||
pub ephemeral: String,
|
pub ephemeral: Base64,
|
||||||
|
|
||||||
/// Ciphertext, encrypted using AES-CBC-256 with PKCS#7 padding, encoded in base64.
|
/// Ciphertext, encrypted using AES-CBC-256 with PKCS#7 padding, encoded in base64.
|
||||||
pub ciphertext: String,
|
pub ciphertext: Base64,
|
||||||
|
|
||||||
/// First 8 bytes of MAC key, encoded in base64.
|
/// First 8 bytes of MAC key, encoded in base64.
|
||||||
pub mac: String,
|
pub mac: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SessionDataInit> for SessionData {
|
impl From<SessionDataInit> for SessionData {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use ruma_identifiers::{DeviceId, DeviceKeyId, EventEncryptionAlgorithm, UserId};
|
use ruma_identifiers::{DeviceId, DeviceKeyId, EventEncryptionAlgorithm, UserId};
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Identity keys for a device.
|
/// Identity keys for a device.
|
||||||
@ -79,7 +80,7 @@ pub type SignedKeySignatures = BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>,
|
|||||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
pub struct SignedKey {
|
pub struct SignedKey {
|
||||||
/// Base64-encoded 32-byte Curve25519 public key.
|
/// Base64-encoded 32-byte Curve25519 public key.
|
||||||
pub key: String,
|
pub key: Base64,
|
||||||
|
|
||||||
/// Signatures for the key object.
|
/// Signatures for the key object.
|
||||||
pub signatures: SignedKeySignatures,
|
pub signatures: SignedKeySignatures,
|
||||||
@ -92,7 +93,7 @@ pub struct SignedKey {
|
|||||||
|
|
||||||
impl SignedKey {
|
impl SignedKey {
|
||||||
/// Creates a new `SignedKey` with the given key and signatures.
|
/// Creates a new `SignedKey` with the given key and signatures.
|
||||||
pub fn new(key: String, signatures: SignedKeySignatures) -> Self {
|
pub fn new(key: Base64, signatures: SignedKeySignatures) -> Self {
|
||||||
Self {
|
Self {
|
||||||
key,
|
key,
|
||||||
signatures,
|
signatures,
|
||||||
@ -103,7 +104,7 @@ impl SignedKey {
|
|||||||
|
|
||||||
/// Creates a new fallback `SignedKey` with the given key and signatures.
|
/// Creates a new fallback `SignedKey` with the given key and signatures.
|
||||||
#[cfg(feature = "unstable-pre-spec")]
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
pub fn new_fallback(key: String, signatures: SignedKeySignatures) -> Self {
|
pub fn new_fallback(key: Base64, signatures: SignedKeySignatures) -> Self {
|
||||||
Self { key, signatures, fallback: true }
|
Self { key, signatures, fallback: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use ruma_events_macros::EventContent;
|
use ruma_events_macros::EventContent;
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
@ -118,7 +119,7 @@ pub struct SasV1Content {
|
|||||||
/// The hash (encoded as unpadded base64) of the concatenation of the
|
/// The hash (encoded as unpadded base64) of the concatenation of the
|
||||||
/// device's ephemeral public key (encoded as unpadded base64) and the
|
/// device's ephemeral public key (encoded as unpadded base64) and the
|
||||||
/// canonical JSON representation of the `m.key.verification.start` message.
|
/// canonical JSON representation of the `m.key.verification.start` message.
|
||||||
pub commitment: String,
|
pub commitment: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mandatory initial set of fields for creating an accept `SasV1Content`.
|
/// Mandatory initial set of fields for creating an accept `SasV1Content`.
|
||||||
@ -146,7 +147,7 @@ pub struct SasV1ContentInit {
|
|||||||
/// The hash (encoded as unpadded base64) of the concatenation of the
|
/// The hash (encoded as unpadded base64) of the concatenation of the
|
||||||
/// device's ephemeral public key (encoded as unpadded base64) and the
|
/// device's ephemeral public key (encoded as unpadded base64) and the
|
||||||
/// canonical JSON representation of the `m.key.verification.start` message.
|
/// canonical JSON representation of the `m.key.verification.start` message.
|
||||||
pub commitment: String,
|
pub commitment: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SasV1ContentInit> for SasV1Content {
|
impl From<SasV1ContentInit> for SasV1Content {
|
||||||
@ -170,6 +171,7 @@ mod tests {
|
|||||||
#[cfg(feature = "unstable-pre-spec")]
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
use ruma_identifiers::event_id;
|
use ruma_identifiers::event_id;
|
||||||
use ruma_identifiers::user_id;
|
use ruma_identifiers::user_id;
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde_json::{
|
use serde_json::{
|
||||||
from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue,
|
from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue,
|
||||||
};
|
};
|
||||||
@ -193,7 +195,7 @@ mod tests {
|
|||||||
key_agreement_protocol: KeyAgreementProtocol::Curve25519,
|
key_agreement_protocol: KeyAgreementProtocol::Curve25519,
|
||||||
message_authentication_code: MessageAuthenticationCode::HkdfHmacSha256,
|
message_authentication_code: MessageAuthenticationCode::HkdfHmacSha256,
|
||||||
short_authentication_string: vec![ShortAuthenticationString::Decimal],
|
short_authentication_string: vec![ShortAuthenticationString::Decimal],
|
||||||
commitment: "test_commitment".into(),
|
commitment: Base64::new(b"hello".to_vec()),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -203,7 +205,7 @@ mod tests {
|
|||||||
"content": {
|
"content": {
|
||||||
"transaction_id": "456",
|
"transaction_id": "456",
|
||||||
"method": "m.sas.v1",
|
"method": "m.sas.v1",
|
||||||
"commitment": "test_commitment",
|
"commitment": "aGVsbG8",
|
||||||
"key_agreement_protocol": "curve25519",
|
"key_agreement_protocol": "curve25519",
|
||||||
"hash": "sha256",
|
"hash": "sha256",
|
||||||
"message_authentication_code": "hkdf-hmac-sha256",
|
"message_authentication_code": "hkdf-hmac-sha256",
|
||||||
@ -258,13 +260,13 @@ mod tests {
|
|||||||
key_agreement_protocol: KeyAgreementProtocol::Curve25519,
|
key_agreement_protocol: KeyAgreementProtocol::Curve25519,
|
||||||
message_authentication_code: MessageAuthenticationCode::HkdfHmacSha256,
|
message_authentication_code: MessageAuthenticationCode::HkdfHmacSha256,
|
||||||
short_authentication_string: vec![ShortAuthenticationString::Decimal],
|
short_authentication_string: vec![ShortAuthenticationString::Decimal],
|
||||||
commitment: "test_commitment".into(),
|
commitment: Base64::new(b"hello".to_vec()),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let json_data = json!({
|
let json_data = json!({
|
||||||
"method": "m.sas.v1",
|
"method": "m.sas.v1",
|
||||||
"commitment": "test_commitment",
|
"commitment": "aGVsbG8",
|
||||||
"key_agreement_protocol": "curve25519",
|
"key_agreement_protocol": "curve25519",
|
||||||
"hash": "sha256",
|
"hash": "sha256",
|
||||||
"message_authentication_code": "hkdf-hmac-sha256",
|
"message_authentication_code": "hkdf-hmac-sha256",
|
||||||
@ -282,7 +284,7 @@ mod tests {
|
|||||||
fn deserialization() {
|
fn deserialization() {
|
||||||
let json = json!({
|
let json = json!({
|
||||||
"transaction_id": "456",
|
"transaction_id": "456",
|
||||||
"commitment": "test_commitment",
|
"commitment": "aGVsbG8",
|
||||||
"method": "m.sas.v1",
|
"method": "m.sas.v1",
|
||||||
"hash": "sha256",
|
"hash": "sha256",
|
||||||
"key_agreement_protocol": "curve25519",
|
"key_agreement_protocol": "curve25519",
|
||||||
@ -302,7 +304,7 @@ mod tests {
|
|||||||
message_authentication_code,
|
message_authentication_code,
|
||||||
short_authentication_string,
|
short_authentication_string,
|
||||||
})
|
})
|
||||||
} if commitment == "test_commitment"
|
} if commitment.encode() == "aGVsbG8"
|
||||||
&& transaction_id == "456"
|
&& transaction_id == "456"
|
||||||
&& hash == HashAlgorithm::Sha256
|
&& hash == HashAlgorithm::Sha256
|
||||||
&& key_agreement_protocol == KeyAgreementProtocol::Curve25519
|
&& key_agreement_protocol == KeyAgreementProtocol::Curve25519
|
||||||
@ -314,7 +316,7 @@ mod tests {
|
|||||||
|
|
||||||
let json = json!({
|
let json = json!({
|
||||||
"content": {
|
"content": {
|
||||||
"commitment": "test_commitment",
|
"commitment": "aGVsbG8",
|
||||||
"transaction_id": "456",
|
"transaction_id": "456",
|
||||||
"method": "m.sas.v1",
|
"method": "m.sas.v1",
|
||||||
"key_agreement_protocol": "curve25519",
|
"key_agreement_protocol": "curve25519",
|
||||||
@ -340,7 +342,7 @@ mod tests {
|
|||||||
short_authentication_string,
|
short_authentication_string,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} if commitment == "test_commitment"
|
} if commitment.encode() == "aGVsbG8"
|
||||||
&& sender == user_id!("@example:localhost")
|
&& sender == user_id!("@example:localhost")
|
||||||
&& transaction_id == "456"
|
&& transaction_id == "456"
|
||||||
&& hash == HashAlgorithm::Sha256
|
&& hash == HashAlgorithm::Sha256
|
||||||
@ -386,7 +388,7 @@ mod tests {
|
|||||||
let id = event_id!("$1598361704261elfgc:localhost");
|
let id = event_id!("$1598361704261elfgc:localhost");
|
||||||
|
|
||||||
let json = json!({
|
let json = json!({
|
||||||
"commitment": "test_commitment",
|
"commitment": "aGVsbG8",
|
||||||
"method": "m.sas.v1",
|
"method": "m.sas.v1",
|
||||||
"hash": "sha256",
|
"hash": "sha256",
|
||||||
"key_agreement_protocol": "curve25519",
|
"key_agreement_protocol": "curve25519",
|
||||||
@ -412,7 +414,7 @@ mod tests {
|
|||||||
message_authentication_code,
|
message_authentication_code,
|
||||||
short_authentication_string,
|
short_authentication_string,
|
||||||
})
|
})
|
||||||
} if commitment == "test_commitment"
|
} if commitment.encode() == "aGVsbG8"
|
||||||
&& *event_id == *id
|
&& *event_id == *id
|
||||||
&& hash == HashAlgorithm::Sha256
|
&& hash == HashAlgorithm::Sha256
|
||||||
&& key_agreement_protocol == KeyAgreementProtocol::Curve25519
|
&& key_agreement_protocol == KeyAgreementProtocol::Curve25519
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
//! [`m.key.verification.key`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationkey
|
//! [`m.key.verification.key`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationkey
|
||||||
|
|
||||||
use ruma_events_macros::EventContent;
|
use ruma_events_macros::EventContent;
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(feature = "unstable-pre-spec")]
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
@ -20,14 +21,14 @@ pub struct ToDeviceKeyVerificationKeyEventContent {
|
|||||||
/// Must be the same as the one used for the `m.key.verification.start` message.
|
/// Must be the same as the one used for the `m.key.verification.start` message.
|
||||||
pub transaction_id: String,
|
pub transaction_id: String,
|
||||||
|
|
||||||
/// The device's ephemeral public key, encoded as unpadded Base64.
|
/// The device's ephemeral public key, encoded as unpadded base64.
|
||||||
pub key: String,
|
pub key: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToDeviceKeyVerificationKeyEventContent {
|
impl ToDeviceKeyVerificationKeyEventContent {
|
||||||
/// Creates a new `ToDeviceKeyVerificationKeyEventContent` with the given transaction ID and
|
/// Creates a new `ToDeviceKeyVerificationKeyEventContent` with the given transaction ID and
|
||||||
/// key.
|
/// key.
|
||||||
pub fn new(transaction_id: String, key: String) -> Self {
|
pub fn new(transaction_id: String, key: Base64) -> Self {
|
||||||
Self { transaction_id, key }
|
Self { transaction_id, key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,8 +41,8 @@ impl ToDeviceKeyVerificationKeyEventContent {
|
|||||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
#[ruma_event(type = "m.key.verification.key", kind = Message)]
|
#[ruma_event(type = "m.key.verification.key", kind = Message)]
|
||||||
pub struct KeyVerificationKeyEventContent {
|
pub struct KeyVerificationKeyEventContent {
|
||||||
/// The device's ephemeral public key, encoded as unpadded Base64.
|
/// The device's ephemeral public key, encoded as unpadded base64.
|
||||||
pub key: String,
|
pub key: Base64,
|
||||||
|
|
||||||
/// Information about the related event.
|
/// Information about the related event.
|
||||||
#[serde(rename = "m.relates_to")]
|
#[serde(rename = "m.relates_to")]
|
||||||
@ -51,7 +52,7 @@ pub struct KeyVerificationKeyEventContent {
|
|||||||
#[cfg(feature = "unstable-pre-spec")]
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
impl KeyVerificationKeyEventContent {
|
impl KeyVerificationKeyEventContent {
|
||||||
/// Creates a new `KeyVerificationKeyEventContent` with the given key and relation.
|
/// Creates a new `KeyVerificationKeyEventContent` with the given key and relation.
|
||||||
pub fn new(key: String, relates_to: Relation) -> Self {
|
pub fn new(key: Base64, relates_to: Relation) -> Self {
|
||||||
Self { key, relates_to }
|
Self { key, relates_to }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use ruma_events_macros::EventContent;
|
use ruma_events_macros::EventContent;
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(feature = "unstable-pre-spec")]
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
@ -24,18 +25,18 @@ pub struct ToDeviceKeyVerificationMacEventContent {
|
|||||||
|
|
||||||
/// A map of the key ID to the MAC of the key, using the algorithm in the verification process.
|
/// A map of the key ID to the MAC of the key, using the algorithm in the verification process.
|
||||||
///
|
///
|
||||||
/// The MAC is encoded as unpadded Base64.
|
/// The MAC is encoded as unpadded base64.
|
||||||
pub mac: BTreeMap<String, String>,
|
pub mac: BTreeMap<String, Base64>,
|
||||||
|
|
||||||
/// The MAC of the comma-separated, sorted, list of key IDs given in the `mac` property,
|
/// The MAC of the comma-separated, sorted, list of key IDs given in the `mac` property,
|
||||||
/// encoded as unpadded Base64.
|
/// encoded as unpadded base64.
|
||||||
pub keys: String,
|
pub keys: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToDeviceKeyVerificationMacEventContent {
|
impl ToDeviceKeyVerificationMacEventContent {
|
||||||
/// Creates a new `ToDeviceKeyVerificationMacEventContent` with the given transaction ID, key ID
|
/// Creates a new `ToDeviceKeyVerificationMacEventContent` with the given transaction ID, key ID
|
||||||
/// to MAC map and key MAC.
|
/// to MAC map and key MAC.
|
||||||
pub fn new(transaction_id: String, mac: BTreeMap<String, String>, keys: String) -> Self {
|
pub fn new(transaction_id: String, mac: BTreeMap<String, Base64>, keys: Base64) -> Self {
|
||||||
Self { transaction_id, mac, keys }
|
Self { transaction_id, mac, keys }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,12 +51,12 @@ impl ToDeviceKeyVerificationMacEventContent {
|
|||||||
pub struct KeyVerificationMacEventContent {
|
pub struct KeyVerificationMacEventContent {
|
||||||
/// A map of the key ID to the MAC of the key, using the algorithm in the verification process.
|
/// A map of the key ID to the MAC of the key, using the algorithm in the verification process.
|
||||||
///
|
///
|
||||||
/// The MAC is encoded as unpadded Base64.
|
/// The MAC is encoded as unpadded base64.
|
||||||
pub mac: BTreeMap<String, String>,
|
pub mac: BTreeMap<String, Base64>,
|
||||||
|
|
||||||
/// The MAC of the comma-separated, sorted, list of key IDs given in the `mac` property,
|
/// The MAC of the comma-separated, sorted, list of key IDs given in the `mac` property,
|
||||||
/// encoded as unpadded Base64.
|
/// encoded as unpadded base64.
|
||||||
pub keys: String,
|
pub keys: Base64,
|
||||||
|
|
||||||
/// Information about the related event.
|
/// Information about the related event.
|
||||||
#[serde(rename = "m.relates_to")]
|
#[serde(rename = "m.relates_to")]
|
||||||
@ -66,7 +67,7 @@ pub struct KeyVerificationMacEventContent {
|
|||||||
impl KeyVerificationMacEventContent {
|
impl KeyVerificationMacEventContent {
|
||||||
/// Creates a new `KeyVerificationMacEventContent` with the given key ID to MAC map, key MAC and
|
/// Creates a new `KeyVerificationMacEventContent` with the given key ID to MAC map, key MAC and
|
||||||
/// relation.
|
/// relation.
|
||||||
pub fn new(mac: BTreeMap<String, String>, keys: String, relates_to: Relation) -> Self {
|
pub fn new(mac: BTreeMap<String, Base64>, keys: Base64, relates_to: Relation) -> Self {
|
||||||
Self { mac, keys, relates_to }
|
Self { mac, keys, relates_to }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use ruma_events_macros::EventContent;
|
use ruma_events_macros::EventContent;
|
||||||
use ruma_identifiers::DeviceId;
|
use ruma_identifiers::DeviceId;
|
||||||
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
@ -115,7 +117,7 @@ pub struct _CustomContent {
|
|||||||
#[serde(rename = "m.reciprocate.v1", tag = "method")]
|
#[serde(rename = "m.reciprocate.v1", tag = "method")]
|
||||||
pub struct ReciprocateV1Content {
|
pub struct ReciprocateV1Content {
|
||||||
/// The shared secret from the QR code, encoded using unpadded base64.
|
/// The shared secret from the QR code, encoded using unpadded base64.
|
||||||
pub secret: String,
|
pub secret: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unstable-pre-spec")]
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
@ -123,7 +125,7 @@ impl ReciprocateV1Content {
|
|||||||
/// Create a new `ReciprocateV1Content` with the given shared secret.
|
/// Create a new `ReciprocateV1Content` with the given shared secret.
|
||||||
///
|
///
|
||||||
/// The shared secret needs to come from the scanned QR code, encoded using unpadded base64.
|
/// The shared secret needs to come from the scanned QR code, encoded using unpadded base64.
|
||||||
pub fn new(secret: String) -> Self {
|
pub fn new(secret: Base64) -> Self {
|
||||||
Self { secret }
|
Self { secret }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,6 +207,8 @@ mod tests {
|
|||||||
#[cfg(feature = "unstable-pre-spec")]
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
use ruma_identifiers::event_id;
|
use ruma_identifiers::event_id;
|
||||||
use ruma_identifiers::user_id;
|
use ruma_identifiers::user_id;
|
||||||
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde_json::{
|
use serde_json::{
|
||||||
from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue,
|
from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue,
|
||||||
};
|
};
|
||||||
@ -288,7 +292,7 @@ mod tests {
|
|||||||
|
|
||||||
#[cfg(feature = "unstable-pre-spec")]
|
#[cfg(feature = "unstable-pre-spec")]
|
||||||
{
|
{
|
||||||
let secret = "This is a secret to everybody".to_owned();
|
let secret = Base64::new(b"This is a secret to everybody".to_vec());
|
||||||
|
|
||||||
let key_verification_start_content = ToDeviceKeyVerificationStartEventContent {
|
let key_verification_start_content = ToDeviceKeyVerificationStartEventContent {
|
||||||
from_device: "123".into(),
|
from_device: "123".into(),
|
||||||
@ -341,7 +345,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(to_json_value(&key_verification_start_content).unwrap(), json_data);
|
assert_eq!(to_json_value(&key_verification_start_content).unwrap(), json_data);
|
||||||
|
|
||||||
let secret = "This is a secret to everybody".to_owned();
|
let secret = Base64::new(b"This is a secret to everybody".to_vec());
|
||||||
|
|
||||||
let key_verification_start_content = KeyVerificationStartEventContent {
|
let key_verification_start_content = KeyVerificationStartEventContent {
|
||||||
from_device: "123".into(),
|
from_device: "123".into(),
|
||||||
@ -468,7 +472,7 @@ mod tests {
|
|||||||
"content": {
|
"content": {
|
||||||
"from_device": "123",
|
"from_device": "123",
|
||||||
"method": "m.reciprocate.v1",
|
"method": "m.reciprocate.v1",
|
||||||
"secret": "It's a secret to everybody",
|
"secret": "c2VjcmV0Cg",
|
||||||
"transaction_id": "456",
|
"transaction_id": "456",
|
||||||
},
|
},
|
||||||
"type": "m.key.verification.start",
|
"type": "m.key.verification.start",
|
||||||
@ -487,7 +491,7 @@ mod tests {
|
|||||||
} if from_device == "123"
|
} if from_device == "123"
|
||||||
&& sender == user_id!("@example:localhost")
|
&& sender == user_id!("@example:localhost")
|
||||||
&& transaction_id == "456"
|
&& transaction_id == "456"
|
||||||
&& secret == "It's a secret to everybody"
|
&& secret.encode() == "c2VjcmV0Cg"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -533,7 +537,7 @@ mod tests {
|
|||||||
let json = json!({
|
let json = json!({
|
||||||
"from_device": "123",
|
"from_device": "123",
|
||||||
"method": "m.reciprocate.v1",
|
"method": "m.reciprocate.v1",
|
||||||
"secret": "It's a secret to everybody",
|
"secret": "c2VjcmV0Cg",
|
||||||
"m.relates_to": {
|
"m.relates_to": {
|
||||||
"rel_type": "m.reference",
|
"rel_type": "m.reference",
|
||||||
"event_id": id,
|
"event_id": id,
|
||||||
@ -548,7 +552,7 @@ mod tests {
|
|||||||
method: StartMethod::ReciprocateV1(ReciprocateV1Content { secret }),
|
method: StartMethod::ReciprocateV1(ReciprocateV1Content { secret }),
|
||||||
} if from_device == "123"
|
} if from_device == "123"
|
||||||
&& event_id == id
|
&& event_id == id
|
||||||
&& secret == "It's a secret to everybody"
|
&& secret.encode() == "c2VjcmV0Cg"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::MxcUri;
|
use ruma_identifiers::MxcUri;
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod aliases;
|
pub mod aliases;
|
||||||
@ -122,12 +123,12 @@ pub struct EncryptedFile {
|
|||||||
pub key: JsonWebKey,
|
pub key: JsonWebKey,
|
||||||
|
|
||||||
/// The 128-bit unique counter block used by AES-CTR, encoded as unpadded base64.
|
/// The 128-bit unique counter block used by AES-CTR, encoded as unpadded base64.
|
||||||
pub iv: String,
|
pub iv: Base64,
|
||||||
|
|
||||||
/// A map from an algorithm name to a hash of the ciphertext, encoded as unpadded base64.
|
/// A map from an algorithm name to a hash of the ciphertext, encoded as unpadded base64.
|
||||||
///
|
///
|
||||||
/// Clients should support the SHA-256 hash, which uses the key sha256.
|
/// Clients should support the SHA-256 hash, which uses the key sha256.
|
||||||
pub hashes: BTreeMap<String, String>,
|
pub hashes: BTreeMap<String, Base64>,
|
||||||
|
|
||||||
/// Version of the encrypted attachments protocol.
|
/// Version of the encrypted attachments protocol.
|
||||||
///
|
///
|
||||||
@ -149,12 +150,12 @@ pub struct EncryptedFileInit {
|
|||||||
pub key: JsonWebKey,
|
pub key: JsonWebKey,
|
||||||
|
|
||||||
/// The 128-bit unique counter block used by AES-CTR, encoded as unpadded base64.
|
/// The 128-bit unique counter block used by AES-CTR, encoded as unpadded base64.
|
||||||
pub iv: String,
|
pub iv: Base64,
|
||||||
|
|
||||||
/// A map from an algorithm name to a hash of the ciphertext, encoded as unpadded base64.
|
/// A map from an algorithm name to a hash of the ciphertext, encoded as unpadded base64.
|
||||||
///
|
///
|
||||||
/// Clients should support the SHA-256 hash, which uses the key sha256.
|
/// Clients should support the SHA-256 hash, which uses the key sha256.
|
||||||
pub hashes: BTreeMap<String, String>,
|
pub hashes: BTreeMap<String, Base64>,
|
||||||
|
|
||||||
/// Version of the encrypted attachments protocol.
|
/// Version of the encrypted attachments protocol.
|
||||||
///
|
///
|
||||||
@ -192,7 +193,7 @@ pub struct JsonWebKey {
|
|||||||
pub alg: String,
|
pub alg: String,
|
||||||
|
|
||||||
/// The key, encoded as url-safe unpadded base64.
|
/// The key, encoded as url-safe unpadded base64.
|
||||||
pub k: String,
|
pub k: Base64,
|
||||||
|
|
||||||
/// Extractable.
|
/// Extractable.
|
||||||
///
|
///
|
||||||
@ -224,7 +225,7 @@ pub struct JsonWebKeyInit {
|
|||||||
pub alg: String,
|
pub alg: String,
|
||||||
|
|
||||||
/// The key, encoded as url-safe unpadded base64.
|
/// The key, encoded as url-safe unpadded base64.
|
||||||
pub k: String,
|
pub k: Base64,
|
||||||
|
|
||||||
/// Extractable.
|
/// Extractable.
|
||||||
///
|
///
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
//! [`m.room.third_party_invite`]: https://spec.matrix.org/v1.1/client-server-api/#mroomthird_party_invite
|
//! [`m.room.third_party_invite`]: https://spec.matrix.org/v1.1/client-server-api/#mroomthird_party_invite
|
||||||
|
|
||||||
use ruma_events_macros::EventContent;
|
use ruma_events_macros::EventContent;
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// The content of an `m.room.third_party_invite` event.
|
/// The content of an `m.room.third_party_invite` event.
|
||||||
@ -30,12 +31,12 @@ pub struct RoomThirdPartyInviteEventContent {
|
|||||||
#[cfg_attr(feature = "compat", serde(default))]
|
#[cfg_attr(feature = "compat", serde(default))]
|
||||||
pub key_validity_url: String,
|
pub key_validity_url: String,
|
||||||
|
|
||||||
/// A Base64-encoded Ed25519 key with which the token must be signed.
|
/// A base64-encoded Ed25519 key with which the token must be signed.
|
||||||
///
|
///
|
||||||
/// If you activate the `compat` feature, this field being absent in JSON will result in an
|
/// If you activate the `compat` feature, this field being absent in JSON will result in an
|
||||||
/// empty string here during deserialization.
|
/// empty string here during deserialization.
|
||||||
#[cfg_attr(feature = "compat", serde(default))]
|
#[cfg_attr(feature = "compat", serde(default = "Base64::empty"))]
|
||||||
pub public_key: String,
|
pub public_key: Base64,
|
||||||
|
|
||||||
/// Keys with which the token may be signed.
|
/// Keys with which the token may be signed.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@ -45,7 +46,7 @@ pub struct RoomThirdPartyInviteEventContent {
|
|||||||
impl RoomThirdPartyInviteEventContent {
|
impl RoomThirdPartyInviteEventContent {
|
||||||
/// Creates a new `RoomThirdPartyInviteEventContent` with the given display name, key validity
|
/// Creates a new `RoomThirdPartyInviteEventContent` with the given display name, key validity
|
||||||
/// url and public key.
|
/// url and public key.
|
||||||
pub fn new(display_name: String, key_validity_url: String, public_key: String) -> Self {
|
pub fn new(display_name: String, key_validity_url: String, public_key: Base64) -> Self {
|
||||||
Self { display_name, key_validity_url, public_key, public_keys: None }
|
Self { display_name, key_validity_url, public_key, public_keys: None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,13 +62,13 @@ pub struct PublicKey {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub key_validity_url: Option<String>,
|
pub key_validity_url: Option<String>,
|
||||||
|
|
||||||
/// A Base64-encoded Ed25519 key with which the token must be signed.
|
/// A base64-encoded Ed25519 key with which the token must be signed.
|
||||||
pub public_key: String,
|
pub public_key: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PublicKey {
|
impl PublicKey {
|
||||||
/// Creates a new `PublicKey` with the given base64-encoded ed25519 key.
|
/// Creates a new `PublicKey` with the given base64-encoded ed25519 key.
|
||||||
pub fn new(public_key: String) -> Self {
|
pub fn new(public_key: Base64) -> Self {
|
||||||
Self { key_validity_url: None, public_key }
|
Self { key_validity_url: None, public_key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use ruma_common::MilliSecondsSinceUnixEpoch;
|
use ruma_common::MilliSecondsSinceUnixEpoch;
|
||||||
use ruma_identifiers::{ServerName, ServerSigningKeyId};
|
use ruma_identifiers::{ServerName, ServerSigningKeyId};
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod discover_homeserver;
|
pub mod discover_homeserver;
|
||||||
@ -16,13 +17,13 @@ pub mod get_server_version;
|
|||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
pub struct VerifyKey {
|
pub struct VerifyKey {
|
||||||
/// The Unpadded Base64 encoded key.
|
/// The unpadded base64-encoded key.
|
||||||
pub key: String,
|
pub key: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerifyKey {
|
impl VerifyKey {
|
||||||
/// Creates a new `VerifyKey` from the given key.
|
/// Creates a new `VerifyKey` from the given key.
|
||||||
pub fn new(key: String) -> Self {
|
pub fn new(key: Base64) -> Self {
|
||||||
Self { key }
|
Self { key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,13 +35,13 @@ pub struct OldVerifyKey {
|
|||||||
/// Timestamp when this key expired.
|
/// Timestamp when this key expired.
|
||||||
pub expired_ts: MilliSecondsSinceUnixEpoch,
|
pub expired_ts: MilliSecondsSinceUnixEpoch,
|
||||||
|
|
||||||
/// The Unpadded Base64 encoded key.
|
/// The unpadded base64-encoded key.
|
||||||
pub key: String,
|
pub key: Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OldVerifyKey {
|
impl OldVerifyKey {
|
||||||
/// Creates a new `OldVerifyKey` with the given expiry time and key.
|
/// Creates a new `OldVerifyKey` with the given expiry time and key.
|
||||||
pub fn new(expired_ts: MilliSecondsSinceUnixEpoch, key: String) -> Self {
|
pub fn new(expired_ts: MilliSecondsSinceUnixEpoch, key: Base64) -> Self {
|
||||||
Self { expired_ts, key }
|
Self { expired_ts, key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use std::collections::BTreeMap;
|
|||||||
use ruma_api::ruma_api;
|
use ruma_api::ruma_api;
|
||||||
use ruma_common::encryption::OneTimeKey;
|
use ruma_common::encryption::OneTimeKey;
|
||||||
use ruma_identifiers::{DeviceId, DeviceKeyAlgorithm, DeviceKeyId, UserId};
|
use ruma_identifiers::{DeviceId, DeviceKeyAlgorithm, DeviceKeyId, UserId};
|
||||||
use ruma_serde::Raw;
|
use ruma_serde::{Base64, Raw};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
ruma_api! {
|
ruma_api! {
|
||||||
@ -56,7 +56,7 @@ pub type OneTimeKeys =
|
|||||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
pub struct KeyObject {
|
pub struct KeyObject {
|
||||||
/// The key, encoded using unpadded base64.
|
/// The key, encoded using unpadded base64.
|
||||||
pub key: String,
|
pub key: Base64,
|
||||||
|
|
||||||
/// Signature of the key object.
|
/// Signature of the key object.
|
||||||
pub signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,
|
pub signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,
|
||||||
@ -65,7 +65,7 @@ pub struct KeyObject {
|
|||||||
impl KeyObject {
|
impl KeyObject {
|
||||||
/// Creates a new `KeyObject` with the given key and signatures.
|
/// Creates a new `KeyObject` with the given key and signatures.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
key: String,
|
key: Base64,
|
||||||
signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,
|
signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self { key, signatures }
|
Self { key, signatures }
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use ruma_api::ruma_api;
|
use ruma_api::ruma_api;
|
||||||
use ruma_identifiers::{ServerSignatures, UserId};
|
use ruma_identifiers::{ServerSignatures, UserId};
|
||||||
|
use ruma_serde::Base64;
|
||||||
|
|
||||||
ruma_api! {
|
ruma_api! {
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -21,7 +22,7 @@ ruma_api! {
|
|||||||
pub token: &'a str,
|
pub token: &'a str,
|
||||||
|
|
||||||
/// The private key, encoded as unpadded base64.
|
/// The private key, encoded as unpadded base64.
|
||||||
pub private_key: &'a str,
|
pub private_key: &'a Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
response: {
|
response: {
|
||||||
@ -41,7 +42,7 @@ ruma_api! {
|
|||||||
|
|
||||||
impl<'a> Request<'a> {
|
impl<'a> Request<'a> {
|
||||||
/// Creates a `Request` with the given Matrix user ID, token and private_key.
|
/// Creates a `Request` with the given Matrix user ID, token and private_key.
|
||||||
pub fn new(mxid: &'a UserId, token: &'a str, private_key: &'a str) -> Self {
|
pub fn new(mxid: &'a UserId, token: &'a str, private_key: &'a Base64) -> Self {
|
||||||
Self { mxid, token, private_key }
|
Self { mxid, token, private_key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! [GET /_matrix/identity/v2/pubkey/isvalid](https://matrix.org/docs/spec/identity_service/r0.3.0#get-matrix-identity-v2-pubkey-isvalid)
|
//! [GET /_matrix/identity/v2/pubkey/isvalid](https://matrix.org/docs/spec/identity_service/r0.3.0#get-matrix-identity-v2-pubkey-isvalid)
|
||||||
|
|
||||||
use ruma_api::ruma_api;
|
use ruma_api::ruma_api;
|
||||||
|
use ruma_serde::Base64;
|
||||||
|
|
||||||
ruma_api! {
|
ruma_api! {
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -15,7 +16,7 @@ ruma_api! {
|
|||||||
request: {
|
request: {
|
||||||
/// Base64-encoded (no padding) public key to check for validity.
|
/// Base64-encoded (no padding) public key to check for validity.
|
||||||
#[ruma_api(query)]
|
#[ruma_api(query)]
|
||||||
pub public_key: &'a str,
|
pub public_key: &'a Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
response: {
|
response: {
|
||||||
@ -26,7 +27,7 @@ ruma_api! {
|
|||||||
|
|
||||||
impl<'a> Request<'a> {
|
impl<'a> Request<'a> {
|
||||||
/// Create a `Request` with the given base64-encoded (unpadded) public key.
|
/// Create a `Request` with the given base64-encoded (unpadded) public key.
|
||||||
pub fn new(public_key: &'a str) -> Self {
|
pub fn new(public_key: &'a Base64) -> Self {
|
||||||
Self { public_key }
|
Self { public_key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use ruma_api::ruma_api;
|
use ruma_api::ruma_api;
|
||||||
use ruma_identifiers::ServerSigningKeyId;
|
use ruma_identifiers::ServerSigningKeyId;
|
||||||
|
use ruma_serde::Base64;
|
||||||
|
|
||||||
ruma_api! {
|
ruma_api! {
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -20,8 +21,8 @@ ruma_api! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response: {
|
response: {
|
||||||
/// Unpadded Base64 encoded public key.
|
/// Unpadded base64-encoded public key.
|
||||||
pub public_key: String,
|
pub public_key: Base64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ impl<'a> Request<'a> {
|
|||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
/// Create a `Response` with the given base64-encoded (unpadded) public key.
|
/// Create a `Response` with the given base64-encoded (unpadded) public key.
|
||||||
pub fn new(public_key: String) -> Self {
|
pub fn new(public_key: Base64) -> Self {
|
||||||
Self { public_key }
|
Self { public_key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! [GET /_matrix/identity/v2/pubkey/ephemeral/isvalid](https://matrix.org/docs/spec/identity_service/r0.3.0#get-matrix-identity-v2-pubkey-ephemeral-isvalid)
|
//! [GET /_matrix/identity/v2/pubkey/ephemeral/isvalid](https://matrix.org/docs/spec/identity_service/r0.3.0#get-matrix-identity-v2-pubkey-ephemeral-isvalid)
|
||||||
|
|
||||||
use ruma_api::ruma_api;
|
use ruma_api::ruma_api;
|
||||||
|
use ruma_serde::Base64;
|
||||||
|
|
||||||
ruma_api! {
|
ruma_api! {
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -15,7 +16,7 @@ ruma_api! {
|
|||||||
request: {
|
request: {
|
||||||
/// The unpadded base64-encoded short-term public key to check.
|
/// The unpadded base64-encoded short-term public key to check.
|
||||||
#[ruma_api(query)]
|
#[ruma_api(query)]
|
||||||
pub public_key: &'a str,
|
pub public_key: &'a Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
response: {
|
response: {
|
||||||
@ -26,7 +27,7 @@ ruma_api! {
|
|||||||
|
|
||||||
impl<'a> Request<'a> {
|
impl<'a> Request<'a> {
|
||||||
/// Create a `Request` with the given base64-encoded (unpadded) short-term public key.
|
/// Create a `Request` with the given base64-encoded (unpadded) short-term public key.
|
||||||
pub fn new(public_key: &'a str) -> Self {
|
pub fn new(public_key: &'a Base64) -> Self {
|
||||||
Self { public_key }
|
Self { public_key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ version = "0.5.0"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
base64 = "0.13.0"
|
||||||
bytes = "1.0.1"
|
bytes = "1.0.1"
|
||||||
form_urlencoded = "1.0.0"
|
form_urlencoded = "1.0.0"
|
||||||
itoa = "0.4.6"
|
itoa = "0.4.6"
|
||||||
|
72
crates/ruma-serde/src/base64.rs
Normal file
72
crates/ruma-serde/src/base64.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
/// DOCS
|
||||||
|
// generic?
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Base64<B = Vec<u8>> {
|
||||||
|
bytes: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
const BASE64_CONFIG: base64::Config = base64::STANDARD_NO_PAD.decode_allow_trailing_bits(true);
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> Base64<B> {
|
||||||
|
/// Create a `Base64` instance from raw bytes, to be base64-encoded in serialialization.
|
||||||
|
pub fn new(bytes: B) -> Self {
|
||||||
|
Self { bytes }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the raw bytes held by this `Base64` instance.
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
self.bytes.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode the bytes contained in this `Base64` instance to unpadded base64.
|
||||||
|
pub fn encode(&self) -> String {
|
||||||
|
base64::encode_config(&self.bytes, BASE64_CONFIG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Base64 {
|
||||||
|
/// Create a `Base64` instance containing an empty `Vec<u8>`.
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self { bytes: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse some base64-encoded data to create a `Base64` instance.
|
||||||
|
pub fn parse(encoded: impl AsRef<[u8]>) -> Result<Self, base64::DecodeError> {
|
||||||
|
base64::decode_config(encoded, BASE64_CONFIG).map(Self::new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> fmt::Debug for Base64<B> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.encode().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> fmt::Display for Base64<B> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.encode().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Base64 {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let encoded = crate::deserialize_cow_str(deserializer)?;
|
||||||
|
Self::parse(&*encoded).map_err(de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> Serialize for Base64<B> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&self.encode())
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
|
mod base64;
|
||||||
mod buf;
|
mod buf;
|
||||||
pub mod can_be_empty;
|
pub mod can_be_empty;
|
||||||
mod canonical_json;
|
mod canonical_json;
|
||||||
@ -19,19 +20,22 @@ mod strings;
|
|||||||
pub mod test;
|
pub mod test;
|
||||||
pub mod urlencoded;
|
pub mod urlencoded;
|
||||||
|
|
||||||
pub use buf::{json_to_buf, slice_to_buf};
|
pub use self::{
|
||||||
pub use can_be_empty::{is_empty, CanBeEmpty};
|
base64::Base64,
|
||||||
pub use canonical_json::{
|
buf::{json_to_buf, slice_to_buf},
|
||||||
|
can_be_empty::{is_empty, CanBeEmpty},
|
||||||
|
canonical_json::{
|
||||||
to_canonical_value, try_from_json_map,
|
to_canonical_value, try_from_json_map,
|
||||||
value::{CanonicalJsonValue, Object as CanonicalJsonObject},
|
value::{CanonicalJsonValue, Object as CanonicalJsonObject},
|
||||||
Error as CanonicalJsonError,
|
Error as CanonicalJsonError,
|
||||||
};
|
},
|
||||||
pub use cow::deserialize_cow_str;
|
cow::deserialize_cow_str,
|
||||||
pub use empty::vec_as_map_of_empty;
|
empty::vec_as_map_of_empty,
|
||||||
pub use raw::Raw;
|
raw::Raw,
|
||||||
pub use strings::{
|
strings::{
|
||||||
btreemap_int_or_string_to_int_values, empty_string_as_none, int_or_string_to_int,
|
btreemap_int_or_string_to_int_values, empty_string_as_none, int_or_string_to_int,
|
||||||
none_as_empty_string,
|
none_as_empty_string,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The inner type of [`JsonValue::Object`].
|
/// The inner type of [`JsonValue::Object`].
|
||||||
|
@ -7,9 +7,9 @@ use std::{
|
|||||||
mem,
|
mem,
|
||||||
};
|
};
|
||||||
|
|
||||||
use base64::{decode_config, encode_config, Config, STANDARD_NO_PAD, URL_SAFE_NO_PAD};
|
use base64::{encode_config, STANDARD_NO_PAD, URL_SAFE_NO_PAD};
|
||||||
use ruma_identifiers::{EventId, RoomVersionId, ServerName, UserId};
|
use ruma_identifiers::{EventId, RoomVersionId, ServerName, UserId};
|
||||||
use ruma_serde::{CanonicalJsonObject, CanonicalJsonValue};
|
use ruma_serde::{Base64, CanonicalJsonObject, CanonicalJsonValue};
|
||||||
use serde_json::{from_str as from_json_str, to_string as to_json_string};
|
use serde_json::{from_str as from_json_str, to_string as to_json_string};
|
||||||
use sha2::{digest::Digest, Sha256};
|
use sha2::{digest::Digest, Sha256};
|
||||||
|
|
||||||
@ -230,7 +230,9 @@ pub fn canonical_json(object: &CanonicalJsonObject) -> Result<String, Error> {
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// use std::collections::BTreeMap;
|
/// use std::collections::BTreeMap;
|
||||||
///
|
///
|
||||||
/// const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
|
/// use ruma_serde::Base64;
|
||||||
|
///
|
||||||
|
/// const PUBLIC_KEY: &[u8] = b"XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
|
||||||
///
|
///
|
||||||
/// // Deserialize the signed JSON.
|
/// // Deserialize the signed JSON.
|
||||||
/// let object = serde_json::from_str(
|
/// let object = serde_json::from_str(
|
||||||
@ -245,7 +247,7 @@ pub fn canonical_json(object: &CanonicalJsonObject) -> Result<String, Error> {
|
|||||||
///
|
///
|
||||||
/// // Create the `PublicKeyMap` that will inform `verify_json` which signatures to verify.
|
/// // Create the `PublicKeyMap` that will inform `verify_json` which signatures to verify.
|
||||||
/// let mut public_key_set = BTreeMap::new();
|
/// let mut public_key_set = BTreeMap::new();
|
||||||
/// public_key_set.insert("ed25519:1".into(), PUBLIC_KEY.to_owned());
|
/// public_key_set.insert("ed25519:1".into(), Base64::parse(PUBLIC_KEY.to_owned()).unwrap());
|
||||||
/// let mut public_key_map = BTreeMap::new();
|
/// let mut public_key_map = BTreeMap::new();
|
||||||
/// public_key_map.insert("domain".into(), public_key_set);
|
/// public_key_map.insert("domain".into(), public_key_set);
|
||||||
///
|
///
|
||||||
@ -289,20 +291,15 @@ pub fn verify_json(
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let verify = |config: Config| {
|
let signature = Base64::parse(signature)
|
||||||
let signature_bytes = decode_config(signature, config)
|
|
||||||
.map_err(|e| ParseError::base64("signature", signature, e))?;
|
.map_err(|e| ParseError::base64("signature", signature, e))?;
|
||||||
|
|
||||||
let public_key_bytes = decode_config(&public_key, config)
|
verify_json_with(
|
||||||
.map_err(|e| ParseError::base64("public key", public_key, e))?;
|
&Ed25519Verifier,
|
||||||
|
public_key.as_bytes(),
|
||||||
verify_json_with(&Ed25519Verifier, &public_key_bytes, &signature_bytes, object)
|
signature.as_bytes(),
|
||||||
};
|
object,
|
||||||
|
)?;
|
||||||
#[cfg(feature = "compat")]
|
|
||||||
also_try_forgiving_base64(STANDARD_NO_PAD, verify)?;
|
|
||||||
#[cfg(not(feature = "compat"))]
|
|
||||||
verify(STANDARD_NO_PAD)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +332,7 @@ where
|
|||||||
|
|
||||||
/// Creates a *content hash* for an event.
|
/// Creates a *content hash* for an event.
|
||||||
///
|
///
|
||||||
/// Returns the hash as a Base64-encoded string, using the standard character set, without padding.
|
/// Returns the hash as a base64-encoded string, using the standard character set, without padding.
|
||||||
///
|
///
|
||||||
/// The content hash of an event covers the complete event including the unredacted contents. It is
|
/// The content hash of an event covers the complete event including the unredacted contents. It is
|
||||||
/// used during federation and is described in the Matrix server-server specification.
|
/// used during federation and is described in the Matrix server-server specification.
|
||||||
@ -347,7 +344,7 @@ where
|
|||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns an error if the event is too large.
|
/// Returns an error if the event is too large.
|
||||||
pub fn content_hash(object: &CanonicalJsonObject) -> Result<String, Error> {
|
pub fn content_hash(object: &CanonicalJsonObject) -> Result<Base64<[u8; 32]>, Error> {
|
||||||
let json = canonical_json_with_fields_to_remove(object, CONTENT_HASH_FIELDS_TO_REMOVE)?;
|
let json = canonical_json_with_fields_to_remove(object, CONTENT_HASH_FIELDS_TO_REMOVE)?;
|
||||||
if json.len() > MAX_PDU_BYTES {
|
if json.len() > MAX_PDU_BYTES {
|
||||||
return Err(Error::PduSize);
|
return Err(Error::PduSize);
|
||||||
@ -355,12 +352,12 @@ pub fn content_hash(object: &CanonicalJsonObject) -> Result<String, Error> {
|
|||||||
|
|
||||||
let hash = Sha256::digest(json.as_bytes());
|
let hash = Sha256::digest(json.as_bytes());
|
||||||
|
|
||||||
Ok(encode_config(&hash, STANDARD_NO_PAD))
|
Ok(Base64::new(hash.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a *reference hash* for an event.
|
/// Creates a *reference hash* for an event.
|
||||||
///
|
///
|
||||||
/// Returns the hash as a Base64-encoded string, using the standard character set, without padding.
|
/// Returns the hash as a base64-encoded string, using the standard character set, without padding.
|
||||||
///
|
///
|
||||||
/// The reference hash of an event covers the essential fields of an event, including content
|
/// The reference hash of an event covers the essential fields of an event, including content
|
||||||
/// hashes. It is used to generate event identifiers and is described in the Matrix server-server
|
/// hashes. It is used to generate event identifiers and is described in the Matrix server-server
|
||||||
@ -507,7 +504,7 @@ where
|
|||||||
|
|
||||||
match hashes_value {
|
match hashes_value {
|
||||||
CanonicalJsonValue::Object(hashes) => {
|
CanonicalJsonValue::Object(hashes) => {
|
||||||
hashes.insert("sha256".into(), CanonicalJsonValue::String(hash))
|
hashes.insert("sha256".into(), CanonicalJsonValue::String(hash.encode()))
|
||||||
}
|
}
|
||||||
_ => return Err(JsonError::not_of_type("hashes", JsonType::Object)),
|
_ => return Err(JsonError::not_of_type("hashes", JsonType::Object)),
|
||||||
};
|
};
|
||||||
@ -546,10 +543,10 @@ where
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use std::collections::BTreeMap;
|
/// # use std::collections::BTreeMap;
|
||||||
/// # use ruma_identifiers::RoomVersionId;
|
/// # use ruma_identifiers::RoomVersionId;
|
||||||
/// # use ruma_signatures::verify_event;
|
/// # use ruma_serde::Base64;
|
||||||
/// # use ruma_signatures::Verified;
|
/// # use ruma_signatures::{verify_event, Verified};
|
||||||
/// #
|
/// #
|
||||||
/// const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
|
/// const PUBLIC_KEY: &[u8] = b"XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
|
||||||
///
|
///
|
||||||
/// // Deserialize an event from JSON.
|
/// // Deserialize an event from JSON.
|
||||||
/// let object = serde_json::from_str(
|
/// let object = serde_json::from_str(
|
||||||
@ -579,14 +576,14 @@ where
|
|||||||
///
|
///
|
||||||
/// // Create the `PublicKeyMap` that will inform `verify_json` which signatures to verify.
|
/// // Create the `PublicKeyMap` that will inform `verify_json` which signatures to verify.
|
||||||
/// let mut public_key_set = BTreeMap::new();
|
/// let mut public_key_set = BTreeMap::new();
|
||||||
/// public_key_set.insert("ed25519:1".into(), PUBLIC_KEY.to_owned());
|
/// public_key_set.insert("ed25519:1".into(), Base64::parse(PUBLIC_KEY.to_owned()).unwrap());
|
||||||
/// let mut public_key_map = BTreeMap::new();
|
/// let mut public_key_map = BTreeMap::new();
|
||||||
/// public_key_map.insert("domain".into(), public_key_set);
|
/// public_key_map.insert("domain".into(), public_key_set);
|
||||||
///
|
///
|
||||||
/// // Verify at least one signature for each entity in `public_key_map`.
|
/// // Verify at least one signature for each entity in `public_key_map`.
|
||||||
/// let verification_result = verify_event(&public_key_map, &object, &RoomVersionId::V6);
|
/// let verification_result = verify_event(&public_key_map, &object, &RoomVersionId::V6);
|
||||||
/// assert!(verification_result.is_ok());
|
/// assert!(verification_result.is_ok());
|
||||||
/// assert!(matches!(verification_result.unwrap(), Verified::All));
|
/// assert_eq!(verification_result.unwrap(), Verified::All);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn verify_event(
|
pub fn verify_event(
|
||||||
public_key_map: &PublicKeyMap,
|
public_key_map: &PublicKeyMap,
|
||||||
@ -659,34 +656,31 @@ pub fn verify_event(
|
|||||||
|
|
||||||
let public_key = signature_and_pubkey.public_key;
|
let public_key = signature_and_pubkey.public_key;
|
||||||
|
|
||||||
let verify = |config: Config| {
|
let signature =
|
||||||
let signature_bytes = decode_config(signature, config)
|
Base64::parse(signature).map_err(|e| ParseError::base64("signature", signature, e))?;
|
||||||
.map_err(|e| ParseError::base64("signature", signature, e))?;
|
|
||||||
|
|
||||||
let public_key_bytes = decode_config(&public_key, config)
|
verify_json_with(
|
||||||
.map_err(|e| ParseError::base64("public key", public_key, e))?;
|
&Ed25519Verifier,
|
||||||
|
public_key.as_bytes(),
|
||||||
verify_json_with(&Ed25519Verifier, &public_key_bytes, &signature_bytes, &canonical_json)
|
signature.as_bytes(),
|
||||||
};
|
&canonical_json,
|
||||||
|
)?;
|
||||||
#[cfg(feature = "compat")]
|
|
||||||
also_try_forgiving_base64(STANDARD_NO_PAD, verify)?;
|
|
||||||
#[cfg(not(feature = "compat"))]
|
|
||||||
verify(STANDARD_NO_PAD)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let calculated_hash = content_hash(object)?;
|
let calculated_hash = content_hash(object)?;
|
||||||
|
|
||||||
if *hash == calculated_hash {
|
if let Ok(hash) = Base64::parse(hash) {
|
||||||
Ok(Verified::All)
|
if hash.as_bytes() == calculated_hash.as_bytes() {
|
||||||
} else {
|
return Ok(Verified::All);
|
||||||
Ok(Verified::Signatures)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Verified::Signatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SignatureAndPubkey<'a> {
|
struct SignatureAndPubkey<'a> {
|
||||||
signature: &'a CanonicalJsonValue,
|
signature: &'a CanonicalJsonValue,
|
||||||
public_key: &'a String,
|
public_key: &'a Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal implementation detail of the canonical JSON algorithm.
|
/// Internal implementation detail of the canonical JSON algorithm.
|
||||||
@ -821,41 +815,6 @@ fn is_third_party_invite(object: &CanonicalJsonObject) -> Result<bool, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compat")]
|
|
||||||
// see https://github.com/ruma/ruma/issues/591
|
|
||||||
// synapse allows this, so we must allow it too.
|
|
||||||
// shouldn't lose data, but when it does, it'll make verification fail instead.
|
|
||||||
pub(crate) fn also_try_forgiving_base64<T, E>(
|
|
||||||
config: Config,
|
|
||||||
twice: impl Fn(Config) -> Result<T, E>,
|
|
||||||
) -> Result<T, E>
|
|
||||||
where
|
|
||||||
E: std::fmt::Display,
|
|
||||||
{
|
|
||||||
use tracing::{debug, warn};
|
|
||||||
|
|
||||||
let first_try = match twice(config) {
|
|
||||||
Ok(t) => return Ok(t),
|
|
||||||
Err(e) => e,
|
|
||||||
};
|
|
||||||
|
|
||||||
let adjusted = config.decode_allow_trailing_bits(true);
|
|
||||||
|
|
||||||
match twice(adjusted) {
|
|
||||||
Ok(t) => {
|
|
||||||
warn!(
|
|
||||||
"Usage of base64 config only worked after allowing trailing bits, first error: {}",
|
|
||||||
first_try
|
|
||||||
);
|
|
||||||
Ok(t)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
debug!("Second error when trying to allow trailing bits: {}", e);
|
|
||||||
Err(first_try)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{
|
use std::{
|
||||||
@ -863,9 +822,8 @@ mod tests {
|
|||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
};
|
};
|
||||||
|
|
||||||
use base64::{encode_config, STANDARD_NO_PAD};
|
|
||||||
use ruma_identifiers::{RoomVersionId, ServerSigningKeyId, SigningKeyAlgorithm};
|
use ruma_identifiers::{RoomVersionId, ServerSigningKeyId, SigningKeyAlgorithm};
|
||||||
use ruma_serde::CanonicalJsonValue;
|
use ruma_serde::{Base64, CanonicalJsonValue};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use super::canonical_json;
|
use super::canonical_json;
|
||||||
@ -941,20 +899,6 @@ mod tests {
|
|||||||
assert!(matches!(verification, Verified::Signatures));
|
assert!(matches!(verification, Verified::Signatures));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compat")]
|
|
||||||
#[test]
|
|
||||||
fn fallback_invalid_base64() {
|
|
||||||
use base64::{decode_config, Config};
|
|
||||||
|
|
||||||
const SLIGHTLY_MALFORMED_BASE64: &str = "3UmJnEIzUr2xWyaUnJg5fXwRybwG5FVC6GqMHverEUn0ztuIsvVxX89JXX2pvdTsOBbLQx+4TVL02l4Cp5wPCm";
|
|
||||||
|
|
||||||
let verify = |config: Config| decode_config(SLIGHTLY_MALFORMED_BASE64, config);
|
|
||||||
|
|
||||||
assert!(verify(STANDARD_NO_PAD).is_err());
|
|
||||||
|
|
||||||
assert!(super::also_try_forgiving_base64(STANDARD_NO_PAD, verify).is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verify_event_check_signatures_for_both_sender_and_event_id() {
|
fn verify_event_check_signatures_for_both_sender_and_event_id() {
|
||||||
let key_pair_sender = generate_key_pair();
|
let key_pair_sender = generate_key_pair();
|
||||||
@ -1062,8 +1006,7 @@ mod tests {
|
|||||||
let mut public_key_map = PublicKeyMap::new();
|
let mut public_key_map = PublicKeyMap::new();
|
||||||
let mut sender_key_map = PublicKeySet::new();
|
let mut sender_key_map = PublicKeySet::new();
|
||||||
let newly_generated_key_pair = generate_key_pair();
|
let newly_generated_key_pair = generate_key_pair();
|
||||||
let encoded_public_key =
|
let encoded_public_key = Base64::new(newly_generated_key_pair.public_key().to_owned());
|
||||||
encode_config(newly_generated_key_pair.public_key(), STANDARD_NO_PAD);
|
|
||||||
let version = ServerSigningKeyId::from_parts(
|
let version = ServerSigningKeyId::from_parts(
|
||||||
SigningKeyAlgorithm::Ed25519,
|
SigningKeyAlgorithm::Ed25519,
|
||||||
key_pair_sender.version().try_into().unwrap(),
|
key_pair_sender.version().try_into().unwrap(),
|
||||||
@ -1092,7 +1035,7 @@ mod tests {
|
|||||||
|
|
||||||
fn add_key_to_map(public_key_map: &mut PublicKeyMap, name: &str, pair: &Ed25519KeyPair) {
|
fn add_key_to_map(public_key_map: &mut PublicKeyMap, name: &str, pair: &Ed25519KeyPair) {
|
||||||
let mut sender_key_map = PublicKeySet::new();
|
let mut sender_key_map = PublicKeySet::new();
|
||||||
let encoded_public_key = encode_config(pair.public_key(), STANDARD_NO_PAD);
|
let encoded_public_key = Base64::new(pair.public_key().to_owned());
|
||||||
let version = ServerSigningKeyId::from_parts(
|
let version = ServerSigningKeyId::from_parts(
|
||||||
SigningKeyAlgorithm::Ed25519,
|
SigningKeyAlgorithm::Ed25519,
|
||||||
pair.version().try_into().unwrap(),
|
pair.version().try_into().unwrap(),
|
||||||
|
@ -11,6 +11,7 @@ use pkcs8::{
|
|||||||
der::{Decodable, Encodable},
|
der::{Decodable, Encodable},
|
||||||
AlgorithmIdentifier, ObjectIdentifier, PrivateKeyInfo,
|
AlgorithmIdentifier, ObjectIdentifier, PrivateKeyInfo,
|
||||||
};
|
};
|
||||||
|
use ruma_serde::Base64;
|
||||||
|
|
||||||
use crate::{signatures::Signature, Algorithm, Error, ParseError};
|
use crate::{signatures::Signature, Algorithm, Error, ParseError};
|
||||||
|
|
||||||
@ -184,8 +185,8 @@ pub type PublicKeyMap = BTreeMap<String, PublicKeySet>;
|
|||||||
|
|
||||||
/// A set of public keys for a single homeserver.
|
/// A set of public keys for a single homeserver.
|
||||||
///
|
///
|
||||||
/// This is represented as a map from key ID to Base64-encoded signature.
|
/// This is represented as a map from key ID to base64-encoded signature.
|
||||||
pub type PublicKeySet = BTreeMap<String, String>;
|
pub type PublicKeySet = BTreeMap<String, Base64>;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! are also required to contain hashes of their content, which are similarly stored within the
|
//! are also required to contain hashes of their content, which are similarly stored within the
|
||||||
//! hashed JSON object under a `hashes` key.
|
//! hashed JSON object under a `hashes` key.
|
||||||
//!
|
//!
|
||||||
//! In JSON representations, both signatures and hashes appear as Base64-encoded strings, using the
|
//! In JSON representations, both signatures and hashes appear as base64-encoded strings, using the
|
||||||
//! standard character set, without padding.
|
//! standard character set, without padding.
|
||||||
//!
|
//!
|
||||||
//! # Signing and hashing
|
//! # Signing and hashing
|
||||||
@ -104,9 +104,10 @@ fn split_id(id: &str) -> Result<(Algorithm, String), SplitError> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use base64::{decode_config, encode_config, STANDARD_NO_PAD};
|
use base64::{decode_config, STANDARD_NO_PAD};
|
||||||
use pkcs8::{der::Decodable, PrivateKeyInfo};
|
use pkcs8::{der::Decodable, PrivateKeyInfo};
|
||||||
use ruma_identifiers::RoomVersionId;
|
use ruma_identifiers::RoomVersionId;
|
||||||
|
use ruma_serde::Base64;
|
||||||
use serde_json::{from_str as from_json_str, to_string as to_json_string};
|
use serde_json::{from_str as from_json_str, to_string as to_json_string};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -119,13 +120,13 @@ mod tests {
|
|||||||
";
|
";
|
||||||
|
|
||||||
/// Convenience method for getting the public key as a string
|
/// Convenience method for getting the public key as a string
|
||||||
fn public_key_string() -> String {
|
fn public_key_string() -> Base64 {
|
||||||
encode_config(
|
Base64::new(
|
||||||
&PrivateKeyInfo::from_der(&decode_config(PKCS8, STANDARD_NO_PAD).unwrap())
|
PrivateKeyInfo::from_der(&decode_config(PKCS8, STANDARD_NO_PAD).unwrap())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.public_key
|
.public_key
|
||||||
.unwrap(),
|
.unwrap()
|
||||||
STANDARD_NO_PAD,
|
.to_owned(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ impl Signature {
|
|||||||
self.signature.as_slice()
|
self.signature.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Base64 encoding of the signature.
|
/// A base64 encoding of the signature.
|
||||||
///
|
///
|
||||||
/// Uses the standard character set with no padding.
|
/// Uses the standard character set with no padding.
|
||||||
pub fn base64(&self) -> String {
|
pub fn base64(&self) -> String {
|
||||||
|
@ -12,7 +12,7 @@ use ruma_events::{
|
|||||||
EventType,
|
EventType,
|
||||||
};
|
};
|
||||||
use ruma_identifiers::{RoomVersionId, UserId};
|
use ruma_identifiers::{RoomVersionId, UserId};
|
||||||
use ruma_serde::Raw;
|
use ruma_serde::{Base64, Raw};
|
||||||
use serde::{de::IgnoredAny, Deserialize};
|
use serde::{de::IgnoredAny, Deserialize};
|
||||||
use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};
|
use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
@ -925,15 +925,21 @@ fn verify_third_party_invite(
|
|||||||
Err(_) => return false,
|
Err(_) => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let decoded_invite_token = match Base64::parse(&tp_id.signed.token) {
|
||||||
|
Ok(tok) => tok,
|
||||||
|
// FIXME: Log a warning?
|
||||||
|
Err(_) => return false,
|
||||||
|
};
|
||||||
|
|
||||||
// A list of public keys in the public_keys field
|
// A list of public keys in the public_keys field
|
||||||
for key in tpid_ev.public_keys.unwrap_or_default() {
|
for key in tpid_ev.public_keys.unwrap_or_default() {
|
||||||
if key.public_key == tp_id.signed.token {
|
if key.public_key == decoded_invite_token {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A single public key in the public_key field
|
// A single public key in the public_key field
|
||||||
tpid_ev.public_key == tp_id.signed.token
|
tpid_ev.public_key == decoded_invite_token
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user