Add Guestbook

This commit is contained in:
Julien Blanchard 2019-08-13 14:50:44 +02:00
parent 541bd4b8b6
commit 9d3b405867
3 changed files with 146 additions and 13 deletions

44
Cargo.lock generated
View File

@ -29,6 +29,17 @@ name = "cfg-if"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "core-foundation"
version = "0.6.4"
@ -118,6 +129,23 @@ dependencies = [
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl"
version = "0.10.24"
@ -162,7 +190,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "pollux"
version = "0.1.0"
dependencies = [
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -273,6 +303,16 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"
@ -329,6 +369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
@ -340,6 +381,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15"
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
"checksum openssl-sys 0.9.48 (registry+https://github.com/rust-lang/crates.io-index)" = "b5ba300217253bcc5dc68bed23d782affa45000193866e025329aa8a7a9f05b8"
@ -358,6 +401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61"

View File

@ -7,4 +7,6 @@ edition = "2018"
[dependencies]
native-tls = "*"
url = "*"
rand = "*"
rand = "*"
percent-encoding = "*"
chrono = "*"

View File

@ -8,9 +8,16 @@ use std::fs::File;
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::str;
use std::sync::Arc;
use std::thread;
use url::Url;
use percent_encoding::percent_decode;
extern crate chrono;
use chrono::{Datelike, Timelike, Utc};
const GUESTBOOK: &str = "/var/gemini/guestbook";
fn main() {
let args: Vec<String> = env::args().collect();
@ -51,14 +58,30 @@ fn handle_request(mut stream: TlsStream<TcpStream>) {
route(stream, request.to_string());
}
fn respond_success(mut stream: TlsStream<TcpStream>, content: String) {
fn respond_input(mut stream: TlsStream<TcpStream>, input: String) {
stream
.write_all(format!("10\t{}\r\n", input).as_bytes())
.unwrap();
}
fn respond_success(mut stream: TlsStream<TcpStream>, content: String, query: Option<&str>) {
// a header
stream.write_all(b"20\ttext/gemini\r\n").unwrap();
stream
.write_all(content.as_bytes())
.expect("Unable to serve file");
match query {
Some(query) => {
append_guestbook(query);
let guestbook = read_guestbook().unwrap();
stream
.write_all(guestbook.as_bytes())
.expect("Unable to serve file");
}
None => {
stream
.write_all(content.as_bytes())
.expect("Unable to serve file");
}
}
// a footer :)
stream
.write_all(b"\n\n---\nServed by Pollux Gemini Server.")
@ -72,6 +95,35 @@ fn respond_redirect(mut stream: TlsStream<TcpStream>) {
.unwrap();
}
fn append_guestbook(message: &str) {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.write(true)
.open(GUESTBOOK)
.expect("file not found");
let now = Utc::now();
let date = format!("{:02}/{:02}/{:04} at {:02}:{:02}", now.day(), now.month(), now.year(), now.hour(), now.minute());
let text = str::replace(message, "query=", "");
let utf8_text = percent_decode(text.as_bytes()).decode_utf8().unwrap();
let entry = format!("\n- {}\n{:?}\n", date, utf8_text);
file.write_all(entry.as_bytes())
.expect("Unable to write file");
}
fn read_guestbook() -> Option<String> {
let mut file = File::open(GUESTBOOK).expect("file not found");
let mut content = String::new();
file.read_to_string(&mut content)
.expect("Unable to read file");
if content.len() > 0 {
Some(content)
} else {
None
}
}
fn random_url() -> &'static str {
let urls = vec![
"gemini://gemini.conman.org",
@ -95,15 +147,25 @@ fn make_pkcs12(pfx_file_path: &str, pfx_file_password: &str) -> native_tls::Iden
fn route(stream: TlsStream<TcpStream>, request: String) {
let url = Url::parse(&request).unwrap();
let query = url.query();
let route = match url.path() {
"/" => (20, String::from("index.gemini")),
"/roulette" => (31, String::new()),
path => (20, str::replace(path, "/", "")),
"/" => (20, String::from("index.gemini"), None),
"/roulette" => (31, String::new(), None),
"/guestbook" => (20, String::from(GUESTBOOK), None),
"/guestbook/new" => {
if query.is_some() {
(20, String::from(GUESTBOOK), query)
} else {
(10, String::from("Leave a message."), None)
}
},
path => (20, str::replace(path, "/", ""), None),
};
match route {
(20, path) => {
(10, message, _) => respond_input(stream, String::from(message)),
(20, path, query) => {
let mut file = OpenOptions::new()
.read(true)
.open(&path)
@ -113,9 +175,34 @@ fn route(stream: TlsStream<TcpStream>, request: String) {
file.read_to_string(&mut content)
.expect("Unable to read file");
respond_success(stream, content)
respond_success(stream, content, query)
}
(31, _) => respond_redirect(stream),
_ => ()
(31, _, _) => respond_redirect(stream),
_ => (),
}
}
// 10 => Status::Input(meta),
// 2 => Status::Success(meta),
// 20 => Status::Success(meta),
// 200 => Status::Success(meta),
// 21 => Status::SuccessEndOfClientCertificateSession(meta),
// 30 => Status::RedirectTemporary(meta),
// 31 => Status::RedirectPermanent(meta),
// 40 => Status::TemporaryFailure(meta),
// 41 => Status::ServerUnavailable(meta),
// 42 => Status::CGIError(meta),
// 43 => Status::ProxyError(meta),
// 44 => Status::SlowDown(meta),
// 50 => Status::PermanentFailure(meta),
// 51 => Status::NotFound(meta),
// 52 => Status::Gone(meta),
// 53 => Status::ProxyRequestRefused(meta),
// 59 => Status::BadRequest(meta),
// 60 => Status::ClientCertificateRequired(meta),
// 61 => Status::TransientCertificateRequired(meta),
// 62 => Status::AuthorisedCertificatedRequired(meta),
// 63 => Status::CertificateNotAccepted(meta),
// 64 => Status::FutureCertificateRejected(meta),
// 65 => Status::ExpiredCertificateRejected(meta),
// _ => Status::Unknown(meta)