Files
2026-04-06 17:36:53 +03:00

12 KiB

<<<<<<< HEAD phase: 17-telegram-scheduler plan: 03 type: execute wave: 2 depends_on: ["17-01", "17-02"] files_modified: - pkg/bot/handlers.go - pkg/bot/handlers_test.go autonomous: true requirements: [TELE-02, TELE-03, TELE-04, TELE-06] must_haves: truths: - "/scan triggers engine.Scan and returns masked findings via Telegram" - "/verify verifies a specific key and returns result" - "/recon runs recon sweep and returns findings" - "/status shows uptime, total findings, last scan, active jobs" - "/stats shows findings by provider, top 10, last 24h count" - "/providers lists loaded provider count and names" - "/help shows all available commands with descriptions" - "/key sends full unmasked key detail to requesting user only" artifacts: - path: "pkg/bot/handlers.go" provides: "All command handler implementations" min_lines: 200 - path: "pkg/bot/handlers_test.go" provides: "Unit tests for handler logic" key_links: - from: "pkg/bot/handlers.go" to: "pkg/engine" via: "engine.Scan for /scan command" pattern: "eng\.Scan" - from: "pkg/bot/handlers.go" to: "pkg/recon" via: "reconEngine.SweepAll for /recon command" pattern: "SweepAll" - from: "pkg/bot/handlers.go" to: "pkg/storage" via: "db.GetFinding for /key command" pattern: "db\.GetFinding" Implement all Telegram bot command handlers: /scan, /verify, /recon, /status, /stats, /providers, /help, /key. Replace the stubs created in Plan 17-01.

Purpose: Makes the bot functional for all TELE-02..06 requirements. Users can control KeyHunter entirely from Telegram. Output: pkg/bot/handlers.go with full implementations, pkg/bot/handlers_test.go.

<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/phases/17-telegram-scheduler/17-CONTEXT.md @.planning/phases/17-telegram-scheduler/17-01-SUMMARY.md @.planning/phases/17-telegram-scheduler/17-02-SUMMARY.md @pkg/engine/engine.go @pkg/recon/engine.go @pkg/storage/db.go @pkg/storage/queries.go @pkg/storage/findings.go From pkg/bot/bot.go (created in 17-01): ```go type Config struct { Token string AllowedChats []int64 DB *storage.DB ScanEngine *engine.Engine ReconEngine *recon.Engine ProviderRegistry *providers.Registry EncKey []byte } type Bot struct { cfg Config; bot *telego.Bot; ... } func (b *Bot) reply(chatID int64, text string) error func (b *Bot) replyPlain(chatID int64, text string) error ```

From pkg/storage/queries.go:

func (db *DB) GetFinding(id int64, encKey []byte) (*Finding, error)
func (db *DB) ListFindingsFiltered(encKey []byte, f Filters) ([]Finding, error)

From pkg/engine/engine.go:

func (e *Engine) Scan(ctx context.Context, src sources.Source, cfg ScanConfig) (<-chan Finding, error)

From pkg/recon/engine.go:

func (e *Engine) SweepAll(ctx context.Context, cfg Config) ([]Finding, error)
Task 1: Implement /scan, /verify, /recon command handlers pkg/bot/handlers.go Create pkg/bot/handlers.go (replace stubs from bot.go). All handlers are methods on *Bot.

*handleScan(bot telego.Bot, msg telego.Message):

  • Parse path from message text: /scan /path/to/dir (whitespace split, second arg)
  • If no path provided, reply with usage: "/scan "
  • Check rate limit (60s cooldown)
  • Reply "Scanning {path}..." immediately
  • Create sources.FileSource for the path
  • Run b.cfg.ScanEngine.Scan(ctx, src, engine.ScanConfig{Workers: runtime.NumCPU()*4})
  • Collect findings from channel
  • Format response: "Found {N} potential keys:\n" + each finding as "- {provider}: {masked_key} ({confidence})" (max 20 per message, truncate with "...and N more")
  • If 0 findings: "No API keys found in {path}"
  • Always use masked keys — never send raw values

*handleVerify(bot telego.Bot, msg telego.Message):

  • Parse key ID from message: /verify <id> (parse int64)
  • If no ID, reply usage: "/verify "
  • Check rate limit (60s cooldown)
  • Look up finding via b.cfg.DB.GetFinding(id, b.cfg.EncKey)
  • If not found, reply "Key #{id} not found"
  • Run verify.NewHTTPVerifier(10s).Verify against the finding using provider spec from registry
  • Reply with: "Key #{id} ({provider}):\nStatus: {verified|invalid|error}\nHTTP: {code}\n{metadata if any}"

*handleRecon(bot telego.Bot, msg telego.Message):

  • Parse query from message: /recon <query> (everything after /recon)
  • If no query, reply usage: "/recon "
  • Check rate limit (60s cooldown)
  • Reply "Running recon for '{query}'..."
  • Run b.cfg.ReconEngine.SweepAll(ctx, recon.Config{Query: query})
  • Format response: "Found {N} results:\n" + each as "- [{source}] {url} ({snippet})" (max 15 per message)
  • If 0 results: "No results found for '{query}'"

All handlers: Wrap in goroutine so the update loop is not blocked. Use context.WithTimeout(ctx, 5*time.Minute) to prevent runaway scans. cd /home/salva/Documents/apikey && go build ./pkg/bot/... /scan, /verify, /recon handlers compile and call correct engine methods.

Task 2: Implement /status, /stats, /providers, /help, /key handlers and tests pkg/bot/handlers.go, pkg/bot/handlers_test.go Add to pkg/bot/handlers.go:

*handleStatus(bot telego.Bot, msg telego.Message):

  • Query DB for total findings count: SELECT COUNT(*) FROM findings
  • Query last scan time: SELECT MAX(finished_at) FROM scans
  • Query active scheduled jobs: SELECT COUNT(*) FROM scheduled_jobs WHERE enabled=1
  • Bot uptime: track start time in Bot struct, compute duration
  • Reply: "Status:\n- Findings: {N}\n- Last scan: {time}\n- Active jobs: {N}\n- Uptime: {duration}"

*handleStats(bot telego.Bot, msg telego.Message):

  • Query findings by provider: SELECT provider_name, COUNT(*) as cnt FROM findings GROUP BY provider_name ORDER BY cnt DESC LIMIT 10
  • Query findings last 24h: SELECT COUNT(*) FROM findings WHERE created_at > datetime('now', '-1 day')
  • Reply: "Stats:\n- Top providers:\n 1. {provider}: {count}\n ...\n- Last 24h: {count} findings"

*handleProviders(bot telego.Bot, msg telego.Message):

  • Get provider list from b.cfg.ProviderRegistry.List()
  • Reply: "Loaded {N} providers:\n{comma-separated list}" (truncate if >4096 chars Telegram message limit)

*handleHelp(bot telego.Bot, msg telego.Message):

  • Static response listing all commands: "/scan - Scan files for API keys\n/verify - Verify a specific key\n/recon - Run OSINT recon\n/status - Show system status\n/stats - Show finding statistics\n/providers - List loaded providers\n/key - Show full key detail (DM only)\n/subscribe - Enable auto-notifications\n/unsubscribe - Disable auto-notifications\n/help - Show this help"

*handleKey(bot telego.Bot, msg telego.Message):

  • Parse key ID from /key <id>
  • If no ID, reply usage
  • Check message is from private chat (msg.Chat.Type == "private"). If group chat, reply "This command is only available in private chat for security"
  • Look up finding via db.GetFinding(id, encKey) — this returns UNMASKED key
  • Reply with full detail: "Key #{id}\nProvider: {provider}\nKey: {full_key_value}\nSource: {source_path}:{line}\nConfidence: {confidence}\nVerified: {yes/no}\nFound: {created_at}"
  • This is the ONLY handler that sends unmasked keys

Tests in pkg/bot/handlers_test.go:

  • TestHandleHelp_ReturnsAllCommands: Verify help text contains all command names
  • TestHandleKey_RejectsGroupChat: Verify /key in group chat returns security message
  • TestFormatFindings_TruncatesAt20: Create 30 mock findings, verify formatted output has 20 entries + "...and 10 more"
  • TestFormatStats_EmptyDB: Verify stats handler works with no findings

For tests, create a helper that builds a Bot with :memory: DB and nil engines (for handlers that only query DB). cd /home/salva/Documents/apikey && go test ./pkg/bot/... -v -count=1 All 8 command handlers implemented. /key restricted to private chat. Tests pass for help, key security, truncation, empty stats.

- `go build ./pkg/bot/...` compiles - `go test ./pkg/bot/... -v` passes all tests - All 8 commands have implementations (no stubs remain)

<success_criteria>

  • /scan triggers engine scan and returns masked findings
  • /verify looks up and verifies a key
  • /recon runs SweepAll
  • /status, /stats, /providers, /help return informational responses
  • /key sends unmasked detail only in private chat
  • All output masks keys except /key in DM </success_criteria>
After completion, create `.planning/phases/17-telegram-scheduler/17-03-SUMMARY.md` ======= phase: "17" plan: "03" type: implementation autonomous: true wave: 1 depends_on: [] requirements: [TELE-01, TELE-02, TELE-03, TELE-04, TELE-06] ---

Phase 17 Plan 03: Bot Command Handlers

Objective

Implement Telegram bot command handlers for /scan, /verify, /recon, /status, /stats, /providers, /help, and /key commands. The bot package wraps existing CLI functionality (scan engine, verifier, recon engine, storage queries, provider registry) and exposes it through Telegram message handlers using the telego library.

Context

  • @pkg/engine/engine.go — scan engine with Scan() method
  • @pkg/verify/verifier.go — HTTPVerifier with Verify/VerifyAll
  • @pkg/recon/engine.go — recon Engine with SweepAll
  • @pkg/storage/queries.go — DB queries (ListFindingsFiltered, GetFinding)
  • @cmd/scan.go — CLI scan flow (source selection, verification, persistence)
  • @cmd/recon.go — CLI recon flow (buildReconEngine, SweepAll, persist)
  • @cmd/keys.go — CLI keys management (list, show, verify)
  • @cmd/providers.go — Provider listing and stats

Tasks

Task 1: Add telego dependency and create bot package with handler registry

type="auto"

Create pkg/bot/ package with:

  • bot.go: Bot struct wrapping telego.Bot, holding references to engine, verifier, recon engine, storage, providers registry, and encryption key
  • handlers.go: Handler registration mapping commands to handler functions
  • Add github.com/mymmrac/telego dependency

Done when: pkg/bot/bot.go compiles, Bot struct has all required dependencies injected

Task 2: Implement all eight command handlers

type="auto"

Implement handlers in pkg/bot/handlers.go:

  • /help — list available commands with descriptions
  • /scan <path> — trigger scan on path, return findings (masked only, never unmasked in Telegram)
  • /verify <id> — verify a finding by ID, return status
  • /recon [--sources=x,y] — run recon sweep, return summary
  • /status — show bot status (uptime, last scan time, DB stats)
  • /stats — show provider/finding statistics
  • /providers — list loaded providers
  • /key <id> — show full key detail (private chat only, with unmasked key)

Security: /key must only work in private chats, never in groups. All other commands use masked keys only.

Done when: All eight handlers compile and handle errors gracefully

Task 3: Unit tests for command handlers

type="auto"

Write tests in pkg/bot/handlers_test.go verifying:

  • /help returns all command descriptions
  • /scan with missing path returns usage error
  • /key refuses to work in group chats
  • /providers returns provider count
  • /stats returns stats summary

Done when: go test ./pkg/bot/... passes

Verification

go build ./...
go test ./pkg/bot/... -v

Success Criteria

  • All eight command handlers implemented in pkg/bot/handlers.go
  • Bot struct accepts all required dependencies via constructor
  • /key command enforced private-chat-only
  • All commands use masked keys except /key in private chat
  • Tests pass

worktree-agent-a39573e4