diff --git a/data/www/admin.html b/data/www/admin/details.html
similarity index 100%
rename from data/www/admin.html
rename to data/www/admin/details.html
diff --git a/data/www/admin/index.html b/data/www/admin/index.html
new file mode 100644
index 0000000..5292743
--- /dev/null
+++ b/data/www/admin/index.html
@@ -0,0 +1,220 @@
+
+
+
+
+
+
+
+
+
+ {{title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bootstrap
+
+
+
+
+
+
+
+
+
+
+
+ Toggle theme
+
+
+
+
+
+
+
+ Light
+
+
+
+
+
+
+
+
+
+
+ Dark
+
+
+
+
+
+
+
+
+
+
+ Auto
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{title}} Admin Interface
+
+ You have reached the {{title}} Admin Interface. This site can be used by
+ the host of the challenge to see the challenge progress, solution, and
+ hints for that challenge. This site is NOT part of the
+ challenge.
+
+
+
+
+
+
Challenge {{ challenge_idx}} — {{ challenge_title }}
+
{{ challenge_description }}
+
+
Hints
+
+ Show hints
+
+
+
+ {% for hint in challenge_hints %}
+
+
+
+
+
+ {{hint}}
+
+
+ {% endfor %}
+
+
+
+
+
Solution
+
+ Show solution
+
+
+
+
+
+
+ {{challenge_solution}}
+
+
+
+
+
+
+
+
+
+
Contestants
+
+ There are cuttently {{ contestants_amount }} contestants.
+ These contestants currently have had at least one connection to
+ the challenge:
+
+
+
+
+
+
Winners
+
+ There are cuttently {{ winners_amount }} winners. These contestants currently have been sent the secret:
+
+
+
+
+
+
+ Created by {{ author }} © {{year}}
+
+
+
+
+
+
+
diff --git a/data/www/details.html b/data/www/details.html
new file mode 100644
index 0000000..7c45c16
--- /dev/null
+++ b/data/www/details.html
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+ {{title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bootstrap
+
+
+
+
+
+
+
+
+
+
+
+ Toggle theme
+
+
+
+
+
+
+
+ Light
+
+
+
+
+
+
+
+
+
+
+ Dark
+
+
+
+
+
+
+
+
+
+
+ Auto
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{title}} Admin Interface
+
+ You have reached the {{title}} Admin Interface. This site can be used by
+ the host of the challenge to see the challenge progress, solution, and
+ hints for that challenge. This site is NOT part of the
+ challenge.
+
+
+
+
+
+
Challenge {{ challenge_idx}} — {{ challenge_title }}
+
{{ challenge_description }}
+
+
Hints
+
+ Show hints
+
+
+
+ {% for hint in challenge_hints %}
+
+
+
+
+
+ {{hint}}
+
+
+ {% endfor %}
+
+
+
+
+
Solution
+
+ Show solution
+
+
+
+
+
+
+ {{challenge_solution}}
+
+
+
+
+
+
+
+
+
+
Contestants
+
+ There are cuttently {{ contestants_amount }} contestants.
+ These contestants currently have had at least one connection to
+ the challenge:
+
+
+
+
+
+
Winners
+
+ There are cuttently {{ winners_amount }} winners. These contestants currently have been sent the
+ secret:
+
+
+
+
+
+
+ Created by {{ author }} © {{year}}
+
+
+
+
+
+
+
diff --git a/data/www/index.html b/data/www/index.html
new file mode 100644
index 0000000..7c45c16
--- /dev/null
+++ b/data/www/index.html
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+ {{title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bootstrap
+
+
+
+
+
+
+
+
+
+
+
+ Toggle theme
+
+
+
+
+
+
+
+ Light
+
+
+
+
+
+
+
+
+
+
+ Dark
+
+
+
+
+
+
+
+
+
+
+ Auto
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{title}} Admin Interface
+
+ You have reached the {{title}} Admin Interface. This site can be used by
+ the host of the challenge to see the challenge progress, solution, and
+ hints for that challenge. This site is NOT part of the
+ challenge.
+
+
+
+
+
+
Challenge {{ challenge_idx}} — {{ challenge_title }}
+
{{ challenge_description }}
+
+
Hints
+
+ Show hints
+
+
+
+ {% for hint in challenge_hints %}
+
+
+
+
+
+ {{hint}}
+
+
+ {% endfor %}
+
+
+
+
+
Solution
+
+ Show solution
+
+
+
+
+
+
+ {{challenge_solution}}
+
+
+
+
+
+
+
+
+
+
Contestants
+
+ There are cuttently {{ contestants_amount }} contestants.
+ These contestants currently have had at least one connection to
+ the challenge:
+
+
+
+
+
+
Winners
+
+ There are cuttently {{ winners_amount }} winners. These contestants currently have been sent the
+ secret:
+
+
+
+
+
+
+ Created by {{ author }} © {{year}}
+
+
+
+
+
+
+
diff --git a/src/meta/admin.rs b/src/meta/admin.rs
index f8b6a21..5badfe5 100644
--- a/src/meta/admin.rs
+++ b/src/meta/admin.rs
@@ -8,17 +8,27 @@ use warp::reply::Reply;
use warp::reply::Response;
use warp::Filter;
+use crate::challenge::ChallengeDesc;
+use crate::vault::VaultRef;
+
use super::errors::TemplateError;
use super::Service;
+fn with_serv(
+ serv: Arc,
+) -> impl Filter,), Error = std::convert::Infallible> + Clone {
+ warp::any().map(move || serv.clone())
+}
+
impl<'tp> Service<'tp> {
pub fn admin_routes(
this: Arc,
) -> impl Filter + Clone + 'tp {
let serv = this.clone();
- warp::path::end()
- .map(move || serv.clone())
- .and_then(overview)
+ warp::path!("admin" / "challenge" / usize)
+ .map(move |id: usize| serv.challenges[id + 1].clone())
+ .and(with_serv(this.clone()))
+ .and_then(details)
.with(warp::trace(|info| {
// Create a span using tracing macros
tracing::info_span!(
@@ -27,33 +37,33 @@ impl<'tp> Service<'tp> {
path = %info.path(),
)
}))
+ .or(warp::path!("admin").and(with_serv(this.clone()).and_then(index)))
}
}
-async fn overview(serv: Arc>) -> Result, warp::Rejection> {
- let challenge = serv.challenges[0].clone();
- let contestants = serv
- .vault
- .contestants()
- .await
- .into_iter()
- .collect::>();
- let winners = serv.vault.winners().await.into_iter().collect::>();
+async fn details(
+ data: (ChallengeDesc, VaultRef),
+ serv: Arc>,
+) -> Result, warp::Rejection> {
+ let challenge = data.0;
+ let vault = data.1;
+ let contestants = vault.contestants().await.into_iter().collect::>();
+ let winners = vault.winners().await.into_iter().collect::>();
let r = Response::new(
serv.env
- .get_template("index")
+ .get_template("admin:index")
.map_err(TemplateError::from)?
.render(context!(
title => "Wooly-Vault",
author => env!("CARGO_PKG_AUTHORS"),
year => "2024",
- challenge_idx => serv.config.challenge,
+ challenge_idx => challenge.id(),
challenge_title => challenge.title(),
challenge_description => challenge.description(),
challenge_hints => challenge.hints(),
challenge_solution => challenge.solution(),
- contestants => serv.vault.contestants().await.iter().collect::>(),
- winners => serv.vault.winners().await.iter().collect::>(),
+ contestants => vault.contestants().await.iter().collect::>(),
+ winners => vault.winners().await.iter().collect::>(),
contestants => contestants,
winners => winners,
contestants_amount => contestants.len(),
@@ -65,3 +75,8 @@ async fn overview(serv: Arc>) -> Result, warp::
Ok(Box::new(r))
}
+
+async fn index(serv: Arc>) -> Result, warp::Rejection> {
+ let r = Response::new("todo".into());
+ Ok(Box::new(r))
+}
diff --git a/src/meta/mod.rs b/src/meta/mod.rs
index 69f00c3..97e5c83 100644
--- a/src/meta/mod.rs
+++ b/src/meta/mod.rs
@@ -18,6 +18,7 @@ use self::errors::handle_rejection;
pub mod admin;
pub mod errors;
+pub mod user;
#[derive(Clone)]
pub struct Service<'tp> {
@@ -28,7 +29,16 @@ pub struct Service<'tp> {
impl<'tp> Service<'tp> {
fn build(config: Config, challenges: Vec<(ChallengeDesc, VaultRef)>) -> Result> {
let mut env = Environment::new();
- env.add_template("index", include_str!("../../data/www/admin.html"))?;
+ env.add_template(
+ "admin:index",
+ include_str!("../../data/www/admin/index.html"),
+ )?;
+ env.add_template(
+ "admin:details",
+ include_str!("../../data/www/admin/details.html"),
+ )?;
+ env.add_template("index", include_str!("../../data/www/index.html"))?;
+ env.add_template("details", include_str!("../../data/www/details.html"))?;
Ok(Self {
config,
env,
@@ -43,6 +53,7 @@ pub async fn serve(challenges: Vec<(ChallengeDesc, VaultRef)>, config: Config) -
let routes = Service::admin_routes(service.clone())
.or(Service::ressources_routes())
+ .or(Service::user_routes(service.clone()))
.recover(handle_rejection)
.with(warp::trace(|info| {
// Create a span using tracing macros
diff --git a/src/meta/user.rs b/src/meta/user.rs
new file mode 100644
index 0000000..19143b4
--- /dev/null
+++ b/src/meta/user.rs
@@ -0,0 +1,82 @@
+use std::sync::Arc;
+
+use anyhow::Result;
+use libpt::log::tracing;
+use minijinja::context;
+use warp::reject::Rejection;
+use warp::reply::Reply;
+use warp::reply::Response;
+use warp::Filter;
+
+use crate::challenge::ChallengeDesc;
+use crate::vault::VaultRef;
+
+use super::errors::TemplateError;
+use super::Service;
+
+fn with_serv(
+ serv: Arc,
+) -> impl Filter,), Error = std::convert::Infallible> + Clone {
+ warp::any().map(move || serv.clone())
+}
+
+impl<'tp> Service<'tp> {
+ pub fn user_routes(
+ this: Arc,
+ ) -> impl Filter + Clone + 'tp {
+ let serv = this.clone();
+ warp::path!("challenge" / usize)
+ .map(move |id: usize| serv.challenges[id + 1].clone())
+ .and(with_serv(this.clone()))
+ .and_then(details)
+ .with(warp::trace(|info| {
+ // Create a span using tracing macros
+ tracing::info_span!(
+ "admin",
+ method = %info.method(),
+ path = %info.path(),
+ )
+ }))
+ .or(warp::path::end().and(with_serv(this.clone()).and_then(index)))
+ }
+}
+
+async fn details(
+ data: (ChallengeDesc, VaultRef),
+ serv: Arc>,
+) -> Result, warp::Rejection> {
+ let challenge = data.0;
+ let vault = data.1;
+ let contestants = vault.contestants().await.into_iter().collect::>();
+ let winners = vault.winners().await.into_iter().collect::>();
+ let r = Response::new(
+ serv.env
+ .get_template("index")
+ .map_err(TemplateError::from)?
+ .render(context!(
+ title => "Wooly-Vault",
+ author => env!("CARGO_PKG_AUTHORS"),
+ year => "2024",
+ challenge_idx => challenge.id(),
+ challenge_title => challenge.title(),
+ challenge_description => challenge.description(),
+ challenge_hints => challenge.hints(),
+ // challenge_solution => challenge.solution(),
+ contestants => vault.contestants().await.iter().collect::>(),
+ winners => vault.winners().await.iter().collect::>(),
+ contestants => contestants,
+ winners => winners,
+ contestants_amount => contestants.len(),
+ winners_amount => winners.len(),
+ ))
+ .map_err(TemplateError::from)?
+ .into(),
+ );
+
+ Ok(Box::new(r))
+}
+
+async fn index(serv: Arc>) -> Result, warp::Rejection> {
+ let r = Response::new("todo".into());
+ Ok(Box::new(r))
+}