add: option_source_password and option_view_password

This commit is contained in:
trisua 2025-07-25 20:26:22 -04:00
parent a49efdd238
commit 2de840f50d
5 changed files with 158 additions and 13 deletions

View file

@ -6,7 +6,7 @@ use crate::{
};
use axum::{
Extension, Json, Router,
extract::Path,
extract::{Path, Query},
http::{HeaderMap, HeaderValue},
response::{Html, IntoResponse},
routing::{get, get_service, post},
@ -119,9 +119,16 @@ async fn view_doc_request(
return Html(tera.render("doc.lisp", &ctx).unwrap());
}
#[derive(Deserialize)]
pub struct ViewQuery {
#[serde(default)]
pub key: String,
}
async fn view_request(
Extension(data): Extension<State>,
Path(slug): Path<String>,
Query(props): Query<ViewQuery>,
) -> impl IntoResponse {
let (ref data, ref tera, ref build_code) = *data.read().await;
let entry = match data
@ -163,6 +170,15 @@ async fn view_request(
return Html(tera.render("error.lisp", &ctx).unwrap());
}
// ...
if !metadata.option_view_password.is_empty()
&& metadata.option_view_password != props.key.clone()
{
let mut ctx = default_context(&data, &build_code);
ctx.insert("entry", &entry);
return Html(tera.render("password.lisp", &ctx).unwrap());
}
// pull views
let views = if !metadata.option_disable_views {
match data
@ -207,6 +223,7 @@ async fn view_request(
ctx.insert("metadata", &metadata);
ctx.insert("metadata_head", &metadata.head_tags());
ctx.insert("metadata_css", &metadata.css());
ctx.insert("password", &props.key);
Html(tera.render("view.lisp", &ctx).unwrap())
}
@ -214,6 +231,7 @@ async fn view_request(
async fn editor_request(
Extension(data): Extension<State>,
Path(slug): Path<String>,
Query(props): Query<ViewQuery>,
) -> impl IntoResponse {
let (ref data, ref tera, ref build_code) = *data.read().await;
let entry = match data
@ -238,9 +256,34 @@ async fn editor_request(
}
};
let metadata: EntryMetadata = match toml::from_str(&EntryMetadata::ini_to_toml(&entry.metadata))
{
Ok(x) => x,
Err(e) => {
let mut ctx = default_context(&data, &build_code);
ctx.insert("error", &e.to_string());
return Html(tera.render("error.lisp", &ctx).unwrap());
}
};
// ...
if if !metadata.option_source_password.is_empty() {
metadata.option_source_password != props.key
} else if !metadata.option_view_password.is_empty() {
metadata.option_view_password != props.key
} else {
false
} {
let mut ctx = default_context(&data, &build_code);
ctx.insert("entry", &entry);
return Html(tera.render("password.lisp", &ctx).unwrap());
}
// ...
let mut ctx = default_context(&data, &build_code);
ctx.insert("entry", &entry);
ctx.insert("password", &props.key);
Html(tera.render("edit.lisp", &ctx).unwrap())
}
@ -311,6 +354,35 @@ fn default_random() -> String {
salt()
}
fn hash_passwords(metadata: &mut EntryMetadata) -> (bool, String) {
// hash passwords
let do_update_metadata = (!metadata.option_view_password.is_empty()
|| !metadata.option_source_password.is_empty())
&& (!metadata.option_view_password.starts_with("h:")
|| !metadata.option_source_password.starts_with("h:"));
if !metadata.option_view_password.is_empty() && !metadata.option_view_password.starts_with("h:")
{
metadata.option_view_password =
format!("h:{}", hash(metadata.option_view_password.clone()));
}
if !metadata.option_source_password.is_empty()
&& !metadata.option_source_password.starts_with("h:")
{
metadata.option_source_password =
format!("h:{}", hash(metadata.option_source_password.clone()));
}
if do_update_metadata {
if let Ok(x) = toml::to_string_pretty(&metadata) {
return (true, x);
};
}
(false, String::new())
}
/// The time that must be waited between each entry creation.
const CREATE_WAIT_TIME: usize = 5000;
@ -318,7 +390,7 @@ async fn create_request(
jar: CookieJar,
headers: HeaderMap,
Extension(data): Extension<State>,
Json(req): Json<CreateEntry>,
Json(mut req): Json<CreateEntry>,
) -> std::result::Result<impl IntoResponse, Json<ApiReturn<()>>> {
let (ref data, _, _) = *data.read().await;
@ -382,15 +454,21 @@ async fn create_request(
}
// check metadata
let metadata: EntryMetadata = match toml::from_str(&EntryMetadata::ini_to_toml(&req.metadata)) {
Ok(x) => x,
Err(e) => return Err(Json(Error::MiscError(e.to_string()).into())),
};
let mut metadata: EntryMetadata =
match toml::from_str(&EntryMetadata::ini_to_toml(&req.metadata)) {
Ok(x) => x,
Err(e) => return Err(Json(Error::MiscError(e.to_string()).into())),
};
if let Err(e) = metadata.validate() {
return Err(Json(Error::MiscError(e.to_string()).into()));
}
let (do_update_metadata, updated) = hash_passwords(&mut metadata);
if do_update_metadata {
req.metadata = updated;
}
// check for existing
if data
.query(&SimplifiedQuery {
@ -471,7 +549,7 @@ async fn edit_request(
headers: HeaderMap,
Extension(data): Extension<State>,
Path(slug): Path<String>,
Json(req): Json<EditEntry>,
Json(mut req): Json<EditEntry>,
) -> impl IntoResponse {
let (ref data, _, _) = *data.read().await;
@ -500,15 +578,21 @@ async fn edit_request(
}
// check metadata
let metadata: EntryMetadata = match toml::from_str(&EntryMetadata::ini_to_toml(&req.metadata)) {
Ok(x) => x,
Err(e) => return Json(Error::MiscError(e.to_string()).into()),
};
let mut metadata: EntryMetadata =
match toml::from_str(&EntryMetadata::ini_to_toml(&req.metadata)) {
Ok(x) => x,
Err(e) => return Json(Error::MiscError(e.to_string()).into()),
};
if let Err(e) = metadata.validate() {
return Json(Error::MiscError(e.to_string()).into());
}
let (do_update_metadata, updated) = hash_passwords(&mut metadata);
if do_update_metadata {
req.metadata = updated;
}
// ...
let (id, mut entry) = match data
.query(&SimplifiedQuery {