mnemonic-hash-checker: add HTML form and use GET parameters

This commit is contained in:
Ryan Heywood 2023-08-05 22:37:13 -05:00
parent 257184b2c3
commit 11f7eeb05c
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
2 changed files with 64 additions and 9 deletions

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>Milk Sad Lookup</title>
<style type="text/css" media="screen">
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px 10px;
}
input {
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<h1>MilkSad Lookup Service</h1>
<p>
Input a SHA256 hash of your mnemonic phrase. <b>DO NOT ENTER</b> your
mnemonic phrase in cleartext.
</p>
<form action="/check" method="get" enctype="multipart/form-data">
<fieldset>
<legend>Lookup</legend>
<div class="row">
<div class="col">
<input type="text" value="" name="sha256" id="sha256" placeholder="put hash here" minlength="64" maxlength="64" required/>
</div>
</div>
<br />
<input type="submit" value="Check For Vulnerability" class="is-full-width" />
</fieldset>
</form>
</div>
</body>
</html>

View File

@ -2,8 +2,9 @@ use std::net::SocketAddr;
use std::sync::Arc;
use axum::{
http::StatusCode,
extract::{Path, State},
extract::{Query, State},
http::{header::CONTENT_TYPE, StatusCode},
response::{AppendHeaders, IntoResponse},
routing::get,
Json, Router,
};
@ -15,6 +16,8 @@ use clap::Parser;
use deadpool_postgres::{Config, ManagerConfig, Pool, RecyclingMethod, Runtime};
use tokio_postgres::NoTls;
use serde::Deserialize;
use tower_http::catch_panic::CatchPanicLayer;
use tower_http::trace::TraceLayer;
@ -68,15 +71,20 @@ fn setup_registry() {
.init();
}
async fn index() -> impl IntoResponse {
(
AppendHeaders([(CONTENT_TYPE, "text/html")]),
include_str!("index.html"),
)
}
#[tracing::instrument(skip(state))]
async fn check_hash(hash: &str, state: &AppState) -> Result<bool> {
let client = state.pool.get().await?;
let column = &state.database_column;
let table = &state.database_table;
let formatted_query = format!("SELECT {column} FROM {table} WHERE hash = $1");
let query = client
.prepare_cached(formatted_query.as_str())
.await?;
let query = client.prepare_cached(formatted_query.as_str()).await?;
let rows = client.query(&query, &[&hash]).await?;
if let Some(row) = rows.get(0) {
let retrieved_hash: String = row.try_get(0)?;
@ -86,13 +94,18 @@ async fn check_hash(hash: &str, state: &AppState) -> Result<bool> {
}
}
#[derive(Deserialize)]
struct CheckQuery {
sha256: String,
}
// Note: Exposes *zero* information of potential errors to clients.
#[tracing::instrument(skip(hash, state))]
#[tracing::instrument(skip(query, state))]
async fn check_hash_slug(
Path(hash): Path<String>,
query: Query<CheckQuery>,
State(state): State<Arc<AppState>>,
) -> (StatusCode, Json<Option<bool>>) {
let result = check_hash(&hash, &state).await;
let result = check_hash(&query.sha256, &state).await;
let status_code = match result.as_ref() {
Ok(true) => StatusCode::OK,
Ok(false) => StatusCode::NOT_FOUND,
@ -125,7 +138,8 @@ async fn main() -> Result<()> {
.unwrap_or_else(|| (std::net::Ipv4Addr::new(127, 0, 0, 1), 8000).into());
let app = Router::new()
.route("/check/:hash", get(check_hash_slug))
.route("/", get(index))
.route("/check", get(check_hash_slug))
.with_state(Arc::new(AppState {
pool,
database_table: cli_config.database_table,