use ruma_common::{
canonical_json::{JsonType, RedactionError},
serde::Base64DecodeError,
EventId, OwnedEventId, OwnedServerName, RoomVersionId,
};
use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
#[allow(clippy::enum_variant_names)]
pub enum Error {
#[error("JSON error: {0}")]
Json(#[from] JsonError),
#[error("Verification error: {0}")]
Verification(#[from] VerificationError),
#[error("Parse error: {0}")]
Parse(#[from] ParseError),
#[error("DER Parse error: {0}")]
DerParse(pkcs8::Error),
#[error("malformed signature ID: expected exactly 2 segment separated by a colon, found {0}")]
InvalidLength(usize),
#[error("malformed signature ID: expected version to contain only characters in the character set `[a-zA-Z0-9_]`, found `{0}`")]
InvalidVersion(String),
#[error("signature uses an unsupported algorithm: {0}")]
UnsupportedAlgorithm(String),
#[error("PDU is larger than maximum of 65535 bytes")]
PduSize,
}
impl From<RedactionError> for Error {
fn from(err: RedactionError) -> Self {
match err {
RedactionError::NotOfType { field: target, of_type, .. } => {
JsonError::NotOfType { target, of_type }.into()
}
RedactionError::JsonFieldMissingFromObject(field) => {
JsonError::JsonFieldMissingFromObject(field).into()
}
#[allow(unreachable_patterns)]
_ => unreachable!(),
}
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum JsonError {
#[error("Value in {target:?} must be a JSON {of_type:?}")]
NotOfType {
target: String,
of_type: JsonType,
},
#[error("Values in {target:?} must be JSON {of_type:?}s")]
NotMultiplesOfType {
target: String,
of_type: JsonType,
},
#[error("JSON object must contain the field {0:?}")]
JsonFieldMissingFromObject(String),
#[error("JSON object {for_target:?} does not have {type_of} key {with_key:?}")]
JsonKeyMissing {
for_target: String,
type_of: String,
with_key: String,
},
#[error(transparent)]
Serde(#[from] serde_json::Error),
}
impl JsonError {
pub(crate) fn not_of_type<T: Into<String>>(target: T, of_type: JsonType) -> Error {
Self::NotOfType { target: target.into(), of_type }.into()
}
pub(crate) fn not_multiples_of_type<T: Into<String>>(target: T, of_type: JsonType) -> Error {
Self::NotMultiplesOfType { target: target.into(), of_type }.into()
}
pub(crate) fn field_missing_from_object<T: Into<String>>(target: T) -> Error {
Self::JsonFieldMissingFromObject(target.into()).into()
}
pub(crate) fn key_missing<T1: Into<String>, T2: Into<String>, T3: Into<String>>(
for_target: T1,
type_of: T2,
with_key: T3,
) -> Error {
Self::JsonKeyMissing {
for_target: for_target.into(),
type_of: type_of.into(),
with_key: with_key.into(),
}
.into()
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum VerificationError {
#[error("Could not find signatures for {0:?}")]
SignatureNotFound(OwnedServerName),
#[error("Could not find public key for {0:?}")]
PublicKeyNotFound(OwnedServerName),
#[error("Not signed with any of the given public keys")]
UnknownPublicKeysForSignature,
#[error("Could not verify signature: {0}")]
Signature(#[source] ed25519_dalek::SignatureError),
}
impl VerificationError {
pub(crate) fn signature_not_found(target: OwnedServerName) -> Error {
Self::SignatureNotFound(target).into()
}
pub(crate) fn public_key_not_found(target: OwnedServerName) -> Error {
Self::PublicKeyNotFound(target).into()
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum ParseError {
#[error("Could not parse User ID: {0}")]
UserId(#[source] ruma_common::IdParseError),
#[error("Could not parse Event ID: {0}")]
EventId(#[source] ruma_common::IdParseError),
#[error("Event Id {0:?} should have a server name for the given room version {1:?}")]
ServerNameFromEventIdByRoomVersion(OwnedEventId, RoomVersionId),
#[error("PKCS#8 Document public key does not match public key derived from private key; derived: {0:X?} (len {}), parsed: {1:X?} (len {})", .derived_key.len(), .parsed_key.len())]
DerivedPublicKeyDoesNotMatchParsedKey {
parsed_key: Vec<u8>,
derived_key: Vec<u8>,
},
#[error("Algorithm OID does not match ed25519, expected {expected}, found {found}")]
Oid {
expected: pkcs8::ObjectIdentifier,
found: pkcs8::ObjectIdentifier,
},
#[error("Could not parse secret key")]
SecretKey,
#[error("Could not parse public key: {0}")]
PublicKey(#[source] ed25519_dalek::SignatureError),
#[error("Could not parse signature: {0}")]
Signature(#[source] ed25519_dalek::SignatureError),
#[error("Could not parse {of_type} base64 string {string:?}: {source}")]
Base64 {
of_type: String,
string: String,
#[source]
source: Base64DecodeError,
},
}
impl ParseError {
pub(crate) fn from_event_id_by_room_version(
event_id: &EventId,
room_version: &RoomVersionId,
) -> Error {
Self::ServerNameFromEventIdByRoomVersion(event_id.to_owned(), room_version.clone()).into()
}
pub(crate) fn derived_vs_parsed_mismatch<P: Into<Vec<u8>>, D: Into<Vec<u8>>>(
parsed: P,
derived: D,
) -> Error {
Self::DerivedPublicKeyDoesNotMatchParsedKey {
parsed_key: parsed.into(),
derived_key: derived.into(),
}
.into()
}
pub(crate) fn base64<T1: Into<String>, T2: Into<String>>(
of_type: T1,
string: T2,
source: Base64DecodeError,
) -> Error {
Self::Base64 { of_type: of_type.into(), string: string.into(), source }.into()
}
}