Update
This commit is contained in:
@@ -33,6 +33,6 @@ class AdminsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def submitted_password
|
def submitted_password
|
||||||
params.fetch(:password, "").upcase.gsub(/\s+/, "")
|
params.fetch(:password, "").upcase.split(/[\s\-]+/).reject(&:empty?).join("-")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
celebrate() {
|
||||||
|
alert("congratulations you solved the wowbug challenge 2026")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,5 +7,8 @@ import { application } from "./application"
|
|||||||
import HelloController from "./hello_controller"
|
import HelloController from "./hello_controller"
|
||||||
application.register("hello", HelloController)
|
application.register("hello", HelloController)
|
||||||
|
|
||||||
|
import AdminPanelController from "./admin_panel_controller"
|
||||||
|
application.register("admin-panel", AdminPanelController)
|
||||||
|
|
||||||
import ListingPuzzleController from "./listing_puzzle_controller"
|
import ListingPuzzleController from "./listing_puzzle_controller"
|
||||||
application.register("listing-puzzle", ListingPuzzleController)
|
application.register("listing-puzzle", ListingPuzzleController)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Controller } from "@hotwired/stimulus"
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
|
||||||
const REVIEW_PATH = "/internal/pdi-bundle-7c4f"
|
const REVIEW_PATH = "f4c7-eldnub-idp/lanretni/".split("").reverse().join("")
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = ["hintPanel", "progress", "reviewPath"]
|
static targets = ["hintPanel", "progress", "reviewPath"]
|
||||||
|
|||||||
@@ -25,89 +25,20 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if @unlocked %>
|
<% if @unlocked %>
|
||||||
<section class="grid gap-10 lg:grid-cols-[1.2fr_0.8fr]">
|
<section data-controller="admin-panel" class="mx-auto max-w-2xl rounded-3xl border border-white/10 bg-white/5 p-8 shadow-2xl shadow-black/20">
|
||||||
<div class="rounded-3xl border border-white/10 bg-white/5 p-8 shadow-2xl shadow-black/20">
|
|
||||||
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-emerald-300">Unlocked</p>
|
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-emerald-300">Unlocked</p>
|
||||||
<h2 class="mt-2 text-3xl font-semibold text-white">Admin Panel Unlocked</h2>
|
<h2 class="mt-2 text-3xl font-semibold text-white">Admin Panel Unlocked</h2>
|
||||||
<p class="mt-3 max-w-2xl text-sm leading-6 text-zinc-300">
|
|
||||||
This is a staged interface only. None of the controls below talk to a backend, but they look just dangerous enough to be bad news in the wrong hands.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="mt-8 grid gap-4 md:grid-cols-2">
|
|
||||||
<button class="rounded-2xl border border-rose-400/35 bg-rose-500/10 px-5 py-4 text-left transition hover:bg-rose-500/15">
|
|
||||||
<p class="text-sm font-semibold text-rose-100">Delete stock page</p>
|
|
||||||
<p class="mt-1 text-sm text-rose-200/80">Soft-delete every draft older than 30 days.</p>
|
|
||||||
</button>
|
|
||||||
<button class="rounded-2xl border border-amber-400/35 bg-amber-500/10 px-5 py-4 text-left transition hover:bg-amber-500/15">
|
|
||||||
<p class="text-sm font-semibold text-amber-100">Mark reserved</p>
|
|
||||||
<p class="mt-1 text-sm text-amber-200/80">Hold a vehicle against inbound showroom enquiries.</p>
|
|
||||||
</button>
|
|
||||||
<button class="rounded-2xl border border-sky-400/35 bg-sky-500/10 px-5 py-4 text-left transition hover:bg-sky-500/15">
|
|
||||||
<p class="text-sm font-semibold text-sky-100">Rewrite price cache</p>
|
|
||||||
<p class="mt-1 text-sm text-sky-200/80">Force a fresh estimate against stale market comparables.</p>
|
|
||||||
</button>
|
|
||||||
<button class="rounded-2xl border border-fuchsia-400/35 bg-fuchsia-500/10 px-5 py-4 text-left transition hover:bg-fuchsia-500/15">
|
|
||||||
<p class="text-sm font-semibold text-fuchsia-100">Feature vehicle</p>
|
|
||||||
<p class="mt-1 text-sm text-fuchsia-200/80">Pin a vehicle to the top rail for 24 hours.</p>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-8 rounded-2xl border border-white/10 bg-zinc-950/60 p-5">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<div>
|
|
||||||
<p class="text-sm font-semibold text-white">Volatile flags</p>
|
|
||||||
<p class="mt-1 text-sm text-zinc-400">Pure theater, but tasteful theater.</p>
|
|
||||||
</div>
|
|
||||||
<span class="rounded-full border border-emerald-400/25 bg-emerald-400/10 px-3 py-1 text-xs font-medium text-emerald-200">staging</span>
|
|
||||||
</div>
|
|
||||||
<div class="mt-5 grid gap-4 md:grid-cols-2">
|
|
||||||
<label class="flex items-center justify-between rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-zinc-300">
|
|
||||||
Spotlight stock badges
|
|
||||||
<input type="checkbox" checked disabled class="h-4 w-4 rounded border-zinc-700 bg-zinc-900 text-emerald-400">
|
|
||||||
</label>
|
|
||||||
<label class="flex items-center justify-between rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-zinc-300">
|
|
||||||
Quiet duplicate enquiries
|
|
||||||
<input type="checkbox" checked disabled class="h-4 w-4 rounded border-zinc-700 bg-zinc-900 text-emerald-400">
|
|
||||||
</label>
|
|
||||||
<label class="flex items-center justify-between rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-zinc-300">
|
|
||||||
Auto-hide thin stock pages
|
|
||||||
<input type="checkbox" disabled class="h-4 w-4 rounded border-zinc-700 bg-zinc-900 text-emerald-400">
|
|
||||||
</label>
|
|
||||||
<label class="flex items-center justify-between rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-zinc-300">
|
|
||||||
Chaos mode pricing
|
|
||||||
<input type="checkbox" disabled class="h-4 w-4 rounded border-zinc-700 bg-zinc-900 text-emerald-400">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<aside class="space-y-5">
|
|
||||||
<div class="rounded-3xl border border-white/10 bg-white/5 p-6">
|
|
||||||
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-400">Recent Actions</p>
|
|
||||||
<div class="mt-4 space-y-4 text-sm text-zinc-300">
|
|
||||||
<div class="rounded-2xl border border-white/10 bg-zinc-950/50 p-4">
|
|
||||||
<p class="font-medium text-white">Valuation cache sweep</p>
|
|
||||||
<p class="mt-1 text-zinc-400">Ran 18 minutes ago by `ops-preview`.</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-2xl border border-white/10 bg-zinc-950/50 p-4">
|
|
||||||
<p class="font-medium text-white">Manual stock review</p>
|
|
||||||
<p class="mt-1 text-zinc-400">Awaiting sign-off from the prep team.</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-2xl border border-white/10 bg-zinc-950/50 p-4">
|
|
||||||
<p class="font-medium text-white">Homepage merchandising slot 02</p>
|
|
||||||
<p class="mt-1 text-zinc-400">Pinned until 2026-04-29 09:00 UTC.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="rounded-3xl border border-white/10 bg-white/5 p-6">
|
|
||||||
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-zinc-400">Session</p>
|
|
||||||
<p class="mt-3 text-sm leading-6 text-zinc-300">
|
<p class="mt-3 text-sm leading-6 text-zinc-300">
|
||||||
This local unlock is backed only by the browser session.
|
One final button. Press it if you want the ending.
|
||||||
</p>
|
</p>
|
||||||
<%= button_to "Clear admin session", admin_path, method: :delete, class: "mt-5 inline-flex items-center rounded-full border border-white/15 px-4 py-2 text-sm font-medium text-zinc-200 transition hover:border-white/30 hover:text-white" %>
|
|
||||||
</div>
|
<button
|
||||||
</aside>
|
type="button"
|
||||||
|
data-action="admin-panel#celebrate"
|
||||||
|
class="mt-8 inline-flex items-center rounded-2xl bg-rose-600 px-6 py-3 text-sm font-semibold text-white transition hover:bg-rose-500"
|
||||||
|
>
|
||||||
|
Delete database
|
||||||
|
</button>
|
||||||
</section>
|
</section>
|
||||||
<% else %>
|
<% else %>
|
||||||
<section class="mx-auto max-w-2xl rounded-3xl border border-white/10 bg-white/5 p-8 shadow-2xl shadow-black/20">
|
<section class="mx-auto max-w-2xl rounded-3xl border border-white/10 bg-white/5 p-8 shadow-2xl shadow-black/20">
|
||||||
|
|||||||
@@ -66,4 +66,5 @@ This file is for the puzzle owner only and should not be linked from the UI.
|
|||||||
- `GET /internal/pdi-bundle-7c4f` shows the login prompt
|
- `GET /internal/pdi-bundle-7c4f` shows the login prompt
|
||||||
- The login prompt tells solvers to use the words in page order
|
- The login prompt tells solvers to use the words in page order
|
||||||
- Entering `GEAR-AXLE-TURBO-PARK` unlocks the fake admin panel
|
- Entering `GEAR-AXLE-TURBO-PARK` unlocks the fake admin panel
|
||||||
- The panel is session-backed only and can be cleared with the "Clear admin session" button
|
- The unlocked panel shows a single red `Delete database` button
|
||||||
|
- Clicking it triggers the alert: `congratulations you solved the wowbug challenge 2026`
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class MotorlotFlowTest < ActionDispatch::IntegrationTest
|
|||||||
|
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_includes response.body, "Admin Panel Unlocked"
|
assert_includes response.body, "Admin Panel Unlocked"
|
||||||
assert_includes response.body, "Delete stock page"
|
assert_includes response.body, "Delete database"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "admin unlock rejects invalid passwords" do
|
test "admin unlock rejects invalid passwords" do
|
||||||
|
|||||||
Reference in New Issue
Block a user