Url to path doesn't work for dir list
This commit is contained in:
@@ -1,22 +1,21 @@
|
|||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
use toml::de::Error;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use toml::de::Error;
|
||||||
// use serde_derive::Deserialize;
|
// use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub port: i32,
|
pub port: i32,
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub server: Vec<Server>,
|
pub server: Vec<Server>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub dir: String,
|
pub dir: String,
|
||||||
pub key: String,
|
pub key: String,
|
||||||
pub cert: String,
|
pub cert: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,13 +25,11 @@ impl Config {
|
|||||||
let config: Config = toml::from_str(&fd).unwrap();
|
let config: Config = toml::from_str(&fd).unwrap();
|
||||||
return config;
|
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();
|
let mut map = HashMap::new();
|
||||||
for srv in &self.server {
|
for srv in &self.server {
|
||||||
map.insert(srv.url.clone(), srv.dir.clone());
|
map.insert(srv.url.clone(), srv.dir.clone());
|
||||||
}
|
}
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
117
src/main.rs
117
src/main.rs
@@ -2,24 +2,25 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
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 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::prelude::*;
|
||||||
use tokio::runtime;
|
use tokio::runtime;
|
||||||
use tokio::net::TcpListener;
|
use tokio_rustls::rustls::internal::pemfile::{certs, pkcs8_private_keys};
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio_rustls::rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig};
|
||||||
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::server::TlsStream;
|
use tokio_rustls::server::TlsStream;
|
||||||
use tokio::net::TcpStream;
|
use tokio_rustls::TlsAcceptor;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod tls;
|
mod tls;
|
||||||
@@ -27,54 +28,93 @@ mod tls;
|
|||||||
fn get_tls_config(cfg: config::Config) -> rustls::ServerConfig {
|
fn get_tls_config(cfg: config::Config) -> rustls::ServerConfig {
|
||||||
let store = rustls::RootCertStore::empty();
|
let store = rustls::RootCertStore::empty();
|
||||||
let verifier = rustls::AllowAnyAnonymousOrAuthenticatedClient::new(store);
|
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.cert_resolver = Arc::new(tls::CertResolver::from_config(cfg).unwrap());
|
||||||
|
|
||||||
tls_config
|
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() {
|
if !path.exists() {
|
||||||
"/" => String::from("index.gemini"),
|
return Ok("51 Not found!\r\n".to_string())
|
||||||
path => str::replace(path, "/", ""),
|
}
|
||||||
};
|
let meta = fs::metadata(&path).expect("Unable to read metadata");
|
||||||
|
if meta.is_file() {
|
||||||
let fd = std::fs::read_to_string(path)
|
return Ok(std::fs::read_to_string(path).expect("Unable to read file"));
|
||||||
.expect("Unable to read file");
|
}
|
||||||
|
let mut list = String::from("# Directory Listing\n\n");
|
||||||
fd
|
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>> {
|
async fn handle_connection(
|
||||||
let mut buffer = [0;512];
|
mut stream: TlsStream<TcpStream>,
|
||||||
|
cfg: config::Config,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
|
|
||||||
|
let mut buffer = [0; 512];
|
||||||
stream.read(&mut buffer).await?;
|
stream.read(&mut buffer).await?;
|
||||||
let request = String::from_utf8_lossy(&buffer[..]).to_owned();
|
let request = String::from_utf8_lossy(&buffer[..]).to_owned();
|
||||||
println!("Request: {}", request);
|
println!("Request: {}", request);
|
||||||
/*
|
|
||||||
|
|
||||||
let url = Url::parse(&request).unwrap();
|
let url = Url::parse(&request).unwrap();
|
||||||
for name in cfg.server {
|
|
||||||
if url.host_str() == Some(&name.url) {
|
if url.scheme() != "gemini" {
|
||||||
println!("serving url: {:?}", url.host_str());
|
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.write_all(&b"20\ttext/gemini\r\n"[..]).await?;
|
||||||
stream.flush().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.write_all(content.as_bytes()).await?;
|
||||||
stream.flush().await?;
|
stream.flush().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
fn main() -> io::Result<()> {
|
||||||
let cfg = config::Config::new("config.toml");
|
let cfg = config::Config::new("config.toml");
|
||||||
let srv_map = cfg.to_map();
|
|
||||||
|
|
||||||
let addr = format!("{}:{}", cfg.host, cfg.port);
|
let addr = format!("{}:{}", cfg.host, cfg.port);
|
||||||
addr.to_socket_addrs()?
|
addr.to_socket_addrs()?
|
||||||
@@ -85,21 +125,22 @@ fn main() -> io::Result<()> {
|
|||||||
.threaded_scheduler()
|
.threaded_scheduler()
|
||||||
.enable_io()
|
.enable_io()
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
let handle = runtime.handle().clone();
|
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 acceptor = TlsAcceptor::from(Arc::new(config));
|
||||||
|
|
||||||
let fut = async {
|
let fut = async {
|
||||||
let mut listener = TcpListener::bind(&addr).await?;
|
let mut listener = TcpListener::bind(&addr).await?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (stream, peer_addr) = listener.accept().await?;
|
let (stream, peer_addr) = listener.accept().await?;
|
||||||
let acceptor = acceptor.clone();
|
let acceptor = acceptor.clone();
|
||||||
|
let cfg = cfg.clone();
|
||||||
|
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
let stream = acceptor.accept(stream).await?;
|
let stream = acceptor.accept(stream).await?;
|
||||||
handle_connection(stream).await;
|
handle_connection(stream, cfg).await?;
|
||||||
println!("Hello: {}", peer_addr);
|
println!("Hello: {}", peer_addr);
|
||||||
|
|
||||||
Ok(()) as io::Result<()>
|
Ok(()) as io::Result<()>
|
||||||
|
|||||||
63
src/tls.rs
63
src/tls.rs
@@ -1,15 +1,15 @@
|
|||||||
use std::fs::File;
|
|
||||||
use std::io::{ self, BufReader };
|
|
||||||
use std::error::Error;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, BufReader};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustls::{ResolvesServerCert, SignatureScheme};
|
|
||||||
use rustls::ClientHello;
|
|
||||||
use rustls::sign::CertifiedKey;
|
use rustls::sign::CertifiedKey;
|
||||||
use rustls::sign::{Signer, SigningKey, RSASigningKey};
|
use rustls::sign::{RSASigningKey, Signer, SigningKey};
|
||||||
use tokio_rustls::rustls::{ Certificate, NoClientAuth, PrivateKey, ServerConfig };
|
use rustls::ClientHello;
|
||||||
use tokio_rustls::rustls::internal::pemfile::{ certs, pkcs8_private_keys };
|
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;
|
use crate::config;
|
||||||
|
|
||||||
@@ -19,56 +19,53 @@ pub fn load_certs(path: &String) -> io::Result<Vec<Certificate>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_key(path: &String) -> PrivateKey {
|
pub fn load_key(path: &String) -> PrivateKey {
|
||||||
let keyfile = File::open(path)
|
let keyfile = File::open(path).expect("cannot open private key file");
|
||||||
.expect("cannot open private key file");
|
|
||||||
let mut reader = BufReader::new(keyfile);
|
let mut reader = BufReader::new(keyfile);
|
||||||
let key = pkcs8_private_keys(&mut reader)
|
let key = pkcs8_private_keys(&mut reader).expect("file contains invalid rsa private key");
|
||||||
.expect("file contains invalid rsa private key");
|
|
||||||
return key[0].clone();
|
return key[0].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CertResolver {
|
pub struct CertResolver {
|
||||||
map: HashMap<String, Box<CertifiedKey>>
|
map: HashMap<String, Box<CertifiedKey>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CertResolver {
|
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();
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
for server in cfg.server.iter() {
|
for server in cfg.server.iter() {
|
||||||
let key = load_key(&server.key);
|
let key = load_key(&server.key);
|
||||||
// .chain_err(|| format!("Failed to load private key from {}", https.key_file))?;
|
// .chain_err(|| format!("Failed to load private key from {}", https.key_file))?;
|
||||||
let certs = load_certs(&server.cert).unwrap();
|
let certs = load_certs(&server.cert).unwrap();
|
||||||
// .chain_err(|| format!("Failed to load certificate from {}", server.cert));
|
// .chain_err(|| format!("Failed to load certificate from {}", server.cert));
|
||||||
/*
|
/*
|
||||||
let signer: Arc<Box<CertifiedKey>> = Arc::new(Box::new(
|
let signer: Arc<Box<CertifiedKey>> = Arc::new(Box::new(
|
||||||
CertifiedKey::new(&key).map_err(|_| format!("Failed to create signer for {}", server.url))
|
CertifiedKey::new(&key).map_err(|_| format!("Failed to create signer for {}", server.url))
|
||||||
));
|
));
|
||||||
*/
|
*/
|
||||||
let signing_key = RSASigningKey::new(
|
let signing_key = RSASigningKey::new(&key).unwrap();
|
||||||
&key).unwrap();
|
|
||||||
|
|
||||||
let signing_key_boxed: Arc<Box<dyn SigningKey>> = Arc::new(
|
let signing_key_boxed: Arc<Box<dyn SigningKey>> = Arc::new(Box::new(signing_key));
|
||||||
Box::new(signing_key));
|
map.insert(
|
||||||
map.insert(server.url.clone(), Box::new(rustls::sign::CertifiedKey::new(
|
server.url.clone(),
|
||||||
certs, signing_key_boxed)));
|
Box::new(rustls::sign::CertifiedKey::new(certs, signing_key_boxed)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Successfully loaded {} TLS configurations", map.len());
|
println!("Successfully loaded {} TLS configurations", map.len());
|
||||||
|
|
||||||
Ok(CertResolver{ map })
|
Ok(CertResolver { map })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResolvesServerCert for CertResolver {
|
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(url) = client_hello.server_name() {
|
||||||
if let Some(cert) = self.map.get(url.into()) {
|
if let Some(cert) = self.map.get(url.into()) {
|
||||||
return Some(*cert.clone())
|
return Some(*cert.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user