This commit is contained in:
Pascal Engélibert 2020-11-06 15:23:17 +01:00
parent fb2d18f879
commit 70ceb146bf
8 changed files with 190 additions and 3 deletions

1
Cargo.lock generated
View File

@ -434,6 +434,7 @@ dependencies = [
"sled",
"structopt",
"tokio",
"urlencoding",
"warp",
]

View File

@ -16,4 +16,5 @@ sha2 = "0.9.1"
sled = "0.34.4"
structopt = "0.3.20"
tokio = { version = "0.2.22", features = ["macros", "rt-threaded"] }
urlencoding = "1.1.1"
warp = "0.2.5"

View File

@ -9,6 +9,7 @@ use std::{
sync::{Arc, RwLock},
};
use warp::Filter;
use warp::Reply;
type PasswordHash = [u8; 32];
@ -56,10 +57,12 @@ pub async fn start_server(
.collect::<Vec<AdWithId>>(),
)));
let config = Arc::new(config);
let dbs = Arc::new(dbs);
let handle_index = {
let cache_ads = cache_ads.clone();
let templates = templates.clone();
move |errors: &[ErrorTemplate]| {
warp::reply::html(
templates
@ -77,6 +80,32 @@ pub async fn start_server(
}
};
let handle_admin_login = {
let templates = templates.clone();
move |errors: &[ErrorTemplate]| {
warp::reply::html(
templates
.hb
.render(
"admin_login.html",
&AdminLoginTemplate { lang: "fr", errors },
)
.unwrap_or_else(|e| e.to_string()),
)
}
};
let handle_admin = {
move |errors: &[ErrorTemplate]| {
warp::reply::html(
templates
.hb
.render("admin.html", &AdminTemplate { lang: "fr", errors })
.unwrap_or_else(|e| e.to_string()),
)
}
};
let route_static = warp::path("static")
.and(warp::get())
.and(warp::fs::dir(opt.dir.0.join(static_files::STATIC_DIR)));
@ -184,7 +213,57 @@ pub async fn start_server(
),
));
warp::serve(route_static.or(route_index))
let route_admin = warp::path("admin").and(
warp::path::end()
.and(
warp::cookie("admin")
.map({
let handle_admin = handle_admin.clone();
let handle_admin_login = handle_admin_login.clone();
let config = config.clone();
move |psw: String| {
if !config.admin_passwords.contains(&psw) {
handle_admin_login(&[ErrorTemplate {
text: "Mot de passe administrateur invalide",
}])
} else {
handle_admin(&[])
}
}
})
.or(warp::path::end().map({
let handle_admin_login = handle_admin_login.clone();
move || handle_admin_login(&[])
})),
)
.or(warp::path("login").and(warp::path::end()).and(
warp::post()
.and(warp::get().map(move || handle_admin(&[])))
.or(warp::body::form::<AdminLoginQuery>().map({
let config = config.clone();
move |query: AdminLoginQuery| {
if config.admin_passwords.contains(&query.psw) {
warp::reply::with_header(
warp::redirect(warp::http::Uri::from_static("/admin")),
"Set-Cookie",
format!("admin={}; HttpOnly", urlencoding::encode(&query.psw)),
)
.into_response()
} else {
handle_admin_login(&[ErrorTemplate {
text: "Mot de passe administrateur invalide",
}])
.into_response()
}
}
})),
))
.or(warp::path("logout")
.and(warp::path::end())
.map(|| warp::redirect(warp::http::Uri::from_static("/")))),
);
warp::serve(route_static.or(route_index).or(route_admin))
.run(config.listen)
.await;
}
@ -196,6 +275,18 @@ struct IndexTemplate<'a> {
ads: &'a Json,
}
#[derive(Serialize)]
struct AdminLoginTemplate<'a> {
lang: &'a str,
errors: &'a [ErrorTemplate<'a>],
}
#[derive(Serialize)]
struct AdminTemplate<'a> {
lang: &'a str,
errors: &'a [ErrorTemplate<'a>],
}
#[derive(Serialize)]
struct ErrorTemplate<'a> {
text: &'a str,
@ -217,6 +308,11 @@ struct RmAdQuery {
psw: String,
}
#[derive(Clone, Debug, Deserialize)]
struct AdminLoginQuery {
psw: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(tag = "a")]
enum Query {

View File

@ -2,8 +2,14 @@ use handlebars::Handlebars;
use std::path::Path;
const TEMPLATES_DIR: &'static str = "templates";
static TEMPLATE_FILES: &'static [(&str, &str)] =
&[("index.html", include_str!("../templates/index.html"))];
static TEMPLATE_FILES: &'static [(&str, &str)] = &[
("index.html", include_str!("../templates/index.html")),
("admin.html", include_str!("../templates/admin.html")),
(
"admin_login.html",
include_str!("../templates/admin_login.html"),
),
];
pub struct Templates<'reg> {
pub hb: Handlebars<'reg>,

View File

@ -31,6 +31,7 @@ h1, h2, h3, h4 {
}
#errors {
margin-bottom: 1em;
padding: 4px;
border: 2px dashed rgba(128, 0, 0, 0.2);
border-radius: 3px;

36
templates/admin.html Normal file
View File

@ -0,0 +1,36 @@
<!doctype html>
<html lang="{{lang}}">
<head>
<meta charset="utf-8"/>
<title>Administration | ĞMarché</title>
<link rel="stylesheet" href="/static/style1.css"/>
<link rel="shortcut icon" href="/static/icon.png"/>
</head>
<body>
<div class="center">
<a href="/"><img id="banner" alt="ĞMarché" src="/static/banner.jpg"/></a>
<h1>Administration &#8211; ĞMarché</h1>
{{#if errors}}
<div id="errors">
<span>Oups, il y a un problème&nbsp;:</span>
<ul>
{{#each errors}}
<li>{{this.text}}</li>
{{/each}}
</ul>
</div>
{{/if}}
<hr style="clear: both;"/>
<p><a href="https://forum.duniter.org">Toutes les questions techniques ont leur place sur le forum.</a></p>
<p><a href="https://git.p2p.legal/tuxmain/gmarche-rs">Code source</a> sous licence <a href="https://www.gnu.org/licenses/licenses.html#AGPL">GNU AGPL v3</a>. &#129408; Écrit en <a href="https://www.rust-lang.org">Rust</a>. Images de Attilax.<br/>
CopyLeft 2020 Pascal Engélibert</p>
<p><a href="/">Accueil</a></p> &#8211; <a href="/admin/logout">Verrouiller</a>
</div>
</body>
</html>

View File

@ -0,0 +1,44 @@
<!doctype html>
<html lang="{{lang}}">
<head>
<meta charset="utf-8"/>
<title>Administration | ĞMarché</title>
<link rel="stylesheet" href="/static/style1.css"/>
<link rel="shortcut icon" href="/static/icon.png"/>
</head>
<body>
<div class="center">
<a href="/"><img id="banner" alt="ĞMarché" src="/static/banner.jpg"/></a>
<h1>Administration &#8211; ĞMarché</h1>
<h2>Authentification</h2>
{{#if errors}}
<div id="errors">
<span>Oups, il y a un problème&nbsp;:</span>
<ul>
{{#each errors}}
<li>{{this.text}}</li>
{{/each}}
</ul>
</div>
{{/if}}
<form action="/admin/login" method="post">
<label for="f_psw">Mot de passe&nbsp;:</label>
<input type="password" id="f_psw" name="psw"/>
<input type="submit" value="S'authentifier"/>
</form>
<hr style="clear: both;"/>
<p><a href="https://forum.duniter.org">Toutes les questions techniques ont leur place sur le forum.</a></p>
<p><a href="https://git.p2p.legal/tuxmain/gmarche-rs">Code source</a> sous licence <a href="https://www.gnu.org/licenses/licenses.html#AGPL">GNU AGPL v3</a>. &#129408; Écrit en <a href="https://www.rust-lang.org">Rust</a>. Images de Attilax.<br/>
CopyLeft 2020 Pascal Engélibert</p>
<p><a href="/">Accueil</a></p>
</div>
</body>
</html>

View File

@ -85,6 +85,8 @@
<p><a href="https://git.p2p.legal/tuxmain/gmarche-rs">Code source</a> sous licence <a href="https://www.gnu.org/licenses/licenses.html#AGPL">GNU AGPL v3</a>. &#129408; Écrit en <a href="https://www.rust-lang.org">Rust</a>. Images de Attilax.<br/>
CopyLeft 2020 Pascal Engélibert</p>
<p><a href="/admin">Administration</a></p>
</div>
</body>
</html>