serde: Fix lots of issues from previous commit
This commit is contained in:
parent
0dbeac8505
commit
b7bcecbb77
@ -1,4 +1,6 @@
|
||||
use std::fmt;
|
||||
//!Transparent base64 encoding / decoding as part of (de)serialization.
|
||||
|
||||
use std::{fmt, marker::PhantomData};
|
||||
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
@ -9,37 +11,50 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Base64<C = Standard, B = Vec<u8>> {
|
||||
bytes: B,
|
||||
_phantom_conf: PhantomData<*mut C>,
|
||||
}
|
||||
|
||||
/// Config used for the [`Base64`] type.
|
||||
pub trait Base64Config {
|
||||
const CONF: base64::Config;
|
||||
/// The config as a constant.
|
||||
///
|
||||
/// Opaque so our interface is not tied to the base64 crate version.
|
||||
#[doc(hidden)]
|
||||
const CONF: Conf;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct Conf(base64::Config);
|
||||
|
||||
/// Standard base64 character set without padding.
|
||||
///
|
||||
/// Allows trailing bits in decoding for maximum compatibility.
|
||||
#[non_exhaustive]
|
||||
// Easier than implementing these all for Base64 manually to avoid the `C: Trait` bounds.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Standard;
|
||||
|
||||
impl Base64Config for Standard {
|
||||
// See https://github.com/matrix-org/matrix-doc/issues/3211
|
||||
const CONF: base64::Config = base64::STANDARD_NO_PAD.decode_allow_trailing_bits(true);
|
||||
const CONF: Conf = Conf(base64::STANDARD_NO_PAD.decode_allow_trailing_bits(true));
|
||||
}
|
||||
|
||||
/// Url-safe base64 character set without padding.
|
||||
///
|
||||
/// Allows trailing bits in decoding for maximum compatibility.
|
||||
#[non_exhaustive]
|
||||
// Easier than implementing these all for Base64 manually to avoid the `C: Trait` bounds.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct UrlSafe;
|
||||
|
||||
impl Base64Config for UrlSafe {
|
||||
const CONF: base64::Config = base64::URL_SAFE_NO_PAD.decode_allow_trailing_bits(true);
|
||||
const CONF: Conf = Conf(base64::URL_SAFE_NO_PAD.decode_allow_trailing_bits(true));
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> Base64<B> {
|
||||
impl<C: Base64Config, B: AsRef<[u8]>> Base64<C, B> {
|
||||
/// Create a `Base64` instance from raw bytes, to be base64-encoded in serialialization.
|
||||
pub fn new(bytes: B) -> Self {
|
||||
Self { bytes }
|
||||
Self { bytes, _phantom_conf: PhantomData }
|
||||
}
|
||||
|
||||
/// Get a reference to the raw bytes held by this `Base64` instance.
|
||||
@ -49,42 +64,42 @@ impl<B: AsRef<[u8]>> Base64<B> {
|
||||
|
||||
/// Encode the bytes contained in this `Base64` instance to unpadded base64.
|
||||
pub fn encode(&self) -> String {
|
||||
base64::encode_config(&self.bytes, BASE64_CONFIG)
|
||||
base64::encode_config(&self.bytes, C::CONF.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Base64<B> {
|
||||
impl<C, B> Base64<C, B> {
|
||||
/// Get the raw bytes held by this `Base64` instance.
|
||||
pub fn into_inner(self) -> B {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl Base64 {
|
||||
impl<C: Base64Config> Base64<C> {
|
||||
/// Create a `Base64` instance containing an empty `Vec<u8>`.
|
||||
pub fn empty() -> Self {
|
||||
Self { bytes: Vec::new() }
|
||||
Self::new(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)
|
||||
base64::decode_config(encoded, C::CONF.0).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for Base64<B> {
|
||||
impl<C: Base64Config, B: AsRef<[u8]>> fmt::Debug for Base64<C, B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.encode().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Display for Base64<B> {
|
||||
impl<C: Base64Config, B: AsRef<[u8]>> fmt::Display for Base64<C, B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.encode().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Base64 {
|
||||
impl<'de, C: Base64Config> Deserialize<'de> for Base64<C> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
@ -94,7 +109,7 @@ impl<'de> Deserialize<'de> for Base64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> Serialize for Base64<B> {
|
||||
impl<C: Base64Config, B: AsRef<[u8]>> Serialize for Base64<C, B> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
|
@ -9,7 +9,7 @@ use std::{
|
||||
|
||||
use base64::{encode_config, STANDARD_NO_PAD, URL_SAFE_NO_PAD};
|
||||
use ruma_identifiers::{EventId, RoomVersionId, ServerName, UserId};
|
||||
use ruma_serde::{Base64, CanonicalJsonObject, CanonicalJsonValue};
|
||||
use ruma_serde::{base64::Standard, Base64, CanonicalJsonObject, CanonicalJsonValue};
|
||||
use serde_json::{from_str as from_json_str, to_string as to_json_string};
|
||||
use sha2::{digest::Digest, Sha256};
|
||||
|
||||
@ -291,7 +291,7 @@ pub fn verify_json(
|
||||
)
|
||||
})?;
|
||||
|
||||
let signature = Base64::parse(signature)
|
||||
let signature = Base64::<Standard>::parse(signature)
|
||||
.map_err(|e| ParseError::base64("signature", signature, e))?;
|
||||
|
||||
verify_json_with(
|
||||
@ -332,8 +332,6 @@ where
|
||||
|
||||
/// Creates a *content hash* for an event.
|
||||
///
|
||||
/// 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
|
||||
/// used during federation and is described in the Matrix server-server specification.
|
||||
///
|
||||
@ -344,7 +342,7 @@ where
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the event is too large.
|
||||
pub fn content_hash(object: &CanonicalJsonObject) -> Result<Base64<[u8; 32]>, Error> {
|
||||
pub fn content_hash(object: &CanonicalJsonObject) -> Result<Base64<Standard, [u8; 32]>, Error> {
|
||||
let json = canonical_json_with_fields_to_remove(object, CONTENT_HASH_FIELDS_TO_REMOVE)?;
|
||||
if json.len() > MAX_PDU_BYTES {
|
||||
return Err(Error::PduSize);
|
||||
@ -656,8 +654,8 @@ pub fn verify_event(
|
||||
|
||||
let public_key = signature_and_pubkey.public_key;
|
||||
|
||||
let signature =
|
||||
Base64::parse(signature).map_err(|e| ParseError::base64("signature", signature, e))?;
|
||||
let signature = Base64::<Standard>::parse(signature)
|
||||
.map_err(|e| ParseError::base64("signature", signature, e))?;
|
||||
|
||||
verify_json_with(
|
||||
&Ed25519Verifier,
|
||||
@ -669,7 +667,7 @@ pub fn verify_event(
|
||||
|
||||
let calculated_hash = content_hash(object)?;
|
||||
|
||||
if let Ok(hash) = Base64::parse(hash) {
|
||||
if let Ok(hash) = Base64::<Standard>::parse(hash) {
|
||||
if hash.as_bytes() == calculated_hash.as_bytes() {
|
||||
return Ok(Verified::All);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user