mod certs;
pub use certs::generate_cert;
use anyhow::Result;
use core::task::{Context, Poll};
use fs::File;
use futures_util::stream::Stream;
use rustls::{server::NoClientAuth, ServerConfig};
use std::path::PathBuf;
use std::pin::Pin;
use std::sync::Arc;
use std::vec::Vec;
use std::{fs, io};
use tokio::net::TcpStream;
use tokio_rustls::{server::TlsStream, TlsAcceptor};
use crate::settings::get_wrangler_home_dir;
pub(super) fn get_tls_acceptor() -> Result<TlsAcceptor> {
let home = get_wrangler_home_dir().join("config");
let cert = home.join("dev-cert.pem");
let privkey = home.join("dev-privkey.rsa");
let certs = load_certs(cert)?;
let key = load_private_key(privkey)?;
let cfg = ServerConfig::builder()
.with_safe_defaults()
.with_client_cert_verifier(NoClientAuth::new());
let cfg = cfg
.with_single_cert(certs, key)
.map_err(|e| io_error(format!("{}", e)))?;
Ok(TlsAcceptor::from(Arc::new(cfg)))
}
pub(super) fn io_error(err: String) -> io::Error {
io::Error::new(io::ErrorKind::Other, err)
}
pub(super) struct HyperAcceptor<'a> {
pub(super) acceptor:
Pin<Box<dyn Stream<Item = Result<TlsStream<TcpStream>, io::Error>> + Send + 'a>>,
}
impl hyper::server::accept::Accept for HyperAcceptor<'_> {
type Conn = TlsStream<TcpStream>;
type Error = io::Error;
fn poll_accept(
mut self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
Pin::new(&mut self.acceptor).poll_next(cx)
}
}
fn get_tls_file(file: PathBuf) -> Result<File, io::Error> {
File::open(&file)
}
fn load_certs(file: PathBuf) -> io::Result<Vec<rustls::Certificate>> {
let certfile = get_tls_file(file)?;
let mut reader = io::BufReader::new(certfile);
match rustls_pemfile::certs(&mut reader) {
Ok(certs) => Ok(certs.into_iter().map(rustls::Certificate).collect()),
Err(_) => Err(io_error("failed to load certificate".into())),
}
}
fn load_private_key(file: PathBuf) -> io::Result<rustls::PrivateKey> {
let keyfile = get_tls_file(file)?;
let mut reader = io::BufReader::new(keyfile);
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut reader)
.map_err(|_| io_error("failed to load private key".into()))?;
if keys.len() != 1 {
return Err(io_error("expected a single private key".into()));
}
Ok(rustls::PrivateKey(keys.pop().unwrap()))
}