Award points for flag submissions on auto-validated crackmes (#127) - #180
Award points for flag submissions on auto-validated crackmes (#127)#180xusheng6 wants to merge 3 commits into
Conversation
Starts the point system from issue #127 with the parts everything else depends on: a flag that can be submitted, a solve that gets recorded, and a score to show for it. Authors opt in when uploading. Opting in requires the flag their crackme prints when beaten, plus a private zip of the source and build scripts. The flag is stored as a bcrypt hash and never in cleartext - a leak of every crackme's flag would quietly retire the whole system - so nobody, author or reviewer, can read one back out. That is what the source archive is for: a reviewer rebuilds the crackme, solves it, and tests the flag they derive against the hash from the review page. A crackme whose flag doesn't match is unsolvable for points and should be rejected. The archive lives outside static/ and is only reachable through the reviewer download route. Reviewers assign an official difficulty when approving, which fixes what a solve of that crackme is worth (difficulty x 100) independently of the community rating, which keeps drifting. Crackmes approved before this existed fall back to their rounded community rating. Solves are keyed by the user's immutable id rather than their username, so a rename can't zero out a score, and the score is summed from the solve records rather than counted on the user document, so it can't drift out of step with them. Points are snapshotted onto each solve at the moment it is earned: the scoring rules are explicitly provisional (issue #127 still has first blood on old crackmes, writeup points, bounties and decay to settle), and re-pricing future solves shouldn't silently rewrite everyone's history. Deleting a crackme takes its solves and source archive with it, and deleting a user takes their solves; both show up in the deletion preview. Follow-ups from the issue, deliberately not here: first blood on old crackmes, writeup points, bounties, decay, and six-month retirement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two changes on review feedback. The flag is now stored as-is instead of hashed. Reviewers need to read it: confirming a crackme is really solvable, and fixing a flag the author mistyped, both need the actual value, and a hash left a wrong flag undetectable until users started failing on it. The review page prints the flag directly, which retires the check-flag tool the hash needed. Cleartext means the flag must not leave the reviewer tool, so it is passed to that template and nowhere else; a test asserts the crackme page, listings, profiles, search and RSS never render it, and neither the operation log (mirrored to Discord) nor the author's notification quotes it. The reviewer crackme editor now covers everything, rather than difficulty being settable only while approving a submission - a typo there used to be unfixable once the crackme was live. It edits the flag (setting or clearing one turns auto-validation on or off), the official difficulty, the private source archive, and the metadata, labels and binary it already handled; it works on pending crackmes as well as approved ones, and the review page links to it. Clearing a flag leaves existing solves and their points alone - they were earned fairly. Its language/arch/platform option lists now come from app/services/crackme_fields.py like every other form, instead of a hardcoded copy that could drift from the upload form. Renaming a crackme is deliberately still not here: PR #179 delivers that across the whole site, including this page, and duplicating it would just collide. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Pushed both changes. Flags are now stored in cleartext. The review page prints the flag directly, which retires the check-flag tool the hash needed — reviewers read it, build the crackme, and confirm it's the flag it actually prints. It also means a mistyped flag can be corrected instead of only being detectable once users start failing on it. Since it's cleartext, it must not leave the reviewer tool: it's passed to that template and nowhere else, and a test asserts the crackme page, listings, profiles, search and RSS never render it. The reviewer operation log (which is mirrored to a Discord channel) and the author's change notification both report that the flag changed without quoting it. The reviewer editor now covers every field, instead of difficulty being settable only during approval — where a typo was unfixable once the crackme went live.
It works on pending crackmes as well as approved ones, and the review page links to it. Its language/arch/platform lists now come from One thing deliberately left out: renaming. #179 already delivers crackme renaming across the whole site (including this page, with the cascade to the denormalized copies on comments, writeups and label requests), so building it again here would just collide with it. Happy to fold it in if you'd rather this PR be self-contained. Suite: 282 passed, 8 new tests covering the editor and flag confidentiality. |
Review feedback on the upload experience and the flag format.
A rejected upload no longer costs the user everything they typed. The
form now posts in the background, so an error just prints a message and
leaves the page - including the files they picked, which no server-side
re-render can restore - exactly as it was. Without JS the form posts
normally and the server re-renders it with the submitted values filled
back in, files excepted. A successful upload became a post/redirect/get
to /upload/crackme/submitted, so refreshing the confirmation can't
re-post it.
The flag format is now CMO{...} rather than CM1{...}.
Auto-validation leads with "Optional. This crackme has a unique flag and
can be auto-validated." and is ticked by default, and the labels block
moved to the end of the form - it is long enough that having it in the
middle made everything after it hard to find.
The score panel on a profile drops the (?) marker; the explanation is
still there as a tooltip on the label.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Starts the point system from #127 with the parts everything else depends on: a flag that can be submitted, a solve that gets recorded, and a score to show for it. The rest of the issue is deliberately left for follow-ups.
What's here
Authors opt in at upload time. A new Auto-validation checkbox on the upload form asks for two things:
CM1{...}format (printable ASCII, no spaces or braces, ≤56 chars).static/, is never published or linked, and is only reachable through the reviewer download route.The flag is stored as a bcrypt hash, never in cleartext. A database leak of every crackme's flag would quietly retire the whole point system, so nobody — author, reviewer or admin — can read one back out of the site. That's what the source archive is for: the review page has a Check flag box, so a reviewer rebuilds the crackme, solves it, and tests the flag they derive against the hash. A crackme whose flag doesn't match is unsolvable for points and should be rejected rather than shipped broken. The tested flag is kept out of the reviewer operation log for the same reason.
Reviewers assign an official difficulty when approving. That number fixes what a solve of the crackme is worth (
difficulty × 100), independently of the community difficulty rating, which keeps drifting as people rate it. Crackmes approved before this existed have no official difficulty and fall back to their rounded community rating.Solvers submit the flag from the crackme page. A correct flag records a solve, awards the points and notifies the solver; a wrong one says so. Authors can't submit flags for their own crackmes, re-submitting a correct flag never awards twice, and the route is rate-limited to 20/hour per user so a badly chosen flag still can't be brute-forced.
Profiles show the score in a new panel, with a Solves tab listing what was solved, for how many points, and when.
Design notes
app/services/points.pyso a later change is one edit.Not here (follow-ups from #127)
First blood on old crackmes, points for writeups, author-funded bounties, decay by solve count, and six-month retirement. Retirement in particular is worth landing together with first blood and writeup points — on its own it would just make older crackmes worth nothing.
Testing
tests/test_solves.py(37 new tests) covers flag format and hashing, the scoring formula and its fallback, opt-in upload with and without a valid flag/source, the whole solve flow (correct, wrong, duplicate, own crackme, non-opted-in crackme, anonymous), the crackme and profile rendering, and the reviewer tools (check flag, source download, official difficulty on approval, source cleanup on reject, solve cascade on crackme and user deletion). Full suite: 275 passed.🤖 Generated with Claude Code