identifiers: Make DeviceKeyId a DST
This commit is contained in:
parent
206c25e7e7
commit
c73eb7dce3
@ -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>>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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>>;
|
||||
|
@ -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: {
|
||||
|
@ -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)]
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user