From 4917fefbeccf7de153ba90d115127a16bbdafa3d Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Fri, 29 Mar 2024 08:59:14 -0700 Subject: [PATCH] Fix bug in default period calc, update readme. --- README.md | 45 +++++++++++++++++++++++++++++++++++---------- src/main.rs | 9 +++++++-- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9856e10..7698843 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,46 @@ SQL checking macros, so your DB needs to have the tables to allow the SQL checks ## How does it work? -If you wish to use this on your webpage, you need to add a couple lines. First, a "tracking pixel" -that registers the current page's view: +You need to register the hit by doing a GET to the `/hit/:page` endpoint, where `:page` is a unique +and persistent identifier for the page; on my blog, I'm using the Zola post slug as the id. This bit +of HTML + JS shows it in action: ``` html - +

There have been no views of this page

+ + ``` -Then, some javascript to retrieve the hit counts: +In this example, the `:page` is "index.html". The `/hit` endpoint registers the hit and then +returns back the latest count of hits. -``` html -help I don't know how to javascript, we need to get http://localhost:5000/hits/all (or 'day' or -'week'), and that will return the number of recorded hits for this page for that time period. -``` +The `index.html` file in this repo has the above code in it; if you serve it like +`python3 -m http.server 3000 & cargo run` +then visit http://localhost:3000 you should see that there is 1 hit, if this is the first time +you're trying it out. Reloading won't increment the count until the hour changes and you visit +again, or you kill and restart Hitman. -It uses the `referer` header to get the page it was called from, and uses that as the key for -counting the hit. +### Privacy? + +The IP from the request is hashed with the date, hour of day, `:page`, and a random 64-bit number +that gets regenerated every time the service is restarted and is never disclosed. This does two +things: + + 1. ensures that hit counts are limited to one per hour per IP per page; + 2. ensures that you can't enumerate all possible hashes from just the page, time, and then just + trying all four billion possible IPs to find the matching hash. + +There is no need to put up a tracking consent form because nothing is being tracked. + +### Security? + +Well, you need to give it a specific origin that is allowed to connect. Is this enough? diff --git a/src/main.rs b/src/main.rs index 5214c93..ddf15d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,7 +67,7 @@ async fn main() { } //-************************************************************************ -// the two route hanlders +// the three route hanlders //-************************************************************************ /// This is the main handler. It counts the hit and returns the latest count. @@ -126,7 +126,10 @@ async fn get_period_hits( let then = now - chrono::Duration::try_days(7).unwrap(); then.to_rfc3339() } - _ => "all".to_string(), + _ => { + let then = now - chrono::Duration::try_days(365_240).unwrap(); // 1000 years + then.to_rfc3339() + } }; let hits = sqlx::query_scalar!( @@ -141,6 +144,8 @@ async fn get_period_hits( format!("{hits}") } +// it's easier to split this into something that handles the request parameters +// and something that does the query async fn get_all_hits(State(db): State, Path(slug): Path) -> String { let hits = all_hits_helper(&db, &slug).await; format!("{hits}")