maj/site/src/main.rs

123 lines
3.4 KiB
Rust
Raw Normal View History

2020-07-27 23:49:39 +00:00
use async_std::task;
use rustls::internal::pemfile::{certs, rsa_private_keys};
use rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig};
2020-07-26 00:16:07 +00:00
use std::fs::File;
use std::io::{self, BufReader};
use std::path::{Path, PathBuf};
2020-07-27 23:49:39 +00:00
use std::sync::Arc;
2020-07-26 00:16:07 +00:00
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
struct Options {
/// host to listen on
#[structopt(short = "H", long, env = "HOST", default_value = "0.0.0.0")]
host: String,
/// port to listen on
#[structopt(short = "p", long, env = "PORT", default_value = "1965")]
port: u16,
/// cert file
#[structopt(short = "c", long = "cert", env = "CERT_FILE")]
cert: PathBuf,
/// key file
#[structopt(short = "k", long = "key", env = "KEY_FILE")]
key: PathBuf,
2020-07-26 12:21:02 +00:00
/// server hostname
#[structopt(
long = "hostname",
env = "SERVER_HOSTNAME",
default_value = "maj.kahless.cetacean.club"
)]
hostname: String,
2020-07-26 00:16:07 +00:00
}
fn load_certs(path: &Path) -> io::Result<Vec<Certificate>> {
certs(&mut BufReader::new(File::open(path)?))
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))
}
fn load_keys(path: &Path) -> io::Result<Vec<PrivateKey>> {
rsa_private_keys(&mut BufReader::new(File::open(path)?))
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
}
2020-07-27 23:49:39 +00:00
fn main() -> Result<(), maj::server::Error> {
2020-07-26 00:16:07 +00:00
pretty_env_logger::init();
let opts = Options::from_args();
let certs = load_certs(&opts.cert)?;
let mut keys = load_keys(&opts.key)?;
2020-07-26 12:21:02 +00:00
log::info!("{:?}", opts);
2020-07-26 00:16:07 +00:00
let mut config = ServerConfig::new(NoClientAuth::new());
config
.set_single_cert(certs, keys.remove(0))
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
2020-07-27 23:49:39 +00:00
task::block_on(maj::server::serve(
Arc::new(Handler {
2020-07-26 12:21:02 +00:00
hostname: opts.hostname,
2020-07-27 23:49:39 +00:00
}),
2020-07-26 12:21:02 +00:00
config,
opts.host,
opts.port,
2020-07-27 23:49:39 +00:00
))?;
2020-07-26 00:16:07 +00:00
Ok(())
}
2020-07-26 12:21:02 +00:00
struct Handler {
hostname: String,
}
2020-07-26 00:16:07 +00:00
fn index() -> Result<maj::Response, maj::server::Error> {
let msg = include_bytes!("index.gmi");
2020-07-26 00:16:07 +00:00
Ok(maj::Response {
status: maj::StatusCode::Success,
meta: "text/gemini".to_string(),
body: msg.to_vec(),
})
}
2020-07-26 12:21:02 +00:00
fn majc() -> Result<maj::Response, maj::server::Error> {
let msg = include_bytes!("majc.gmi");
Ok(maj::Response {
status: maj::StatusCode::Success,
meta: "text/gemini".to_string(),
body: msg.to_vec(),
})
}
2020-07-26 00:16:07 +00:00
#[async_trait::async_trait]
impl maj::server::Handler for Handler {
async fn handle(&self, r: maj::server::Request) -> Result<maj::Response, maj::server::Error> {
2020-07-26 12:21:02 +00:00
if r.url.has_host() && r.url.host_str().unwrap().to_string() != self.hostname {
return Ok(maj::Response {
status: maj::StatusCode::ProxyRequestRefused,
meta: "Wrong host".to_string(),
body: vec![],
});
}
2020-07-26 00:16:07 +00:00
match r.url.path() {
2020-07-26 12:21:02 +00:00
"" => Ok(maj::Response {
status: maj::StatusCode::PermanentRedirect,
meta: format!("gemini://{}/", self.hostname),
body: vec![],
}),
"/" => index(),
"/majc" => majc(),
2020-07-26 00:16:07 +00:00
_ => Ok(maj::Response {
status: maj::StatusCode::NotFound,
2020-07-26 12:21:02 +00:00
meta: "Not found".to_string(),
2020-07-26 00:16:07 +00:00
body: vec![],
}),
}
}
}