mnemonic-hash-checker: add HTML form and use GET parameters
This commit is contained in:
parent
257184b2c3
commit
11f7eeb05c
|
@ -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>
|
|
@ -2,8 +2,9 @@ use std::net::SocketAddr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
http::StatusCode,
|
extract::{Query, State},
|
||||||
extract::{Path, State},
|
http::{header::CONTENT_TYPE, StatusCode},
|
||||||
|
response::{AppendHeaders, IntoResponse},
|
||||||
routing::get,
|
routing::get,
|
||||||
Json, Router,
|
Json, Router,
|
||||||
};
|
};
|
||||||
|
@ -15,6 +16,8 @@ use clap::Parser;
|
||||||
use deadpool_postgres::{Config, ManagerConfig, Pool, RecyclingMethod, Runtime};
|
use deadpool_postgres::{Config, ManagerConfig, Pool, RecyclingMethod, Runtime};
|
||||||
use tokio_postgres::NoTls;
|
use tokio_postgres::NoTls;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use tower_http::catch_panic::CatchPanicLayer;
|
use tower_http::catch_panic::CatchPanicLayer;
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
|
|
||||||
|
@ -68,15 +71,20 @@ fn setup_registry() {
|
||||||
.init();
|
.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn index() -> impl IntoResponse {
|
||||||
|
(
|
||||||
|
AppendHeaders([(CONTENT_TYPE, "text/html")]),
|
||||||
|
include_str!("index.html"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(state))]
|
#[tracing::instrument(skip(state))]
|
||||||
async fn check_hash(hash: &str, state: &AppState) -> Result<bool> {
|
async fn check_hash(hash: &str, state: &AppState) -> Result<bool> {
|
||||||
let client = state.pool.get().await?;
|
let client = state.pool.get().await?;
|
||||||
let column = &state.database_column;
|
let column = &state.database_column;
|
||||||
let table = &state.database_table;
|
let table = &state.database_table;
|
||||||
let formatted_query = format!("SELECT {column} FROM {table} WHERE hash = $1");
|
let formatted_query = format!("SELECT {column} FROM {table} WHERE hash = $1");
|
||||||
let query = client
|
let query = client.prepare_cached(formatted_query.as_str()).await?;
|
||||||
.prepare_cached(formatted_query.as_str())
|
|
||||||
.await?;
|
|
||||||
let rows = client.query(&query, &[&hash]).await?;
|
let rows = client.query(&query, &[&hash]).await?;
|
||||||
if let Some(row) = rows.get(0) {
|
if let Some(row) = rows.get(0) {
|
||||||
let retrieved_hash: String = row.try_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.
|
// Note: Exposes *zero* information of potential errors to clients.
|
||||||
#[tracing::instrument(skip(hash, state))]
|
#[tracing::instrument(skip(query, state))]
|
||||||
async fn check_hash_slug(
|
async fn check_hash_slug(
|
||||||
Path(hash): Path<String>,
|
query: Query<CheckQuery>,
|
||||||
State(state): State<Arc<AppState>>,
|
State(state): State<Arc<AppState>>,
|
||||||
) -> (StatusCode, Json<Option<bool>>) {
|
) -> (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() {
|
let status_code = match result.as_ref() {
|
||||||
Ok(true) => StatusCode::OK,
|
Ok(true) => StatusCode::OK,
|
||||||
Ok(false) => StatusCode::NOT_FOUND,
|
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());
|
.unwrap_or_else(|| (std::net::Ipv4Addr::new(127, 0, 0, 1), 8000).into());
|
||||||
|
|
||||||
let app = Router::new()
|
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 {
|
.with_state(Arc::new(AppState {
|
||||||
pool,
|
pool,
|
||||||
database_table: cli_config.database_table,
|
database_table: cli_config.database_table,
|
||||||
|
|
Loading…
Reference in New Issue