identifiers: Make DeviceKeyId a DST

This commit is contained in:
Jonas Platte 2021-09-17 20:22:45 +02:00
parent 206c25e7e7
commit c73eb7dce3
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
8 changed files with 49 additions and 59 deletions

View File

@ -48,7 +48,7 @@ pub enum BackupAlgorithm {
public_key: String,
/// Signatures of the auth_data as Signed JSON.
signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
signatures: BTreeMap<UserId, BTreeMap<Box<DeviceKeyId>, String>>,
},
}

View File

@ -60,4 +60,4 @@ impl Response {
}
/// The one-time keys for a given device.
pub type OneTimeKeys = BTreeMap<Box<DeviceId>, BTreeMap<DeviceKeyId, OneTimeKey>>;
pub type OneTimeKeys = BTreeMap<Box<DeviceId>, BTreeMap<Box<DeviceKeyId>, OneTimeKey>>;

View File

@ -27,7 +27,7 @@ ruma_api! {
/// One-time public keys for "pre-key" messages.
#[serde(skip_serializing_if = "Option::is_none")]
pub one_time_keys: Option<BTreeMap<DeviceKeyId, OneTimeKey>>,
pub one_time_keys: Option<BTreeMap<Box<DeviceKeyId>, OneTimeKey>>,
}
response: {

View File

@ -25,10 +25,10 @@ pub struct DeviceKeys {
pub algorithms: Vec<EventEncryptionAlgorithm>,
/// Public identity keys.
pub keys: BTreeMap<DeviceKeyId, String>,
pub keys: BTreeMap<Box<DeviceKeyId>, String>,
/// Signatures for the device key object.
pub signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
pub signatures: BTreeMap<UserId, BTreeMap<Box<DeviceKeyId>, String>>,
/// Additional data added to the device key information by intermediate servers, and
/// not covered by the signatures.
@ -43,8 +43,8 @@ impl DeviceKeys {
user_id: UserId,
device_id: Box<DeviceId>,
algorithms: Vec<EventEncryptionAlgorithm>,
keys: BTreeMap<DeviceKeyId, String>,
signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
keys: BTreeMap<Box<DeviceKeyId>, String>,
signatures: BTreeMap<UserId, BTreeMap<Box<DeviceKeyId>, String>>,
) -> Self {
Self { user_id, device_id, algorithms, keys, signatures, unsigned: Default::default() }
}
@ -72,7 +72,7 @@ impl UnsignedDeviceInfo {
}
/// Signatures for a `SignedKey` object.
pub type SignedKeySignatures = BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>;
pub type SignedKeySignatures = BTreeMap<UserId, BTreeMap<Box<DeviceKeyId>, String>>;
/// A key for the SignedCurve25519 algorithm
#[derive(Debug, Clone, Serialize, Deserialize)]

View File

@ -47,7 +47,8 @@ impl Response {
pub type OneTimeKeyClaims = BTreeMap<UserId, BTreeMap<Box<DeviceId>, DeviceKeyAlgorithm>>;
/// One time keys for use in pre-key messages
pub type OneTimeKeys = BTreeMap<UserId, BTreeMap<Box<DeviceId>, BTreeMap<DeviceKeyId, OneTimeKey>>>;
pub type OneTimeKeys =
BTreeMap<UserId, BTreeMap<Box<DeviceId>, BTreeMap<Box<DeviceKeyId>, OneTimeKey>>>;
/// A key and its signature
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -57,12 +58,15 @@ pub struct KeyObject {
pub key: String,
/// Signature of the key object.
pub signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
pub signatures: BTreeMap<UserId, BTreeMap<Box<DeviceKeyId>, String>>,
}
impl KeyObject {
/// Creates a new `KeyObject` with the given key and signatures.
pub fn new(key: String, signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>) -> Self {
pub fn new(
key: String,
signatures: BTreeMap<UserId, BTreeMap<Box<DeviceKeyId>, String>>,
) -> Self {
Self { key, signatures }
}
}

View File

@ -31,7 +31,7 @@ pub fn device_key_id(input: TokenStream) -> TokenStream {
assert!(device_key_id::validate(&id.value()).is_ok(), "Invalid device key id");
let output = quote! {
<#dollar_crate::DeviceKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
<&#dollar_crate::DeviceKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()

View File

@ -1,10 +1,12 @@
use std::num::NonZeroU8;
use crate::Error;
pub fn validate(s: &str) -> Result<NonZeroU8, Error> {
let colon_idx = NonZeroU8::new(s.find(':').ok_or(Error::MissingDelimiter)? as u8)
.ok_or(Error::InvalidKeyAlgorithm)?;
pub fn validate(s: &str) -> Result<(), Error> {
let colon_idx = s.find(':').ok_or(Error::MissingDelimiter)?;
Ok(colon_idx)
if colon_idx == 0 {
Err(Error::InvalidKeyAlgorithm)
} else {
// Any non-empty string is accepted as a key algorithm for forwards compatibility
Ok(())
}
}

View File

@ -1,25 +1,17 @@
//! Identifiers for device keys for end-to-end encryption.
use std::{convert::TryInto, fmt, num::NonZeroU8};
use ruma_identifiers_validation::device_key_id::validate;
use crate::{crypto_algorithms::DeviceKeyAlgorithm, DeviceId};
/// A key algorithm and a device id, combined with a ':'.
#[derive(Clone)]
pub struct DeviceKeyId {
full_id: Box<str>,
colon_idx: NonZeroU8,
}
impl fmt::Debug for DeviceKeyId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.full_id.fmt(f)
}
opaque_identifier_validated! {
/// A key algorithm and a device id, combined with a ':'.
pub type DeviceKeyId [ validate ];
}
impl DeviceKeyId {
/// Create a `DeviceKeyId` from a `DeviceKeyAlgorithm` and a `DeviceId`.
pub fn from_parts(algorithm: DeviceKeyAlgorithm, device_id: &DeviceId) -> Self {
pub fn from_parts(algorithm: DeviceKeyAlgorithm, device_id: &DeviceId) -> Box<Self> {
let algorithm: &str = algorithm.as_ref();
let device_id: &str = device_id.as_ref();
@ -28,34 +20,24 @@ impl DeviceKeyId {
res.push(':');
res.push_str(device_id);
let colon_idx =
NonZeroU8::new(algorithm.len().try_into().expect("no algorithm name len > 255"))
.expect("no empty algorithm name");
DeviceKeyId { full_id: res.into(), colon_idx }
Self::from_owned(res.into())
}
/// Returns key algorithm of the device key ID.
pub fn algorithm(&self) -> DeviceKeyAlgorithm {
self.full_id[..self.colon_idx.get() as usize].into()
self.as_str()[..self.colon_idx()].into()
}
/// Returns device ID of the device key ID.
pub fn device_id(&self) -> &DeviceId {
(&self.full_id[self.colon_idx.get() as usize + 1..]).into()
self.as_str()[self.colon_idx() + 1..].into()
}
fn colon_idx(&self) -> usize {
self.as_str().find(':').unwrap()
}
}
fn try_from<S>(key_id: S) -> Result<DeviceKeyId, crate::Error>
where
S: AsRef<str> + Into<Box<str>>,
{
let colon_idx = ruma_identifiers_validation::device_key_id::validate(key_id.as_ref())?;
Ok(DeviceKeyId { full_id: key_id.into(), colon_idx })
}
common_impls!(DeviceKeyId, try_from, "Device key ID with algorithm and device ID");
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
@ -66,9 +48,8 @@ mod tests {
#[test]
fn convert_device_key_id() {
assert_eq!(
DeviceKeyId::try_from("ed25519:JLAFKJWSCS")
.expect("Failed to create device key ID.")
.as_ref(),
<&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS")
.expect("Failed to create device key ID."),
"ed25519:JLAFKJWSCS"
);
}
@ -76,7 +57,7 @@ mod tests {
#[cfg(feature = "serde")]
#[test]
fn serialize_device_key_id() {
let device_key_id = DeviceKeyId::try_from("ed25519:JLAFKJWSCS").unwrap();
let device_key_id = <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS").unwrap();
let serialized = serde_json::to_value(device_key_id).unwrap();
assert_eq!(serialized, serde_json::json!("ed25519:JLAFKJWSCS"));
@ -85,40 +66,43 @@ mod tests {
#[cfg(feature = "serde")]
#[test]
fn deserialize_device_key_id() {
let deserialized: DeviceKeyId =
let deserialized: Box<DeviceKeyId> =
serde_json::from_value(serde_json::json!("ed25519:JLAFKJWSCS")).unwrap();
let expected = DeviceKeyId::try_from("ed25519:JLAFKJWSCS").unwrap();
let expected = <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS").unwrap();
assert_eq!(deserialized, expected);
}
#[test]
fn missing_key_algorithm() {
assert_eq!(DeviceKeyId::try_from(":JLAFKJWSCS").unwrap_err(), Error::InvalidKeyAlgorithm);
assert_eq!(
<&DeviceKeyId>::try_from(":JLAFKJWSCS").unwrap_err(),
Error::InvalidKeyAlgorithm
);
}
#[test]
fn missing_delimiter() {
assert_eq!(
DeviceKeyId::try_from("ed25519|JLAFKJWSCS").unwrap_err(),
<&DeviceKeyId>::try_from("ed25519|JLAFKJWSCS").unwrap_err(),
Error::MissingDelimiter,
);
}
#[test]
fn empty_device_id_ok() {
assert!(DeviceKeyId::try_from("ed25519:").is_ok());
assert!(<&DeviceKeyId>::try_from("ed25519:").is_ok());
}
#[test]
fn valid_key_algorithm() {
let device_key_id = DeviceKeyId::try_from("ed25519:JLAFKJWSCS").unwrap();
let device_key_id = <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS").unwrap();
assert_eq!(device_key_id.algorithm(), DeviceKeyAlgorithm::Ed25519);
}
#[test]
fn valid_device_id() {
let device_key_id = DeviceKeyId::try_from("ed25519:JLAFKJWSCS").unwrap();
let device_key_id = <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS").unwrap();
assert_eq!(device_key_id.device_id(), "JLAFKJWSCS");
}
}