actix-telegram 0.0.5

telegram bot api lib based on actix
use crate::types::InputFile;
#[cfg(feature = "tls")]
use native_tls::{Identity, Protocol, TlsAcceptor};
#[cfg(feature = "ssl")]
use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod};
#[cfg(feature = "rust-tls")]
use rustls::{
    internal::pemfile::{certs, pkcs8_private_keys, rsa_private_keys},
    Certificate, NoClientAuth, PrivateKey, ServerConfig,
};
#[allow(unused_imports)]
use std::fs::{self, File};
#[allow(unused_imports)]
use std::io::BufReader;
use std::path::{Path, PathBuf};

pub enum Key {
    #[cfg(feature = "rust-tls")]
    Rustls(RustlsKey),
    #[cfg(feature = "ssl")]
    Openssl(OpensslKey),
    #[cfg(feature = "tls")]
    NativeTls(NativeTlsKey),
}

#[cfg(feature = "rust-tls")]
pub enum KeyKind {
    RSA,
    PKCS8,
}

#[cfg(feature = "rust-tls")]
pub struct RustlsKey {
    key: PathBuf,
    kind: KeyKind,
}

#[cfg(feature = "ssl")]
pub struct OpensslKey {
    key: PathBuf,
}

#[cfg(feature = "tls")]
pub struct NativeTlsKey {
    password: String,
}

impl Key {
    #[cfg(feature = "rust-tls")]
    pub fn new<P: AsRef<Path>>(key: P, kind: KeyKind) -> Self {
        let key = key.as_ref().to_path_buf();
        if !key.exists() {
            panic!("Key file not found")
        }
        Key::Rustls(RustlsKey { key, kind })
    }

    #[cfg(feature = "openssl")]
    pub fn new<P: AsRef<Path>>(key: P) -> Self {
        let key = key.as_ref().to_path_buf();
        if !key.exists() {
            panic!("Key file not found")
        }
        Key::Openssl(OpensslKey { key })
    }

    #[cfg(feature = "tls")]
    pub fn new(password: String) -> Self {
        Key::NativeTls(NativeTlsKey { password })
    }

    #[cfg(feature = "rust-tls")]
    fn key(&self) -> PrivateKey {
        match self {
            Key::Rustls(RustlsKey { key, kind }) => {
                let key_file = &mut BufReader::new(File::open(key.as_path()).unwrap());
                let mut keys = match kind {
                    KeyKind::RSA => rsa_private_keys(key_file).unwrap(),
                    KeyKind::PKCS8 => pkcs8_private_keys(key_file).unwrap(),
                };
                keys.remove(0)
            }
        }
    }

    #[cfg(feature = "ssl")]
    fn key(&self) -> &Path {
        match self {
            Key::Openssl(OpensslKey { key }) => key.as_path(),
        }
    }

    #[cfg(feature = "tls")]
    fn key(&self) -> &str {
        match self {
            Key::NativeTls(NativeTlsKey { password }) => password,
        }
    }
}

pub enum Cert {
    #[cfg(feature = "rust-tls")]
    Rustls(RustlsCert),
    #[cfg(feature = "ssl")]
    Openssl(OpensslCert),
    #[cfg(feature = "tls")]
    NativeTls(NativeTlsCert),
}

#[cfg(feature = "rust-tls")]
pub struct RustlsCert {
    cert: PathBuf,
}

#[cfg(feature = "ssl")]
pub struct OpensslCert {
    cert: PathBuf,
}

#[cfg(feature = "tls")]
pub struct NativeTlsCert {
    cert_pem: PathBuf,
    cert_p12: PathBuf,
}

impl Cert {
    #[cfg(feature = "rust-tls")]
    pub fn new<P: AsRef<Path>>(cert: P) -> Self {
        let cert = cert.as_ref().to_path_buf();
        if !cert.exists() {
            panic!("Certificate file not found")
        }
        Cert::Rustls(RustlsCert { cert })
    }

    #[cfg(feature = "openssl")]
    pub fn new<P: AsRef<Path>>(cert: P) -> Self {
        let cert = cert.as_ref().to_path_buf();
        if !cert.exists() {
            panic!("Certificate file not found")
        }
        Cert::Openssl(OpensslCert { cert })
    }

    #[cfg(feature = "tls")]
    pub fn new<P: AsRef<Path>, P1: AsRef<Path>>(cert_pem: P, cert_p12: P1) -> Self {
        let cert_pem = cert_pem.as_ref().to_path_buf();
        let cert_p12 = cert_p12.as_ref().to_path_buf();
        if !(cert_pem.exists() && cert_p12.exists()) {
            panic!("Certificate files not found")
        }
        Cert::NativeTls(NativeTlsCert { cert_pem, cert_p12 })
    }

    #[cfg(feature = "rust-tls")]
    fn cert(&self) -> Vec<Certificate> {
        match self {
            Cert::Rustls(RustlsCert { cert }) => {
                let cert_file = &mut BufReader::new(File::open(cert.as_path()).unwrap());
                certs(cert_file).unwrap()
            }
        }
    }

    #[cfg(feature = "ssl")]
    fn cert(&self) -> &Path {
        match self {
            Cert::Openssl(OpensslCert { cert }) => cert.as_path(),
        }
    }

    #[cfg(feature = "tls")]
    fn cert(&self) -> Vec<u8> {
        match self {
            Cert::NativeTls(NativeTlsCert { cert_p12, .. }) => {
                fs::read(cert_p12.as_path()).unwrap()
            }
        }
    }
}

impl<'a> From<&'a CertAndKey> for InputFile {
    #[inline(always)]
    fn from(cert_and_key: &CertAndKey) -> Self {
        From::from(&cert_and_key.cert)
    }
}

impl<'a> From<&'a Cert> for InputFile {
    #[cfg(feature = "rust-tls")]
    #[inline(always)]
    fn from(cert: &Cert) -> InputFile {
        match cert {
            Cert::Rustls(RustlsCert { cert }) => InputFile::Disk {
                path: cert.to_string_lossy().to_string(),
            },
        }
    }

    #[cfg(feature = "ssl")]
    #[inline(always)]
    fn from(cert: &Cert) -> InputFile {
        match cert {
            Cert::Openssl(OpensslCert { cert }) => InputFile::Disk {
                path: cert.to_string_lossy().to_string(),
            },
        }
    }

    #[cfg(feature = "tls")]
    #[inline(always)]
    fn from(cert: &Cert) -> InputFile {
        match cert {
            Cert::NativeTls(NativeTlsCert { cert_pem, .. }) => InputFile::Disk {
                path: cert_pem.to_string_lossy().to_string(),
            },
        }
    }
}

pub struct CertAndKey {
    cert: Cert,
    key: Key,
}

impl CertAndKey {
    pub fn new(cert: Cert, key: Key) -> Self {
        Self { cert, key }
    }

    #[cfg(feature = "rust-tls")]
    pub(super) fn get_acceptor(&self) -> ServerConfig {
        let mut config = ServerConfig::new(NoClientAuth::new());
        config
            .set_single_cert(self.cert.cert(), self.key.key())
            .unwrap();
        config
    }

    #[cfg(feature = "ssl")]
    pub(super) fn get_acceptor(&self) -> SslAcceptorBuilder {
        let mut builder = SslAcceptor::mozilla_modern(SslMethod::tls()).unwrap();
        builder
            .set_private_key_file(self.key.key(), SslFiletype::PEM)
            .unwrap();
        builder
            .set_certificate_chain_file(self.cert.cert())
            .unwrap();
        builder
    }

    #[cfg(feature = "tls")]
    pub(super) fn get_acceptor(&self) -> TlsAcceptor {
        let identity = Identity::from_pkcs12(&self.cert.cert(), self.key.key()).unwrap();
        TlsAcceptor::builder(identity)
            .min_protocol_version(Some(Protocol::Tlsv12))
            .build()
            .unwrap()
    }
}