use std::io::{Read, Write}; use std::net::TcpStream; #[derive(Clone)] pub struct TlsServer { acceptor: native_tls::TlsAcceptor, } impl TlsServer { pub fn new( cert_path: &str, _key_path: &str, unsafe_mode: bool, ) -> Result> { let cert_data = if unsafe_mode { if std::path::Path::new(cert_path).exists() { std::fs::read(cert_path)? } else { return Err(format!( "Certificate file '{}' not found. In --unsafe mode, you must provide a valid PKCS12 certificate file.\n\ You can generate one with:\n\ openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes\n\ openssl pkcs12 -export -out identity.p12 -inkey key.pem -in cert.pem", cert_path ).into()); } } else { std::fs::read(cert_path)? }; let identity = native_tls::Identity::from_pkcs12(&cert_data, "")?; let acceptor = native_tls::TlsAcceptor::new(identity)?; Ok(Self { acceptor }) } pub fn accept(&self, stream: TcpStream) -> Result> { let stream = self.acceptor.accept(stream)?; Ok(TlsStream::new(stream)) } } pub struct TlsStream { stream: native_tls::TlsStream, } impl TlsStream { pub fn new(stream: native_tls::TlsStream) -> Self { Self { stream } } pub fn read_line(&mut self, s: &mut String) -> std::io::Result { let mut buf = [0u8; 1024]; loop { match self.stream.read(&mut buf) { Ok(0) => return Ok(0), Ok(n) => { let chunk = std::str::from_utf8(&buf[..n]).unwrap_or(""); s.push_str(chunk); if s.contains('\n') { return Ok(n); } } Err(e) => return Err(e), } } } pub fn write_line(&mut self, msg: &str) -> std::io::Result<()> { use std::io::Write; self.stream.write_all(msg.as_bytes())?; self.stream.write_all(b"\n")?; self.stream.flush()?; Ok(()) } pub fn peer_addr(&self) -> std::io::Result { self.stream.get_ref().peer_addr() } } impl Read for TlsStream { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.stream.read(buf) } } impl Write for TlsStream { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.stream.write(buf) } fn flush(&mut self) -> std::io::Result<()> { self.stream.flush() } }