351 lines
8.6 KiB
Rust
351 lines
8.6 KiB
Rust
use super::{cli, config, db, queries::*, static_files, templates::*, utils::*};
|
|
|
|
use handlebars::to_json;
|
|
use sha2::{Digest, Sha512Trunc256};
|
|
use std::{
|
|
convert::{TryFrom, TryInto},
|
|
sync::Arc,
|
|
};
|
|
|
|
pub async fn start_server(
|
|
config: config::Config,
|
|
dbs: db::Dbs,
|
|
templates: Templates<'static>,
|
|
opt: cli::MainOpt,
|
|
) {
|
|
let templates = Arc::new(templates);
|
|
let config = Arc::new(config);
|
|
let dbs = Arc::new(dbs);
|
|
|
|
let mut app = tide::new();
|
|
app.at("/static")
|
|
.serve_dir(opt.dir.0.join(static_files::STATIC_DIR))
|
|
.unwrap();
|
|
app.at("/").get({
|
|
let templates = templates.clone();
|
|
let dbs = dbs.clone();
|
|
move |req: tide::Request<()>| serve_index(req, templates.clone(), dbs.clone(), &[], None)
|
|
});
|
|
app.at("/").post({
|
|
let templates = templates.clone();
|
|
let dbs = dbs.clone();
|
|
move |req: tide::Request<()>| handle_post_index(req, templates.clone(), dbs.clone())
|
|
});
|
|
app.at("/ad/:ad").get({
|
|
let templates = templates.clone();
|
|
let dbs = dbs.clone();
|
|
move |req: tide::Request<()>| serve_index(req, templates.clone(), dbs.clone(), &[], None)
|
|
});
|
|
app.at("/admin").get({
|
|
let config = config.clone();
|
|
let templates = templates.clone();
|
|
let dbs = dbs.clone();
|
|
move |req: tide::Request<()>| {
|
|
handle_admin(req, config.clone(), templates.clone(), dbs.clone())
|
|
}
|
|
});
|
|
app.at("/admin").post({
|
|
let config = config.clone();
|
|
move |req: tide::Request<()>| {
|
|
handle_post_admin(req, config.clone(), templates.clone(), dbs.clone())
|
|
}
|
|
});
|
|
app.at("/admin/logout").get(handle_admin_logout);
|
|
app.listen(config.listen).await.unwrap();
|
|
}
|
|
|
|
async fn serve_index<'a>(
|
|
req: tide::Request<()>,
|
|
templates: Arc<Templates<'static>>,
|
|
dbs: Arc<db::Dbs>,
|
|
errors: &[ErrorTemplate<'a>],
|
|
new_ad_form_refill: Option<NewAdQuery>,
|
|
) -> tide::Result<tide::Response> {
|
|
let selected_ad = req.param("ad").ok();
|
|
Ok(tide::Response::builder(200)
|
|
.content_type(tide::http::mime::HTML)
|
|
.body(
|
|
templates
|
|
.hb
|
|
.render(
|
|
"index.html",
|
|
&IndexTemplate {
|
|
lang: "fr",
|
|
errors,
|
|
ads: &to_json(
|
|
dbs.ads
|
|
.iter()
|
|
.filter_map(|x| {
|
|
let (ad_id, ad) = x.ok()?;
|
|
let ad_id = hex::encode(ad_id.as_ref());
|
|
Some(AdWithId {
|
|
ad: bincode::deserialize::<Ad>(&ad).ok()?,
|
|
selected: selected_ad.map_or(false, |i| i == ad_id),
|
|
id: ad_id,
|
|
})
|
|
})
|
|
.collect::<Vec<AdWithId>>(),
|
|
),
|
|
new_ad_form_refill,
|
|
},
|
|
)
|
|
.unwrap_or_else(|e| e.to_string()),
|
|
)
|
|
.build())
|
|
}
|
|
|
|
async fn serve_admin<'a>(
|
|
req: tide::Request<()>,
|
|
templates: Arc<Templates<'static>>,
|
|
dbs: Arc<db::Dbs>,
|
|
errors: &[ErrorTemplate<'a>],
|
|
) -> tide::Result<tide::Response> {
|
|
let selected_ad = req.param("ad").ok();
|
|
Ok(tide::Response::builder(200)
|
|
.content_type(tide::http::mime::HTML)
|
|
.body(
|
|
templates
|
|
.hb
|
|
.render(
|
|
"admin.html",
|
|
&AdminTemplate {
|
|
lang: "fr",
|
|
errors,
|
|
ads: &to_json(
|
|
dbs.ads
|
|
.iter()
|
|
.filter_map(|x| {
|
|
let (ad_id, ad) = x.ok()?;
|
|
let ad_id = hex::encode(ad_id.as_ref());
|
|
Some(AdWithId {
|
|
ad: bincode::deserialize::<Ad>(&ad).ok()?,
|
|
selected: selected_ad.map_or(false, |i| i == ad_id),
|
|
id: ad_id,
|
|
})
|
|
})
|
|
.collect::<Vec<AdWithId>>(),
|
|
),
|
|
},
|
|
)
|
|
.unwrap_or_else(|e| e.to_string()),
|
|
)
|
|
.build())
|
|
}
|
|
|
|
async fn serve_admin_login<'a>(
|
|
_req: tide::Request<()>,
|
|
templates: Arc<Templates<'static>>,
|
|
errors: &[ErrorTemplate<'a>],
|
|
) -> tide::Result<tide::Response> {
|
|
Ok(tide::Response::builder(200)
|
|
.content_type(tide::http::mime::HTML)
|
|
.body(
|
|
templates
|
|
.hb
|
|
.render(
|
|
"admin_login.html",
|
|
&AdminLoginTemplate { lang: "fr", errors },
|
|
)
|
|
.unwrap_or_else(|e| e.to_string()),
|
|
)
|
|
.build())
|
|
}
|
|
|
|
async fn handle_post_index(
|
|
mut req: tide::Request<()>,
|
|
templates: Arc<Templates<'static>>,
|
|
dbs: Arc<db::Dbs>,
|
|
) -> tide::Result<tide::Response> {
|
|
match req.body_form::<Query>().await? {
|
|
Query::NewAdQuery(query) => handle_new_ad(req, templates.clone(), dbs.clone(), query).await,
|
|
Query::RmAdQuery(query) => handle_rm_ad(req, templates.clone(), dbs.clone(), query).await,
|
|
}
|
|
}
|
|
|
|
async fn handle_new_ad(
|
|
req: tide::Request<()>,
|
|
templates: Arc<Templates<'static>>,
|
|
dbs: Arc<db::Dbs>,
|
|
query: NewAdQuery,
|
|
) -> tide::Result<tide::Response> {
|
|
let mut hasher = Sha512Trunc256::new();
|
|
hasher.update(&query.psw);
|
|
dbs.ads
|
|
.insert(
|
|
AdId::random(),
|
|
bincode::serialize(&Ad {
|
|
pubkey: if query.pubkey.is_empty() {
|
|
None
|
|
} else {
|
|
Some(match format_pubkey(&query.pubkey) {
|
|
Ok(pubkey) => pubkey,
|
|
Err(e) => return serve_index(
|
|
req,
|
|
templates,
|
|
dbs,
|
|
&[ErrorTemplate {
|
|
text: match e {
|
|
PubkeyDecodeError::BadChecksum => {
|
|
"La somme de contrôle de la clé publique est incorrecte."
|
|
}
|
|
PubkeyDecodeError::BadFormat => {
|
|
"Le format de la clé publique est incorrect."
|
|
}
|
|
},
|
|
}],
|
|
Some(query),
|
|
)
|
|
.await,
|
|
})
|
|
},
|
|
author: query.author,
|
|
password: hasher.finalize()[..].try_into().unwrap(),
|
|
price: query.price,
|
|
quantity: query.quantity,
|
|
time: 0,
|
|
title: query.title,
|
|
})
|
|
.unwrap(),
|
|
)
|
|
.unwrap();
|
|
dbs.ads.flush().unwrap();
|
|
Ok(tide::Redirect::new("/").into())
|
|
}
|
|
|
|
async fn handle_rm_ad(
|
|
req: tide::Request<()>,
|
|
templates: Arc<Templates<'static>>,
|
|
dbs: Arc<db::Dbs>,
|
|
query: RmAdQuery,
|
|
) -> tide::Result<tide::Response> {
|
|
let mut hasher = Sha512Trunc256::new();
|
|
hasher.update(query.psw);
|
|
let password: PasswordHash = hasher.finalize()[..].try_into().unwrap();
|
|
/*query
|
|
.ads
|
|
.into_iter()
|
|
.filter_map(|x| Some(AdId::try_from(hex::decode(x).ok()?.as_ref()).ok()?))
|
|
.for_each(|ad_id| {
|
|
if let Some(raw) = dbs.ads.get(&ad_id).unwrap() {
|
|
if let Ok(ad) = bincode::deserialize::<Ad>(&raw) {
|
|
if ad.password == password {
|
|
dbs.ads.remove(&ad_id).unwrap();
|
|
}
|
|
}
|
|
}
|
|
});*/
|
|
if let Ok(ad_id) = hex::decode(query.ad) {
|
|
if let Ok(ad_id) = AdId::try_from(ad_id.as_ref()) {
|
|
if let Some(raw) = dbs.ads.get(&ad_id).unwrap() {
|
|
if let Ok(ad) = bincode::deserialize::<Ad>(&raw) {
|
|
if ad.password == password {
|
|
dbs.ads.remove(&ad_id).unwrap();
|
|
|
|
dbs.ads.flush().unwrap();
|
|
} else {
|
|
return serve_index(
|
|
req,
|
|
templates,
|
|
dbs,
|
|
&[ErrorTemplate {
|
|
text: "Le mot de passe de l'annonce est incorrect.",
|
|
}],
|
|
None,
|
|
)
|
|
.await;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(tide::Redirect::new("/").into())
|
|
}
|
|
|
|
async fn handle_admin(
|
|
req: tide::Request<()>,
|
|
config: Arc<config::Config>,
|
|
templates: Arc<Templates<'static>>,
|
|
dbs: Arc<db::Dbs>,
|
|
) -> tide::Result<tide::Response> {
|
|
if let Some(psw) = req.cookie("admin") {
|
|
if config.admin_passwords.contains(&String::from(psw.value())) {
|
|
serve_admin(req, templates, dbs, &[]).await
|
|
} else {
|
|
serve_admin_login(
|
|
req,
|
|
templates,
|
|
&[ErrorTemplate {
|
|
text: "Mot de passe administrateur invalide",
|
|
}],
|
|
)
|
|
.await
|
|
}
|
|
} else {
|
|
serve_admin_login(req, templates, &[]).await
|
|
}
|
|
}
|
|
|
|
async fn handle_post_admin(
|
|
mut req: tide::Request<()>,
|
|
config: Arc<config::Config>,
|
|
templates: Arc<Templates<'static>>,
|
|
dbs: Arc<db::Dbs>,
|
|
) -> tide::Result<tide::Response> {
|
|
if let Some(psw) = req.cookie("admin") {
|
|
if config.admin_passwords.contains(&String::from(psw.value())) {
|
|
match req.body_form::<AdminQuery>().await? {
|
|
AdminQuery::RmAdQuery(query) => {
|
|
if let Ok(ad_id) = hex::decode(query.ad) {
|
|
if let Ok(ad_id) = AdId::try_from(ad_id.as_ref()) {
|
|
dbs.ads.remove(&ad_id).unwrap();
|
|
|
|
dbs.ads.flush().unwrap();
|
|
}
|
|
}
|
|
Ok(tide::Redirect::new("/admin").into())
|
|
}
|
|
_ => serve_admin(req, templates, dbs, &[]).await,
|
|
}
|
|
} else {
|
|
serve_admin_login(
|
|
req,
|
|
templates,
|
|
&[ErrorTemplate {
|
|
text: "Mot de passe administrateur invalide",
|
|
}],
|
|
)
|
|
.await
|
|
}
|
|
} else if let AdminQuery::LoginQuery(query) = req.body_form::<AdminQuery>().await? {
|
|
if config.admin_passwords.contains(&query.psw) {
|
|
serve_admin(req, templates, dbs, &[]).await.map(|mut r| {
|
|
let mut cookie = tide::http::Cookie::new("admin", query.psw);
|
|
cookie.set_http_only(Some(true));
|
|
cookie.set_path("/");
|
|
r.insert_cookie(cookie);
|
|
r
|
|
})
|
|
} else {
|
|
serve_admin_login(
|
|
req,
|
|
templates,
|
|
&[ErrorTemplate {
|
|
text: "Mot de passe administrateur invalide",
|
|
}],
|
|
)
|
|
.await
|
|
}
|
|
} else {
|
|
serve_admin_login(req, templates, &[]).await
|
|
}
|
|
}
|
|
|
|
async fn handle_admin_logout(req: tide::Request<()>) -> tide::Result<tide::Response> {
|
|
let mut r: tide::Response = tide::Redirect::new("/").into();
|
|
if let Some(mut cookie) = req.cookie("admin") {
|
|
cookie.set_path("/");
|
|
r.remove_cookie(cookie);
|
|
}
|
|
Ok(r)
|
|
}
|