Url to path doesn't work for dir list

This commit is contained in:
int 80h
2020-04-21 19:40:57 -04:00
parent ef003c3eee
commit 4056cbbc2f
3 changed files with 116 additions and 81 deletions

View File

@@ -1,18 +1,17 @@
extern crate serde_derive;
extern crate toml;
use toml::de::Error;
use std::collections::HashMap;
use toml::de::Error;
// use serde_derive::Deserialize;
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub struct Config {
pub port: i32,
pub host: String,
pub server: Vec<Server>,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub struct Server {
pub url: String,
pub dir: String,
@@ -26,13 +25,11 @@ impl Config {
let config: Config = toml::from_str(&fd).unwrap();
return config;
}
pub fn to_map( &self /*cfg: &config::Config*/) -> HashMap<String, String> {
pub fn to_map(&self /*cfg: &config::Config*/) -> HashMap<String, String> {
let mut map = HashMap::new();
for srv in &self.server {
map.insert(srv.url.clone(), srv.dir.clone());
}
map
}
}

View File

@@ -2,24 +2,25 @@
#[macro_use]
extern crate serde_derive;
use std::fs::File;
use std::sync::Arc;
use std::net::ToSocketAddrs;
use std::io::{ self, BufReader };
use std::collections::HashMap;
use futures_util::future::TryFutureExt;
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::fs;
use std::io::{self, BufReader};
use std::net::ToSocketAddrs;
use std::sync::Arc;
use std::path::{Path, PathBuf};
use tokio::io::AsyncWriteExt;
use tokio::net::TcpListener;
use tokio::net::TcpStream;
use tokio::prelude::*;
use tokio::runtime;
use tokio::net::TcpListener;
use tokio::io::AsyncWriteExt;
use tokio_rustls::rustls::{ Certificate, NoClientAuth, PrivateKey, ServerConfig };
use tokio_rustls::rustls::internal::pemfile::{ certs, pkcs8_private_keys };
use tokio_rustls::TlsAcceptor;
use tokio_rustls::rustls::internal::pemfile::{certs, pkcs8_private_keys};
use tokio_rustls::rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig};
use tokio_rustls::server::TlsStream;
use tokio::net::TcpStream;
use tokio_rustls::TlsAcceptor;
use url::Url;
use std::error::Error;
mod config;
mod tls;
@@ -27,54 +28,93 @@ mod tls;
fn get_tls_config(cfg: config::Config) -> rustls::ServerConfig {
let store = rustls::RootCertStore::empty();
let verifier = rustls::AllowAnyAnonymousOrAuthenticatedClient::new(store);
let mut tls_config = rustls::ServerConfig::new( verifier /*NoClientAuth::new()*/);
let mut tls_config = rustls::ServerConfig::new(verifier);
tls_config.cert_resolver = Arc::new(tls::CertResolver::from_config(cfg).unwrap());
tls_config
}
fn get_content(request: String) -> String {
fn get_content(mut path: PathBuf, u: url::Url) -> Result<String, io::Error> {
println!("URL: {}", u);
if u.path() == "" || u.path() == "/" {
path.push("index.gemini");
} else {
path.push(u.path().trim_start_matches("/"));
}
let url = Url::parse(&request).unwrap();
if !u.path().ends_with("/") {
u.path().to_string().push('/');
}
println!("{}", path.to_str().unwrap());
let path = match url.path() {
"/" => String::from("index.gemini"),
path => str::replace(path, "/", ""),
};
let fd = std::fs::read_to_string(path)
.expect("Unable to read file");
fd
if !path.exists() {
return Ok("51 Not found!\r\n".to_string())
}
let meta = fs::metadata(&path).expect("Unable to read metadata");
if meta.is_file() {
return Ok(std::fs::read_to_string(path).expect("Unable to read file"));
}
let mut list = String::from("# Directory Listing\n\n");
if !u.path().ends_with("/") {
path.push(format!("{}/", u.path().trim_start_matches("/")));
}
for file in fs::read_dir(path)? {
if let Ok(file) = file {
let f = file.file_name().to_str().unwrap().to_owned();
let p = u.join(&f).unwrap().as_str().to_owned();
println!("=>\t{} {}\r\n", p, f);
list.push_str(format!("=> {} {}\n", p, f).as_str());
}
}
return Ok(list);
}
async fn handle_connection(mut stream: TlsStream<TcpStream>) -> Result<(), Box<dyn Error>> {
let mut buffer = [0;512];
async fn handle_connection(
mut stream: TlsStream<TcpStream>,
cfg: config::Config,
) -> Result<(), io::Error> {
let mut buffer = [0; 512];
stream.read(&mut buffer).await?;
let request = String::from_utf8_lossy(&buffer[..]).to_owned();
println!("Request: {}", request);
/*
let url = Url::parse(&request).unwrap();
for name in cfg.server {
if url.host_str() == Some(&name.url) {
println!("serving url: {:?}", url.host_str());
if url.scheme() != "gemini" {
stream.write_all(&b"53\tnot gemini scheme!\r\n"[..]).await?;
stream.flush().await?;
panic!("Not gemini scheme");
}
if url.path().to_string().contains("..") {
stream.write_all(&b"50\tNot in path\r\n"[..]).await?;
stream.flush().await?;
panic!("Contains ..");
}
let mut dir = String::new();
for server in cfg.server {
if Some(server.url.as_str()) == url.host_str() {
dir = server.dir;
}
}
*/
let p = PathBuf::from(dir);
stream.write_all(&b"20\ttext/gemini\r\n"[..]).await?;
stream.flush().await?;
let content = get_content(request.to_string());
let content = get_content(p, url)?;
stream.write_all(content.as_bytes()).await?;
stream.flush().await?;
Ok(())
}
fn main() -> io::Result<()> {
let cfg = config::Config::new("config.toml");
let srv_map = cfg.to_map();
let addr = format!("{}:{}", cfg.host, cfg.port);
addr.to_socket_addrs()?
@@ -85,21 +125,22 @@ fn main() -> io::Result<()> {
.threaded_scheduler()
.enable_io()
.build()?;
let handle = runtime.handle().clone();
let config = get_tls_config(cfg);
let config = get_tls_config(cfg.clone());
let acceptor = TlsAcceptor::from(Arc::new(config));
let fut = async {
let mut listener = TcpListener::bind(&addr).await?;
loop {
let (stream, peer_addr) = listener.accept().await?;
let acceptor = acceptor.clone();
let cfg = cfg.clone();
let fut = async move {
let stream = acceptor.accept(stream).await?;
handle_connection(stream).await;
handle_connection(stream, cfg).await?;
println!("Hello: {}", peer_addr);
Ok(()) as io::Result<()>

View File

@@ -1,15 +1,15 @@
use std::fs::File;
use std::io::{ self, BufReader };
use std::error::Error;
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::io::{self, BufReader};
use std::sync::Arc;
use rustls::{ResolvesServerCert, SignatureScheme};
use rustls::ClientHello;
use rustls::sign::CertifiedKey;
use rustls::sign::{Signer, SigningKey, RSASigningKey};
use tokio_rustls::rustls::{ Certificate, NoClientAuth, PrivateKey, ServerConfig };
use tokio_rustls::rustls::internal::pemfile::{ certs, pkcs8_private_keys };
use rustls::sign::{RSASigningKey, Signer, SigningKey};
use rustls::ClientHello;
use rustls::{ResolvesServerCert, SignatureScheme};
use tokio_rustls::rustls::internal::pemfile::{certs, pkcs8_private_keys};
use tokio_rustls::rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig};
use crate::config;
@@ -19,20 +19,18 @@ pub fn load_certs(path: &String) -> io::Result<Vec<Certificate>> {
}
pub fn load_key(path: &String) -> PrivateKey {
let keyfile = File::open(path)
.expect("cannot open private key file");
let keyfile = File::open(path).expect("cannot open private key file");
let mut reader = BufReader::new(keyfile);
let key = pkcs8_private_keys(&mut reader)
.expect("file contains invalid rsa private key");
let key = pkcs8_private_keys(&mut reader).expect("file contains invalid rsa private key");
return key[0].clone();
}
pub struct CertResolver {
map: HashMap<String, Box<CertifiedKey>>
map: HashMap<String, Box<CertifiedKey>>,
}
impl CertResolver {
pub fn from_config(cfg: config::Config) -> Result<Self,()> {
pub fn from_config(cfg: config::Config) -> Result<Self, ()> {
let mut map = HashMap::new();
for server in cfg.server.iter() {
@@ -45,30 +43,29 @@ impl CertResolver {
CertifiedKey::new(&key).map_err(|_| format!("Failed to create signer for {}", server.url))
));
*/
let signing_key = RSASigningKey::new(
&key).unwrap();
let signing_key = RSASigningKey::new(&key).unwrap();
let signing_key_boxed: Arc<Box<dyn SigningKey>> = Arc::new(
Box::new(signing_key));
map.insert(server.url.clone(), Box::new(rustls::sign::CertifiedKey::new(
certs, signing_key_boxed)));
let signing_key_boxed: Arc<Box<dyn SigningKey>> = Arc::new(Box::new(signing_key));
map.insert(
server.url.clone(),
Box::new(rustls::sign::CertifiedKey::new(certs, signing_key_boxed)),
);
}
println!("Successfully loaded {} TLS configurations", map.len());
Ok(CertResolver{ map })
Ok(CertResolver { map })
}
}
impl ResolvesServerCert for CertResolver {
fn resolve( &self, client_hello: ClientHello) -> Option<CertifiedKey> {
fn resolve(&self, client_hello: ClientHello) -> Option<CertifiedKey> {
if let Some(url) = client_hello.server_name() {
if let Some(cert) = self.map.get(url.into()) {
return Some(*cert.clone())
return Some(*cert.clone());
}
}
None
}
}