use std::net::SocketAddr;
use crate::base::Header;
use crate::options::{Options, OptionsError};
use crate::types::*;
use crate::wire::Container;
#[derive(Clone, Builder, Debug)]
pub struct Base {
pub(crate) id: Id,
pub(crate) header: Header,
#[builder(default = "Body::None")]
pub(crate) body: Body,
#[builder(default = "PrivateOptions::None")]
pub(crate) private_options: PrivateOptions,
#[builder(default = "vec![]")]
pub(crate) public_options: Vec<Options>,
#[builder(default = "None")]
pub(crate) parent: Option<Signature>,
#[builder(default = "None")]
pub(crate) public_key: Option<PublicKey>,
#[builder(default = "None")]
pub(crate) peer_id: Option<Id>,
#[builder(default = "None")]
pub(crate) signature: Option<Signature>,
#[builder(default = "false")]
pub(crate) verified: bool,
#[builder(default = "None")]
pub(crate) raw: Option<Vec<u8>>,
}
impl PartialEq for Base {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.header == other.header
&& self.body == other.body
&& self.private_options == other.private_options
&& self.public_options == other.public_options
&& self.parent == other.parent
&& self.public_key == other.public_key
&& self.peer_id == other.peer_id
&& self.signature == other.signature
}
}
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum NewBody<T: ImmutableData> {
Cleartext(T),
Encrypted(T),
None,
}
impl Body {
pub fn decrypt(&mut self, secret_key: Option<&SecretKey>) -> Result<(), Error> {
let body = match (&self, &secret_key) {
(NewBody::Cleartext(b), _) => b.to_vec(),
(NewBody::Encrypted(e), Some(sk)) => {
let mut d = e.to_vec();
let n = match crate::crypto::sk_decrypt2(sk, &mut d) {
Ok(n) => n,
Err(_) => return Err(Error::SecretKeyMismatch),
};
d.truncate(n);
d
}
_ => return Err(Error::NoSecretKey),
};
*self = Self::Cleartext(body);
Ok(())
}
}
pub type Body = NewBody<Vec<u8>>;
impl From<Vec<u8>> for Body {
fn from(o: Vec<u8>) -> Self {
if o.len() > 0 {
Body::Cleartext(o)
} else {
Body::None
}
}
}
impl From<Option<Body>> for Body {
fn from(o: Option<Body>) -> Self {
match o {
Some(b) => b,
None => Body::None,
}
}
}
pub type PrivateOptions = crate::options::OptionsList<Vec<Options>, Vec<u8>>;
impl From<Vec<Options>> for PrivateOptions {
fn from(o: Vec<Options>) -> Self {
if o.len() > 0 {
PrivateOptions::Cleartext(o)
} else {
PrivateOptions::None
}
}
}
impl PrivateOptions {
pub fn append(&mut self, o: Options) {
match self {
PrivateOptions::Cleartext(opts) => opts.push(o),
PrivateOptions::None => *self = PrivateOptions::Cleartext(vec![o]),
_ => panic!("attmepting to append private options to encrypted object"),
}
}
}
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum BaseError {
Io,
Options(OptionsError),
InvalidSignature,
NoPublicKey,
NoPrivateKey,
NoPeerId,
ValidateError,
DecryptError,
NoDecryptionKey,
PublicKeyIdMismatch,
}
use crate::net;
use crate::page;
pub enum Parent<'a, 'b, 'c> {
None,
Page(&'a page::Page),
Request(&'b net::Request),
Response(&'c net::Response),
}
impl From<OptionsError> for BaseError {
fn from(o: OptionsError) -> BaseError {
BaseError::Options(o)
}
}
impl From<std::io::Error> for BaseError {
fn from(e: std::io::Error) -> BaseError {
error!("io error: {}", e);
BaseError::Io
}
}
impl BaseBuilder {
pub fn base(
&mut self,
id: Id,
application_id: u16,
kind: Kind,
index: u16,
flags: Flags,
) -> &mut Self {
let header = Header::new(application_id, kind, index, flags);
self.id = Some(id);
self.header = Some(header);
self
}
pub fn append_public_option(&mut self, o: Options) -> &mut Self {
match &mut self.public_options {
Some(opts) => opts.push(o),
None => self.public_options = Some(vec![o]),
}
self
}
pub fn append_private_option(&mut self, o: Options) -> &mut Self {
match &mut self.private_options {
Some(PrivateOptions::Cleartext(opts)) => opts.push(o),
_ => self.private_options = Some(PrivateOptions::Cleartext(vec![o])),
}
self
}
}
impl Base {
pub fn new(
id: Id,
application_id: u16,
kind: Kind,
flags: Flags,
version: u16,
body: Body,
public_options: Vec<Options>,
private_options: PrivateOptions,
) -> Base {
let header = Header::new(application_id, kind, version, flags);
Base {
id,
header,
body,
public_options,
private_options,
parent: None,
peer_id: None,
public_key: None,
signature: None,
verified: false,
raw: None,
}
}
pub fn id(&self) -> &Id {
&self.id
}
pub fn header(&self) -> &Header {
&self.header
}
pub fn flags(&self) -> Flags {
self.header.flags()
}
pub fn body(&self) -> &Body {
&self.body
}
pub fn public_options(&self) -> &[Options] {
&self.public_options
}
pub fn private_options(&self) -> &PrivateOptions {
&self.private_options
}
pub fn signature(&self) -> &Option<Signature> {
&self.signature
}
pub fn set_signature(&mut self, sig: Signature) {
self.signature = Some(sig);
}
pub fn append_public_option(&mut self, o: Options) {
self.public_options.push(o);
}
pub fn append_private_option(&mut self, o: Options) {
match &mut self.private_options {
PrivateOptions::Cleartext(opts) => opts.push(o),
PrivateOptions::None => self.private_options = PrivateOptions::Cleartext(vec![o]),
_ => panic!("attmepting to append private options to encrypted object"),
}
}
pub fn clean(&mut self) {}
}
impl Base {
pub fn pub_key_option(options: &[Options]) -> Option<PublicKey> {
options.iter().find_map(|o| match o {
Options::PubKey(pk) => Some(pk.public_key.clone()),
_ => None,
})
}
pub fn peer_id_option(options: &[Options]) -> Option<Id> {
options.iter().find_map(|o| match o {
Options::PeerId(peer_id) => Some(peer_id.peer_id.clone()),
_ => None,
})
}
pub fn issued_option(options: &[Options]) -> Option<DateTime> {
options.iter().find_map(|o| match o {
Options::Issued(t) => Some(t.when),
_ => None,
})
}
pub fn expiry_option(options: &[Options]) -> Option<DateTime> {
options.iter().find_map(|o| match o {
Options::Expiry(t) => Some(t.when),
_ => None,
})
}
pub fn prev_sig_option(options: &[Options]) -> Option<Signature> {
options.iter().find_map(|o| match o {
Options::PrevSig(s) => Some(s.sig.clone()),
_ => None,
})
}
pub fn address_option(options: &[Options]) -> Option<Address> {
options.iter().find_map(|o| match o {
Options::IPv4(addr) => Some(SocketAddr::V4(*addr)),
Options::IPv6(addr) => Some(SocketAddr::V6(*addr)),
_ => None,
})
}
pub fn raw(&self) -> &Option<Vec<u8>> {
&self.raw
}
pub fn set_raw(&mut self, raw: Vec<u8>) {
self.raw = Some(raw);
}
}
impl Base {
pub fn parse<'a, P, S, T: AsRef<[u8]>>(
data: T,
pub_key_s: P,
sec_key_s: S,
) -> Result<(Base, usize), BaseError>
where
P: FnMut(&Id) -> Option<PublicKey>,
S: FnMut(&Id) -> Option<SecretKey>,
{
Container::parse(data, pub_key_s, sec_key_s)
}
}
use std::io::Write;
impl Base {
pub fn encode<'a, T: AsRef<[u8]> + AsMut<[u8]>>(
&mut self,
signing_key: Option<&PrivateKey>,
encryption_key: Option<&SecretKey>,
mut buff: T,
) -> Result<usize, BaseError> {
if let Some(raw) = &self.raw {
let mut d = buff.as_mut();
d.write_all(&raw)?;
return Ok(raw.len());
}
let signing_key = match signing_key {
Some(k) => k,
None => return Err(BaseError::NoPrivateKey),
};
let (container, n) = Container::encode(buff, &self, signing_key, encryption_key);
self.set_signature(container.signature().into());
Ok(n)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::base::*;
use crate::types::PageKind;
use crate::crypto;
fn setup() -> (Id, PublicKey, PrivateKey, SecretKey) {
let (pub_key, pri_key) =
crypto::new_pk().expect("Error generating new public/private key pair");
let id = crypto::hash(&pub_key)
.expect("Error generating new ID")
.into();
let sec_key = crypto::new_sk().expect("Error generating new secret key");
(id, pub_key, pri_key, sec_key)
}
#[test]
fn encode_decode_primary_page() {
let (id, pub_key, pri_key, _sec_key) = setup();
let header = HeaderBuilder::default()
.kind(PageKind::Generic.into())
.build()
.expect("Error building page header");
let data = vec![1, 2, 3, 4, 5, 6, 7];
let mut page = BaseBuilder::default()
.id(id)
.header(header)
.body(Body::Cleartext(data))
.build()
.expect("Error building page");
let mut buff = vec![0u8; 1024];
let n = page
.encode(Some(&pri_key), None, &mut buff)
.expect("Error encoding page");
let (mut decoded, m) = Base::parse(&buff[..n], |_id| Some(pub_key.clone()), |_id| None)
.expect("Error decoding page");
decoded.clean();
assert_eq!(page, decoded);
assert_eq!(n, m);
}
#[test]
fn encode_decode_secondary_page() {
let (id, pub_key, pri_key, _sec_key) = setup();
let fake_id = crypto::hash(&[0x00, 0x11, 0x22]).unwrap();
let header = HeaderBuilder::default()
.flags(Flags::SECONDARY)
.kind(PageKind::Replica.into())
.build()
.expect("Error building page header");
let data = vec![1, 2, 3, 4, 5, 6, 7];
let mut page = BaseBuilder::default()
.id(fake_id)
.header(header)
.body(Body::Cleartext(data))
.peer_id(Some(id.clone()))
.public_key(Some(pub_key.clone()))
.build()
.expect("Error building page");
let mut buff = vec![0u8; 1024];
let n = page
.encode(Some(&pri_key), None, &mut buff)
.expect("Error encoding page");
page.raw = Some(buff[..n].to_vec());
let (mut decoded, m) = Base::parse(&buff[..n], |_id| Some(pub_key.clone()), |_id| None)
.expect("Error decoding page with known public key");
decoded.clean();
assert_eq!(page, decoded);
assert_eq!(n, m);
let (mut decoded, m) = Base::parse(&buff[..n], |_id| None, |_id| None)
.expect("Error decoding page with unknown public key");
decoded.clean();
assert_eq!(page, decoded);
assert_eq!(n, m);
}
#[test]
fn encode_decode_encrypted_page() {
let (id, pub_key, pri_key, sec_key) = setup();
let header = HeaderBuilder::default()
.flags(Flags::ENCRYPTED)
.kind(PageKind::Generic.into())
.build()
.expect("Error building page header");
let data = vec![1, 2, 3, 4, 5, 6, 7];
let mut page = BaseBuilder::default()
.id(id)
.header(header)
.body(Body::Cleartext(data))
.build()
.expect("Error building page");
let mut buff = vec![0u8; 1024];
let n = page
.encode(Some(&pri_key), Some(&sec_key), &mut buff)
.expect("Error encoding page");
let (mut decoded, m) = Base::parse(
&buff[..n],
|_id| Some(pub_key.clone()),
|_id| Some(sec_key.clone()),
)
.expect("Error decoding page");
decoded.clean();
assert_eq!(page, decoded);
assert_eq!(n, m);
}
}