14 KiB
14 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 18-web-dashboard | 03 | execute | 2 |
|
|
false |
|
|
Purpose: Completes the user-facing web dashboard and makes it accessible via the CLI. Output: Full dashboard with all pages + cmd/serve.go wiring.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/18-web-dashboard/18-CONTEXT.md @.planning/phases/18-web-dashboard/18-01-SUMMARY.md @.planning/phases/18-web-dashboard/18-02-SUMMARY.md ```go // pkg/web/server.go type Config struct { DB *storage.DB EncKey []byte Providers *providers.Registry Dorks *dorks.Registry ReconEngine *recon.Engine Port int AuthUser string AuthPass string AuthToken string } type Server struct { router chi.Router; cfg Config; tmpl *template.Template; sse *SSEHub } func NewServer(cfg Config) (*Server, error) func (s *Server) ListenAndServe() error func (s *Server) Router() chi.Router ```// pkg/web/embed.go
var staticFiles embed.FS // //go:embed static/*
var templateFiles embed.FS // //go:embed templates/*
// pkg/web/auth.go
func AuthMiddleware(user, pass, token string) func(http.Handler) http.Handler
// pkg/web/api.go
func (s *Server) mountAPI(r chi.Router) // mounts /api/v1/*
func writeJSON(w http.ResponseWriter, status int, v interface{})
// pkg/web/sse.go
type SSEHub struct { ... }
func NewSSEHub() *SSEHub
func (h *SSEHub) Broadcast(evt SSEEvent)
type SSEEvent struct { Type string; Data interface{} }
var servePort int
var serveTelegram bool
var serveCmd = &cobra.Command{ Use: "serve", ... }
// Currently only starts Telegram bot — needs HTTP server wiring
func openDBWithKey() (*storage.DB, []byte, error) // returns DB + encryption key
-
providers.html — extends layout (WEB-06):
- Stats summary bar: total count, per-category counts in badges
- Provider table: Name, Category, Confidence, Keywords count, Has Verify
- Filter by category via htmx dropdown
- Click provider name -> expand row with details (patterns, verify endpoint) via
hx-get="/api/v1/providers/{name}" hx-target="#detail-{name}"
-
scan.html — extends layout (WEB-03):
- Form: Path input, verify checkbox, workers number input
- "Start Scan" button:
hx-post="/api/v1/scan"with JSON body, shows progress section - Progress section (hidden until scan starts): connects to SSE via inline script:
const es = new EventSource('/api/v1/scan/progress');es.addEventListener('scan:finding', (e) => { /* append row */ });es.addEventListener('scan:complete', (e) => { es.close(); }); - Results table: populated live via SSE events
-
recon.html — extends layout (WEB-05):
- Source checkboxes: populated from
recon.Engine.List(), grouped by category - Query input, stealth toggle, respect-robots toggle
- "Sweep" button:
hx-post="/api/v1/recon"triggers sweep - Live results via SSE (same pattern as scan.html with recon event types)
- Results displayed as cards showing provider, masked key, source
- Source checkboxes: populated from
-
dorks.html — extends layout (WEB-07):
- Dork list table: ID, Source, Category, Query (truncated), Description
- Filter by source dropdown
- "Add Dork" form: source, category, query, description fields.
hx-post="/api/v1/dorks"to create. - Stats bar: total dorks, per-source counts
-
settings.html — extends layout (WEB-08):
- Config form populated from viper settings (rendered server-side)
- Key fields: database path, encryption, telegram token (masked), default workers, verify timeout
- "Save" button:
hx-put="/api/v1/config"with form data as JSON - Success/error toast notification via htmx
hx-swap-oob
-
Update handlers.go — add page handlers:
handleKeys(w, r)— render keys.html with initial data (first 50 findings, provider list for filter dropdown)handleKeyReveal(w, r)— GET /keys/{id}/reveal — returns unmasked key value as HTML fragment (for htmx swap)handleProviders(w, r)— render providers.html with provider list + statshandleScan(w, r)— render scan.htmlhandleRecon(w, r)— render recon.html with source listhandleDorks(w, r)— render dorks.html with dork list + statshandleSettings(w, r)— render settings.html with current config
-
Update server.go — register new routes in the router:
GET /keys-> handleKeysGET /keys/{id}/reveal-> handleKeyRevealGET /providers-> handleProvidersGET /scan-> handleScanGET /recon-> handleReconGET /dorks-> handleDorksGET /settings-> handleSettings
-
Create handlers_test.go:
- Test each page handler returns 200 with expected content
- Test keys page contains "keys-table" div
- Test providers page lists provider names
- Test key reveal returns unmasked value cd /home/salva/Documents/apikey && go test ./pkg/web/... -v -count=1 All 6 page templates render correctly, htmx attributes are present for interactive features, SSE JavaScript is embedded in scan and recon pages, page handlers serve data from real packages, all tests pass
srv, err := web.NewServer(web.Config{
DB: db,
EncKey: encKey,
Providers: reg,
Dorks: dorkReg,
ReconEngine: reconEng,
Port: servePort,
AuthUser: viper.GetString("web.auth_user"),
AuthPass: viper.GetString("web.auth_pass"),
AuthToken: viper.GetString("web.auth_token"),
})
```
- Start HTTP server in a goroutine:
go srv.ListenAndServe() - Keep existing Telegram bot start logic (conditioned on --telegram flag)
- Update the port message:
fmt.Printf("KeyHunter dashboard running at http://localhost:%d\n", servePort) - The existing
<-ctx.Done()already handles graceful shutdown
-
Add serve flags:
--no-webflag (default false) to disable web dashboard (for telegram-only mode)--auth-user,--auth-pass,--auth-tokenflags bound to viperweb.auth_user,web.auth_pass,web.auth_token
-
Ensure the DB is opened unconditionally (it currently only opens when --telegram is set):
- Move
openDBWithKey()call before the telegram conditional - Both web server and telegram bot share the same DB instance
cd /home/salva/Documents/apikey && go build -o /dev/null ./cmd/... && echo "build OK"
keyhunter servestarts HTTP server on port 8080 with full dashboard, --telegram additionally starts bot, --port changes listen port, --auth-user/pass/token enable auth,go build ./cmd/...succeeds
- Move
<success_criteria>
- All 7 HTML pages render with proper layout and navigation
- Keys page supports filtering, reveal, copy, delete via htmx
- Scan and recon pages show live progress via SSE
- Providers page shows 108+ providers with stats
- Settings page reads/writes config
- cmd/serve.go starts HTTP server + optional Telegram bot
- Auth middleware protects dashboard when credentials configured </success_criteria>