Browse Source

Configuration file

Signed-off-by: Alexey Yerin <yerinalexey98fd@gmail.com>
master
Alexey Yerin 4 years ago committed by Garrit Franke
parent
commit
0dcc450ffc
  1. 73
      Cargo.lock
  2. 5
      Cargo.toml
  3. 26
      src/config.rs
  4. 13
      src/error.rs
  5. 72
      src/main.rs

73
Cargo.lock generated

@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "anyhow"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
[[package]]
name = "autocfg"
version = "1.0.1"
@ -173,6 +179,24 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
@ -262,11 +286,45 @@ dependencies = [
"libc",
]
[[package]]
name = "serde"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "taurus"
version = "0.0.1"
dependencies = [
"anyhow",
"native-tls",
"serde",
"toml",
"url",
]
@ -290,6 +348,15 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117"
[[package]]
name = "toml"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645"
dependencies = [
"serde",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"
@ -308,6 +375,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "url"
version = "2.1.1"

5
Cargo.toml

@ -8,4 +8,7 @@ edition = "2018"
[dependencies]
url = "2.1.1"
native-tls = "0.2.4"
native-tls = "0.2.4"
serde = { version = "1.0.117", features = ["derive"] }
toml = "0.5.7"
anyhow = "1.0.34"

26
src/config.rs

@ -0,0 +1,26 @@
use serde::Deserialize;
use std::fs;
use std::io::prelude::*;
#[derive(Deserialize)]
pub struct Config {
pub port: Option<u16>,
pub certificate_file: Option<String>,
pub certificate_password: String,
pub static_root: Option<String>,
}
impl Config {
pub fn load(config_path: Option<String>) -> anyhow::Result<Self> {
let config_path = config_path.unwrap_or_else(|| "/etc/taurus/taurus.toml".to_owned());
let mut file = fs::File::open(config_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(toml::from_str(&contents)?)
}
}

13
src/error.rs

@ -0,0 +1,13 @@
pub struct SimpleError(String);
impl std::convert::From<String> for SimpleError {
fn from(string: String) -> Self {
Self(string)
}
}
impl std::fmt::Debug for SimpleError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
formatter.write_str(&self.0)
}
}

72
src/main.rs

@ -1,51 +1,66 @@
extern crate native_tls;
extern crate url;
mod config;
mod error;
mod gemini;
use native_tls::{Identity, TlsAcceptor, TlsStream};
use std::fs::File;
use std::io;
use std::io::Read;
use std::io::Write;
use std::net::TcpListener;
use std::net::TcpStream;
use std::io::{self, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::path;
use std::sync::Arc;
use std::thread;
fn main() {
fn main() -> Result<(), error::SimpleError> {
let config: config::Config = config::Config::load(None)
.map_err(|err| format!("failed to read configuration file: {}", err))?;
// Defaults for configuration file
let port = config.port.unwrap_or(1965);
let cert_file = config
.certificate_file
.unwrap_or_else(|| "/etc/taurus/identity.pfx".to_owned());
let static_root = config
.static_root
.unwrap_or_else(|| "/var/www/gemini".to_owned());
// Read certificate
let mut file =
File::open("identity.pfx").expect("File identity.pfx not found in current directory");
File::open(cert_file).map_err(|err| format!("failed to open identity file: {}", err))?;
let mut identity = vec![];
file.read_to_end(&mut identity)
.expect("Cannot read identity.pfx");
let identity = Identity::from_pkcs12(&identity, "qqqq").unwrap();
.map_err(|err| format!("failed to read identity file: {}", err))?;
let identity = Identity::from_pkcs12(&identity, &config.certificate_password)
.map_err(|err| format!("failed to parse certificate: {}", err))?;
// 1965 is the standard port for gemini
let port = "1965";
let address = format!("0.0.0.0:{}", port);
let listener =
TcpListener::bind(address).unwrap_or_else(|_| panic!("Could not bind to port {}", port));
let listener = TcpListener::bind(address).map_err(|err| format!("failed to bind: {}", err))?;
let acceptor = TlsAcceptor::new(identity).unwrap();
let acceptor = Arc::new(acceptor);
println!("Listening on port 1965");
println!("Info: Listening on port {}", port);
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let acceptor = acceptor.clone();
let static_root = static_root.clone();
thread::spawn(move || match acceptor.accept(stream) {
Ok(stream) => {
handle_client(stream).unwrap_or_else(|e| println!("Error: {}", e))
}
Err(e) => println!("Can't handle stream: {}", e),
Ok(stream) => handle_client(stream, &static_root)
.unwrap_or_else(|e| println!("Error: {}", e)),
Err(e) => println!("Error: can't handle stream: {}", e),
});
}
Err(err) => println!("Error: {}", err),
}
}
Ok(())
}
/// Helper function to read a file into Vec
@ -67,7 +82,7 @@ fn send_file(path: &str, response: &mut gemini::GeminiResonse) {
Err(err) => {
// Cannot read file or it doesn't exist
println!("Error ({}): {}", path, err);
println!("Error [{}]: {}", path, err);
response.status = [b'5', b'1'];
response.meta = format!("Resource not found: {}", path).into();
@ -85,10 +100,10 @@ fn redirect(path: &str, response: &mut gemini::GeminiResonse) {
response.meta = path.into();
}
fn handle_client(mut stream: TlsStream<TcpStream>) -> Result<(), String> {
fn handle_client(mut stream: TlsStream<TcpStream>, static_root: &str) -> Result<(), String> {
let mut buffer = [0; 1024];
if let Err(e) = stream.read(&mut buffer) {
println!("Could not read from stream: {}", e)
return Err(format!("could not read from stream: {}", e));
}
let mut raw_request = String::from_utf8_lossy(&buffer[..]).to_mut().to_owned();
@ -110,23 +125,28 @@ fn handle_client(mut stream: TlsStream<TcpStream>) -> Result<(), String> {
} else {
let path = path::Path::new(".").join(file_path).as_path().to_owned();
let actual_path = path::Path::new(&static_root)
.join(&path)
.as_path()
.to_owned();
// Check if file/dir exists
if path.exists() {
if actual_path.exists() {
// If it's a directory, try to find index.gmi
if path.is_dir() {
if actual_path.is_dir() {
let redir_path = path
.join("index.gmi")
.iter()
.skip(1)
.collect::<path::PathBuf>()
.to_str()
.ok_or("Invalid Unicode".to_owned())?
.ok_or("invalid Unicode".to_owned())?
.to_owned();
redirect(&("/".to_owned() + &redir_path), &mut response);
} else {
send_file(
path.to_str().ok_or("Invalid Unicode".to_owned())?,
actual_path.to_str().ok_or("invalid Unicode".to_owned())?,
&mut response,
);
}
@ -136,7 +156,7 @@ fn handle_client(mut stream: TlsStream<TcpStream>) -> Result<(), String> {
}
if let Err(e) = stream.write(&response.build()) {
println!("Could not write to stream: {}", e);
return Err(format!("could not write to stream: {}", e));
}
Ok(())

Loading…
Cancel
Save