mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-27 16:51:34 +00:00
protocols/rendezvous: Implement protocol (#2107)
Implement the libp2p rendezvous protocol. > A lightweight mechanism for generalized peer discovery. It can be used for bootstrap purposes, real time peer discovery, application specific routing, and so on. Co-authored-by: rishflab <rishflab@hotmail.com> Co-authored-by: Daniel Karzel <daniel@comit.network>
This commit is contained in:
30
core/src/envelope.proto
Normal file
30
core/src/envelope.proto
Normal file
@ -0,0 +1,30 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package envelope_proto;
|
||||
|
||||
import "keys.proto";
|
||||
|
||||
// Envelope encloses a signed payload produced by a peer, along with the public
|
||||
// key of the keypair it was signed with so that it can be statelessly validated
|
||||
// by the receiver.
|
||||
//
|
||||
// The payload is prefixed with a byte string that determines the type, so it
|
||||
// can be deserialized deterministically. Often, this byte string is a
|
||||
// multicodec.
|
||||
message Envelope {
|
||||
// public_key is the public key of the keypair the enclosed payload was
|
||||
// signed with.
|
||||
keys_proto.PublicKey public_key = 1;
|
||||
|
||||
// payload_type encodes the type of payload, so that it can be deserialized
|
||||
// deterministically.
|
||||
bytes payload_type = 2;
|
||||
|
||||
// payload is the actual payload carried inside this envelope.
|
||||
bytes payload = 3;
|
||||
|
||||
// signature is the signature produced by the private key corresponding to
|
||||
// the enclosed public key, over the payload, prefixing a domain string for
|
||||
// additional security.
|
||||
bytes signature = 5;
|
||||
}
|
@ -42,6 +42,7 @@ pub mod error;
|
||||
|
||||
use self::error::*;
|
||||
use crate::{keys_proto, PeerId};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
/// Identity keypair of a node.
|
||||
///
|
||||
@ -205,6 +206,7 @@ impl PublicKey {
|
||||
/// that the signature has been produced by the corresponding
|
||||
/// private key (authenticity), and that the message has not been
|
||||
/// tampered with (integrity).
|
||||
#[must_use]
|
||||
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
|
||||
use PublicKey::*;
|
||||
match self {
|
||||
@ -221,7 +223,35 @@ impl PublicKey {
|
||||
pub fn to_protobuf_encoding(&self) -> Vec<u8> {
|
||||
use prost::Message;
|
||||
|
||||
let public_key = match self {
|
||||
let public_key = keys_proto::PublicKey::from(self);
|
||||
|
||||
let mut buf = Vec::with_capacity(public_key.encoded_len());
|
||||
public_key
|
||||
.encode(&mut buf)
|
||||
.expect("Vec<u8> provides capacity as needed");
|
||||
buf
|
||||
}
|
||||
|
||||
/// Decode a public key from a protobuf structure, e.g. read from storage
|
||||
/// or received from another node.
|
||||
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
|
||||
use prost::Message;
|
||||
|
||||
let pubkey = keys_proto::PublicKey::decode(bytes)
|
||||
.map_err(|e| DecodingError::new("Protobuf").source(e))?;
|
||||
|
||||
pubkey.try_into()
|
||||
}
|
||||
|
||||
/// Convert the `PublicKey` into the corresponding `PeerId`.
|
||||
pub fn to_peer_id(&self) -> PeerId {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PublicKey> for keys_proto::PublicKey {
|
||||
fn from(key: &PublicKey) -> Self {
|
||||
match key {
|
||||
PublicKey::Ed25519(key) => keys_proto::PublicKey {
|
||||
r#type: keys_proto::KeyType::Ed25519 as i32,
|
||||
data: key.encode().to_vec(),
|
||||
@ -236,24 +266,14 @@ impl PublicKey {
|
||||
r#type: keys_proto::KeyType::Secp256k1 as i32,
|
||||
data: key.encode().to_vec(),
|
||||
},
|
||||
};
|
||||
|
||||
let mut buf = Vec::with_capacity(public_key.encoded_len());
|
||||
public_key
|
||||
.encode(&mut buf)
|
||||
.expect("Vec<u8> provides capacity as needed");
|
||||
buf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode a public key from a protobuf structure, e.g. read from storage
|
||||
/// or received from another node.
|
||||
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
|
||||
use prost::Message;
|
||||
|
||||
#[allow(unused_mut)] // Due to conditional compilation.
|
||||
let mut pubkey = keys_proto::PublicKey::decode(bytes)
|
||||
.map_err(|e| DecodingError::new("Protobuf").source(e))?;
|
||||
impl TryFrom<keys_proto::PublicKey> for PublicKey {
|
||||
type Error = DecodingError;
|
||||
|
||||
fn try_from(pubkey: keys_proto::PublicKey) -> Result<Self, Self::Error> {
|
||||
let key_type = keys_proto::KeyType::from_i32(pubkey.r#type)
|
||||
.ok_or_else(|| DecodingError::new(format!("unknown key type: {}", pubkey.r#type)))?;
|
||||
|
||||
@ -281,11 +301,6 @@ impl PublicKey {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the `PublicKey` into the corresponding `PeerId`.
|
||||
pub fn to_peer_id(&self) -> PeerId {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -39,6 +39,14 @@ mod keys_proto {
|
||||
include!(concat!(env!("OUT_DIR"), "/keys_proto.rs"));
|
||||
}
|
||||
|
||||
mod envelope_proto {
|
||||
include!(concat!(env!("OUT_DIR"), "/envelope_proto.rs"));
|
||||
}
|
||||
|
||||
mod peer_record_proto {
|
||||
include!(concat!(env!("OUT_DIR"), "/peer_record_proto.rs"));
|
||||
}
|
||||
|
||||
/// Multi-address re-export.
|
||||
pub use multiaddr;
|
||||
pub type Negotiated<T> = multistream_select::Negotiated<T>;
|
||||
@ -51,6 +59,8 @@ pub mod either;
|
||||
pub mod identity;
|
||||
pub mod muxing;
|
||||
pub mod network;
|
||||
pub mod peer_record;
|
||||
pub mod signed_envelope;
|
||||
pub mod transport;
|
||||
pub mod upgrade;
|
||||
|
||||
@ -61,6 +71,8 @@ pub use multihash;
|
||||
pub use muxing::StreamMuxer;
|
||||
pub use network::Network;
|
||||
pub use peer_id::PeerId;
|
||||
pub use peer_record::PeerRecord;
|
||||
pub use signed_envelope::SignedEnvelope;
|
||||
pub use translation::address_translation;
|
||||
pub use transport::Transport;
|
||||
pub use upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeError, UpgradeInfo};
|
||||
|
@ -109,7 +109,7 @@ where
|
||||
/// A connection may close if
|
||||
///
|
||||
/// * it encounters an error, which includes the connection being
|
||||
/// closed by the remote. In this case `error` is `Some`.
|
||||
/// closed by the remote. In this case `error` is `ome`.
|
||||
/// * it was actively closed by [`EstablishedConnection::start_close`],
|
||||
/// i.e. a successful, orderly close. In this case `error` is `None`.
|
||||
/// * it was actively closed by [`super::peer::ConnectedPeer::disconnect`] or
|
||||
|
27
core/src/peer_record.proto
Normal file
27
core/src/peer_record.proto
Normal file
@ -0,0 +1,27 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package peer_record_proto;
|
||||
|
||||
// PeerRecord messages contain information that is useful to share with other peers.
|
||||
// Currently, a PeerRecord contains the public listen addresses for a peer, but this
|
||||
// is expected to expand to include other information in the future.
|
||||
//
|
||||
// PeerRecords are designed to be serialized to bytes and placed inside of
|
||||
// SignedEnvelopes before sharing with other peers.
|
||||
message PeerRecord {
|
||||
|
||||
// AddressInfo is a wrapper around a binary multiaddr. It is defined as a
|
||||
// separate message to allow us to add per-address metadata in the future.
|
||||
message AddressInfo {
|
||||
bytes multiaddr = 1;
|
||||
}
|
||||
|
||||
// peer_id contains a libp2p peer id in its binary representation.
|
||||
bytes peer_id = 1;
|
||||
|
||||
// seq contains a monotonically-increasing sequence counter to order PeerRecords in time.
|
||||
uint64 seq = 2;
|
||||
|
||||
// addresses is a list of public listen addresses for the peer.
|
||||
repeated AddressInfo addresses = 3;
|
||||
}
|
199
core/src/peer_record.rs
Normal file
199
core/src/peer_record.rs
Normal file
@ -0,0 +1,199 @@
|
||||
use crate::identity::error::SigningError;
|
||||
use crate::identity::Keypair;
|
||||
use crate::signed_envelope::SignedEnvelope;
|
||||
use crate::{peer_record_proto, signed_envelope, Multiaddr, PeerId};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use std::time::SystemTime;
|
||||
|
||||
const PAYLOAD_TYPE: &str = "/libp2p/routing-state-record";
|
||||
const DOMAIN_SEP: &str = "libp2p-routing-state";
|
||||
|
||||
/// Represents a peer routing record.
|
||||
///
|
||||
/// Peer records are designed to be distributable and carry a signature by being wrapped in a signed envelope.
|
||||
/// For more information see RFC0003 of the libp2p specifications: <https://github.com/libp2p/specs/blob/master/RFC/0003-routing-records.md>
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct PeerRecord {
|
||||
peer_id: PeerId,
|
||||
seq: u64,
|
||||
addresses: Vec<Multiaddr>,
|
||||
|
||||
/// A signed envelope representing this [`PeerRecord`].
|
||||
///
|
||||
/// If this [`PeerRecord`] was constructed from a [`SignedEnvelope`], this is the original instance.
|
||||
envelope: SignedEnvelope,
|
||||
}
|
||||
|
||||
impl PeerRecord {
|
||||
/// Attempt to re-construct a [`PeerRecord`] from a [`SignedEnvelope`].
|
||||
///
|
||||
/// If this function succeeds, the [`SignedEnvelope`] contained a peer record with a valid signature and can hence be considered authenticated.
|
||||
pub fn from_signed_envelope(envelope: SignedEnvelope) -> Result<Self, FromEnvelopeError> {
|
||||
use prost::Message;
|
||||
|
||||
let payload = envelope.payload(String::from(DOMAIN_SEP), PAYLOAD_TYPE.as_bytes())?;
|
||||
let record = peer_record_proto::PeerRecord::decode(payload)?;
|
||||
|
||||
let peer_id = PeerId::from_bytes(&record.peer_id)?;
|
||||
let seq = record.seq;
|
||||
let addresses = record
|
||||
.addresses
|
||||
.into_iter()
|
||||
.map(|a| a.multiaddr.try_into())
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(Self {
|
||||
peer_id,
|
||||
seq,
|
||||
addresses,
|
||||
envelope,
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a new [`PeerRecord`] by authenticating the provided addresses with the given key.
|
||||
///
|
||||
/// This is the same key that is used for authenticating every libp2p connection of your application, i.e. what you use when setting up your [`crate::transport::Transport`].
|
||||
pub fn new(key: Keypair, addresses: Vec<Multiaddr>) -> Result<Self, SigningError> {
|
||||
use prost::Message;
|
||||
|
||||
let seq = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("now() is never before UNIX_EPOCH")
|
||||
.as_secs();
|
||||
let peer_id = key.public().to_peer_id();
|
||||
|
||||
let payload = {
|
||||
let record = peer_record_proto::PeerRecord {
|
||||
peer_id: peer_id.to_bytes(),
|
||||
seq,
|
||||
addresses: addresses
|
||||
.iter()
|
||||
.map(|m| peer_record_proto::peer_record::AddressInfo {
|
||||
multiaddr: m.to_vec(),
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let mut buf = Vec::with_capacity(record.encoded_len());
|
||||
record
|
||||
.encode(&mut buf)
|
||||
.expect("Vec<u8> provides capacity as needed");
|
||||
buf
|
||||
};
|
||||
|
||||
let envelope = SignedEnvelope::new(
|
||||
key,
|
||||
String::from(DOMAIN_SEP),
|
||||
PAYLOAD_TYPE.as_bytes().to_vec(),
|
||||
payload,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
peer_id,
|
||||
seq,
|
||||
addresses,
|
||||
envelope,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_signed_envelope(&self) -> SignedEnvelope {
|
||||
self.envelope.clone()
|
||||
}
|
||||
|
||||
pub fn into_signed_envelope(self) -> SignedEnvelope {
|
||||
self.envelope
|
||||
}
|
||||
|
||||
pub fn peer_id(&self) -> PeerId {
|
||||
self.peer_id
|
||||
}
|
||||
|
||||
pub fn seq(&self) -> u64 {
|
||||
self.seq
|
||||
}
|
||||
|
||||
pub fn addresses(&self) -> &[Multiaddr] {
|
||||
self.addresses.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FromEnvelopeError {
|
||||
/// Failed to extract the payload from the envelope.
|
||||
BadPayload(signed_envelope::ReadPayloadError),
|
||||
/// Failed to decode the provided bytes as a [`PeerRecord`].
|
||||
InvalidPeerRecord(prost::DecodeError),
|
||||
/// Failed to decode the peer ID.
|
||||
InvalidPeerId(multihash::Error),
|
||||
/// Failed to decode a multi-address.
|
||||
InvalidMultiaddr(multiaddr::Error),
|
||||
}
|
||||
|
||||
impl From<signed_envelope::ReadPayloadError> for FromEnvelopeError {
|
||||
fn from(e: signed_envelope::ReadPayloadError) -> Self {
|
||||
Self::BadPayload(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<prost::DecodeError> for FromEnvelopeError {
|
||||
fn from(e: prost::DecodeError) -> Self {
|
||||
Self::InvalidPeerRecord(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<multihash::Error> for FromEnvelopeError {
|
||||
fn from(e: multihash::Error) -> Self {
|
||||
Self::InvalidPeerId(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<multiaddr::Error> for FromEnvelopeError {
|
||||
fn from(e: multiaddr::Error) -> Self {
|
||||
Self::InvalidMultiaddr(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FromEnvelopeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::BadPayload(_) => write!(f, "Failed to extract payload from envelope"),
|
||||
Self::InvalidPeerRecord(_) => {
|
||||
write!(f, "Failed to decode bytes as PeerRecord")
|
||||
}
|
||||
Self::InvalidPeerId(_) => write!(f, "Failed to decode bytes as PeerId"),
|
||||
Self::InvalidMultiaddr(_) => {
|
||||
write!(f, "Failed to decode bytes as MultiAddress")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for FromEnvelopeError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::InvalidPeerRecord(inner) => Some(inner),
|
||||
Self::InvalidPeerId(inner) => Some(inner),
|
||||
Self::InvalidMultiaddr(inner) => Some(inner),
|
||||
Self::BadPayload(inner) => Some(inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const HOME: &str = "/ip4/127.0.0.1/tcp/1337";
|
||||
|
||||
#[test]
|
||||
fn roundtrip_envelope() {
|
||||
let record =
|
||||
PeerRecord::new(Keypair::generate_ed25519(), vec![HOME.parse().unwrap()]).unwrap();
|
||||
|
||||
let envelope = record.to_signed_envelope();
|
||||
let reconstructed = PeerRecord::from_signed_envelope(envelope).unwrap();
|
||||
|
||||
assert_eq!(reconstructed, record)
|
||||
}
|
||||
}
|
203
core/src/signed_envelope.rs
Normal file
203
core/src/signed_envelope.rs
Normal file
@ -0,0 +1,203 @@
|
||||
use crate::identity::error::SigningError;
|
||||
use crate::identity::Keypair;
|
||||
use crate::{identity, PublicKey};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use unsigned_varint::encode::usize_buffer;
|
||||
|
||||
/// A signed envelope contains an arbitrary byte string payload, a signature of the payload, and the public key that can be used to verify the signature.
|
||||
///
|
||||
/// For more details see libp2p RFC0002: <https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md>
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct SignedEnvelope {
|
||||
key: PublicKey,
|
||||
payload_type: Vec<u8>,
|
||||
payload: Vec<u8>,
|
||||
signature: Vec<u8>,
|
||||
}
|
||||
|
||||
impl SignedEnvelope {
|
||||
/// Constructs a new [`SignedEnvelope`].
|
||||
pub fn new(
|
||||
key: Keypair,
|
||||
domain_separation: String,
|
||||
payload_type: Vec<u8>,
|
||||
payload: Vec<u8>,
|
||||
) -> Result<Self, SigningError> {
|
||||
let buffer = signature_payload(domain_separation, &payload_type, &payload);
|
||||
|
||||
let signature = key.sign(&buffer)?;
|
||||
|
||||
Ok(Self {
|
||||
key: key.public(),
|
||||
payload_type,
|
||||
payload,
|
||||
signature,
|
||||
})
|
||||
}
|
||||
|
||||
/// Verify this [`SignedEnvelope`] against the provided domain-separation string.
|
||||
#[must_use]
|
||||
pub fn verify(&self, domain_separation: String) -> bool {
|
||||
let buffer = signature_payload(domain_separation, &self.payload_type, &self.payload);
|
||||
|
||||
self.key.verify(&buffer, &self.signature)
|
||||
}
|
||||
|
||||
/// Extract the payload of this [`SignedEnvelope`].
|
||||
///
|
||||
/// You must provide the correct domain-separation string and expected payload type in order to get the payload.
|
||||
/// This guards against accidental mis-use of the payload where the signature was created for a different purpose or payload type.
|
||||
pub fn payload(
|
||||
&self,
|
||||
domain_separation: String,
|
||||
expected_payload_type: &[u8],
|
||||
) -> Result<&[u8], ReadPayloadError> {
|
||||
if &self.payload_type != expected_payload_type {
|
||||
return Err(ReadPayloadError::UnexpectedPayloadType {
|
||||
expected: expected_payload_type.to_vec(),
|
||||
got: self.payload_type.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
if !self.verify(domain_separation) {
|
||||
return Err(ReadPayloadError::InvalidSignature);
|
||||
}
|
||||
|
||||
Ok(&self.payload)
|
||||
}
|
||||
|
||||
/// Encode this [`SignedEnvelope`] using the protobuf encoding specified in the RFC.
|
||||
pub fn into_protobuf_encoding(self) -> Vec<u8> {
|
||||
use prost::Message;
|
||||
|
||||
let envelope = crate::envelope_proto::Envelope {
|
||||
public_key: Some((&self.key).into()),
|
||||
payload_type: self.payload_type,
|
||||
payload: self.payload,
|
||||
signature: self.signature,
|
||||
};
|
||||
|
||||
let mut buf = Vec::with_capacity(envelope.encoded_len());
|
||||
envelope
|
||||
.encode(&mut buf)
|
||||
.expect("Vec<u8> provides capacity as needed");
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
/// Decode a [`SignedEnvelope`] using the protobuf encoding specified in the RFC.
|
||||
pub fn from_protobuf_encoding(bytes: &[u8]) -> Result<Self, DecodingError> {
|
||||
use prost::Message;
|
||||
|
||||
let envelope = crate::envelope_proto::Envelope::decode(bytes)?;
|
||||
|
||||
Ok(Self {
|
||||
key: envelope
|
||||
.public_key
|
||||
.ok_or(DecodingError::MissingPublicKey)?
|
||||
.try_into()?,
|
||||
payload_type: envelope.payload_type,
|
||||
payload: envelope.payload,
|
||||
signature: envelope.signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn signature_payload(domain_separation: String, payload_type: &[u8], payload: &[u8]) -> Vec<u8> {
|
||||
let mut domain_sep_length_buffer = usize_buffer();
|
||||
let domain_sep_length =
|
||||
unsigned_varint::encode::usize(domain_separation.len(), &mut domain_sep_length_buffer);
|
||||
|
||||
let mut payload_type_length_buffer = usize_buffer();
|
||||
let payload_type_length =
|
||||
unsigned_varint::encode::usize(payload_type.len(), &mut payload_type_length_buffer);
|
||||
|
||||
let mut payload_length_buffer = usize_buffer();
|
||||
let payload_length = unsigned_varint::encode::usize(payload.len(), &mut payload_length_buffer);
|
||||
|
||||
let mut buffer = Vec::with_capacity(
|
||||
domain_sep_length.len()
|
||||
+ domain_separation.len()
|
||||
+ payload_type_length.len()
|
||||
+ payload_type.len()
|
||||
+ payload_length.len()
|
||||
+ payload.len(),
|
||||
);
|
||||
|
||||
buffer.extend_from_slice(domain_sep_length);
|
||||
buffer.extend_from_slice(domain_separation.as_bytes());
|
||||
buffer.extend_from_slice(payload_type_length);
|
||||
buffer.extend_from_slice(payload_type);
|
||||
buffer.extend_from_slice(payload_length);
|
||||
buffer.extend_from_slice(payload);
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
/// Errors that occur whilst decoding a [`SignedEnvelope`] from its byte representation.
|
||||
#[derive(Debug)]
|
||||
pub enum DecodingError {
|
||||
/// Decoding the provided bytes as a signed envelope failed.
|
||||
InvalidEnvelope(prost::DecodeError),
|
||||
/// The public key in the envelope could not be converted to our internal public key type.
|
||||
InvalidPublicKey(identity::error::DecodingError),
|
||||
/// The public key in the envelope could not be converted to our internal public key type.
|
||||
MissingPublicKey,
|
||||
}
|
||||
|
||||
impl From<prost::DecodeError> for DecodingError {
|
||||
fn from(e: prost::DecodeError) -> Self {
|
||||
Self::InvalidEnvelope(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<identity::error::DecodingError> for DecodingError {
|
||||
fn from(e: identity::error::DecodingError) -> Self {
|
||||
Self::InvalidPublicKey(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DecodingError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvalidEnvelope(_) => write!(f, "Failed to decode envelope"),
|
||||
Self::InvalidPublicKey(_) => write!(f, "Failed to convert public key"),
|
||||
Self::MissingPublicKey => write!(f, "Public key is missing from protobuf struct"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for DecodingError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::InvalidEnvelope(inner) => Some(inner),
|
||||
Self::InvalidPublicKey(inner) => Some(inner),
|
||||
Self::MissingPublicKey => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors that occur whilst extracting the payload of a [`SignedEnvelope`].
|
||||
#[derive(Debug)]
|
||||
pub enum ReadPayloadError {
|
||||
/// The signature on the signed envelope does not verify with the provided domain separation string.
|
||||
InvalidSignature,
|
||||
/// The payload contained in the envelope is not of the expected type.
|
||||
UnexpectedPayloadType { expected: Vec<u8>, got: Vec<u8> },
|
||||
}
|
||||
|
||||
impl fmt::Display for ReadPayloadError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvalidSignature => write!(f, "Invalid signature"),
|
||||
Self::UnexpectedPayloadType { expected, got } => write!(
|
||||
f,
|
||||
"Unexpected payload type, expected {:?} but got {:?}",
|
||||
expected, got
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ReadPayloadError {}
|
Reference in New Issue
Block a user