Code1 now only submits within the correct time window

This commit is contained in:
2026-10-13 22:59:05 -05:00
parent 8775601f49
commit 1ec94767f0
3 changed files with 39 additions and 4 deletions
+5 -1
View File
@@ -10,6 +10,8 @@ crate-type = ["cdylib", "rlib"]
leptos = { version = "0.8.0" } leptos = { version = "0.8.0" }
leptos_router = { version = "0.8.0" } leptos_router = { version = "0.8.0" }
axum = { version = "0.8.0", optional = true } axum = { version = "0.8.0", optional = true }
chrono = { version = "0.4", default-features = false, features = ["clock"], optional = true }
chrono-tz = { version = "0.10", optional = true }
console_error_panic_hook = { version = "0.1", optional = true } console_error_panic_hook = { version = "0.1", optional = true }
dotenvy = { version = "0.15", optional = true } dotenvy = { version = "0.15", optional = true }
leptos_axum = { version = "0.8.0", optional = true } leptos_axum = { version = "0.8.0", optional = true }
@@ -28,6 +30,8 @@ hydrate = [
] ]
ssr = [ ssr = [
"dep:axum", "dep:axum",
"dep:chrono",
"dep:chrono-tz",
"dep:dotenvy", "dep:dotenvy",
"dep:tokio", "dep:tokio",
"dep:leptos_axum", "dep:leptos_axum",
@@ -66,7 +70,7 @@ style-file = "style/main.scss"
assets-dir = "public" assets-dir = "public"
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup. # The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
site-addr = "127.0.0.1:3000" site-addr = "0.0.0.0:3000"
# The port to use for automatic reload monitoring # The port to use for automatic reload monitoring
reload-port = 3001 reload-port = 3001
+7 -2
View File
@@ -71,7 +71,12 @@ step when ready.
The robot submits code 1 with `POST /event/buzz` and a JSON body containing The robot submits code 1 with `POST /event/buzz` and a JSON body containing
`delay_ms` (a non-negative integer) and `secret` (the value of `CODE1_SECRET`). `delay_ms` (a non-negative integer) and `secret` (the value of `CODE1_SECRET`).
The server subtracts the target delay of 6430 ms from `delay_ms` to calculate The server subtracts the target delay of 6430 ms from `delay_ms` to calculate
the signed buzz delta. the signed buzz delta. Deltas outside the inclusive range -500 to +500 ms are
logged and ignored; the endpoint returns HTTP `200` and does not record the
submission or send/log the submission actions. Accepted submissions return
HTTP `202`. Correctly timed buzzes are only accepted between 11:00 AM and
1:30 PM, inclusive, in the `America/Chicago` timezone. Requests outside that
window are logged and return HTTP `200` without running submission actions.
Set `CODE1_SECRET` to a unique random secret of at least 32 bytes in Set `CODE1_SECRET` to a unique random secret of at least 32 bytes in
`.env`. For example, with the server running locally: `.env`. For example, with the server running locally:
@@ -167,7 +172,7 @@ Set the following environment variables (updating for your project as needed):
export LEPTOS_OUTPUT_NAME="code_submission" export LEPTOS_OUTPUT_NAME="code_submission"
export LEPTOS_SITE_ROOT="site" export LEPTOS_SITE_ROOT="site"
export LEPTOS_SITE_PKG_DIR="pkg" export LEPTOS_SITE_PKG_DIR="pkg"
export LEPTOS_SITE_ADDR="127.0.0.1:3000" export LEPTOS_SITE_ADDR="0.0.0.0:3000"
export LEPTOS_RELOAD_PORT="3001" export LEPTOS_RELOAD_PORT="3001"
``` ```
Finally, run the server binary. Finally, run the server binary.
+27 -1
View File
@@ -1,9 +1,13 @@
use axum::{extract::ConnectInfo, http::StatusCode, Json}; use axum::{extract::ConnectInfo, http::StatusCode, Json};
use chrono::Timelike;
use serde_json::Value; use serde_json::Value;
use std::net::SocketAddr; use std::net::SocketAddr;
pub const ID: &str = "code1"; pub const ID: &str = "code1";
const TARGET_DELAY_MS: i64 = 6430; const TARGET_DELAY_MS: i64 = 6430;
const MAX_BUZZ_DELTA_MS: i64 = 500;
const ACCEPTANCE_START_SECONDS: u32 = 11 * 60 * 60;
const ACCEPTANCE_END_SECONDS: u32 = 13 * 60 * 60 + 30 * 60;
const SELF_NOTIFICATION: &str = "Code 1 has been submitted while the server is live."; const SELF_NOTIFICATION: &str = "Code 1 has been submitted while the server is live.";
const CHALLENGE_1_FIRST: &str = "SECDED-13\nPARITY MSB...LSB"; const CHALLENGE_1_FIRST: &str = "SECDED-13\nPARITY MSB...LSB";
const CHALLENGE_1_SECOND: &str = "0x144A const CHALLENGE_1_SECOND: &str = "0x144A
@@ -77,10 +81,32 @@ pub async fn buzz_event_handler(
)); ));
} }
let chicago_now = chrono::Utc::now().with_timezone(&chrono_tz::America::Chicago);
let seconds_since_midnight = chicago_now.num_seconds_from_midnight();
let after_start = seconds_since_midnight >= ACCEPTANCE_START_SECONDS;
let before_or_at_end = seconds_since_midnight < ACCEPTANCE_END_SECONDS
|| (seconds_since_midnight == ACCEPTANCE_END_SECONDS && chicago_now.nanosecond() == 0);
if !after_start || !before_or_at_end {
leptos::logging::log!(
"Code 1 buzz rejected outside acceptance window: local_time={}, source={}",
chicago_now.format("%Y-%m-%d %H:%M:%S %Z"),
address.ip()
);
return Ok(StatusCode::OK);
}
let delta_ms = delay_ms - TARGET_DELAY_MS;
if delta_ms.abs() > MAX_BUZZ_DELTA_MS {
leptos::logging::log!(
"Code 1 buzz rejected: delay_ms={delay_ms}, delta_ms={delta_ms}, source={}",
address.ip()
);
return Ok(StatusCode::OK);
}
let live = crate::manage::server_live_state(); let live = crate::manage::server_live_state();
crate::codes::history::record_successful_submission(address.ip(), live, ID) crate::codes::history::record_successful_submission(address.ip(), live, ID)
.map_err(|error| (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()))?; .map_err(|error| (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()))?;
let delta_ms = delay_ms - TARGET_DELAY_MS;
on_submit(live, delta_ms).await.map_err(|error| { on_submit(live, delta_ms).await.map_err(|error| {
leptos::logging::log!("Code 1 buzz event failed: {error}"); leptos::logging::log!("Code 1 buzz event failed: {error}");
( (