From 1ec94767f0305d8c51f957dd3a94eef7035abd10 Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Tue, 13 Oct 2026 22:59:05 -0500 Subject: [PATCH] Code1 now only submits within the correct time window --- Cargo.toml | 6 +++++- README.md | 9 +++++++-- src/codes/code1.rs | 28 +++++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 18f716a..c1de22b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ crate-type = ["cdylib", "rlib"] leptos = { version = "0.8.0" } leptos_router = { version = "0.8.0" } 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 } dotenvy = { version = "0.15", optional = true } leptos_axum = { version = "0.8.0", optional = true } @@ -28,6 +30,8 @@ hydrate = [ ] ssr = [ "dep:axum", + "dep:chrono", + "dep:chrono-tz", "dep:dotenvy", "dep:tokio", "dep:leptos_axum", @@ -66,7 +70,7 @@ style-file = "style/main.scss" 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. -site-addr = "127.0.0.1:3000" +site-addr = "0.0.0.0:3000" # The port to use for automatic reload monitoring reload-port = 3001 diff --git a/README.md b/README.md index 2402977..346b52f 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,12 @@ step when ready. 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`). 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 `.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_SITE_ROOT="site" 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" ``` Finally, run the server binary. diff --git a/src/codes/code1.rs b/src/codes/code1.rs index d2beb52..f474a10 100644 --- a/src/codes/code1.rs +++ b/src/codes/code1.rs @@ -1,9 +1,13 @@ use axum::{extract::ConnectInfo, http::StatusCode, Json}; +use chrono::Timelike; use serde_json::Value; use std::net::SocketAddr; pub const ID: &str = "code1"; 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 CHALLENGE_1_FIRST: &str = "SECDED-13\nPARITY MSB...LSB"; 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(); crate::codes::history::record_successful_submission(address.ip(), live, ID) .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| { leptos::logging::log!("Code 1 buzz event failed: {error}"); (