Files
keyhunter/.planning/phases/09-osint-infrastructure/09-03-PLAN.md
2026-04-06 00:39:27 +03:00

7.3 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
09-osint-infrastructure 03 execute 1
pkg/recon/stealth.go
pkg/recon/stealth_test.go
pkg/recon/dedup.go
pkg/recon/dedup_test.go
true
RECON-INFRA-06
truths artifacts key_links
Stealth mode exposes a UA pool of 10 realistic browser user-agents (Chrome/Firefox/Safari across Linux/macOS/Windows)
RandomUserAgent returns a UA from the pool, distributed across calls
Dedup drops duplicate Findings keyed by SHA256(provider + masked_key + source)
Dedup preserves first-seen order and metadata
path provides contains
pkg/recon/stealth.go UA pool, RandomUserAgent, StealthHeaders helper var userAgents
path provides contains
pkg/recon/dedup.go Dedup([]Finding) []Finding keyed by sha256(provider|masked|source) func Dedup
from to via pattern
pkg/recon/dedup.go crypto/sha256 finding hash key sha256.Sum256
Implement stealth mode helpers (UA rotation) and cross-source deduplication. Both are small, self-contained, and unblock the parallel sweep orchestrator from producing noisy duplicate findings.

Purpose: Satisfies RECON-INFRA-06 (stealth UA rotation) and provides the dedup primitive that SweepAll callers use to satisfy RECON-INFRA-08's "deduplicates findings before persisting" criterion. Output: pkg/recon/stealth.go, pkg/recon/dedup.go, and their tests

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/phases/09-osint-infrastructure/09-CONTEXT.md @pkg/engine/finding.go Task 1: Stealth UA pool + RandomUserAgent pkg/recon/stealth.go, pkg/recon/stealth_test.go - userAgents is an unexported slice of exactly 10 realistic UA strings covering Chrome/Firefox/Safari on Linux/macOS/Windows - RandomUserAgent() returns a random entry from the pool - StealthHeaders() returns map[string]string{"User-Agent": RandomUserAgent(), "Accept-Language": "en-US,en;q=0.9"} - Tests: TestUAPoolSize (== 10), TestRandomUserAgentInPool (returned value is in pool), TestStealthHeadersHasUA Create pkg/recon/stealth.go with a package-level `userAgents` slice of 10 realistic UAs. Include at least: - Chrome 120 Windows - Chrome 120 macOS - Chrome 120 Linux - Firefox 121 Windows - Firefox 121 macOS - Firefox 121 Linux - Safari 17 macOS - Safari 17 iOS - Edge 120 Windows - Chrome Android
```go
package recon

import "math/rand"

var userAgents = []string{
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 14.2; rv:121.0) Gecko/20100101 Firefox/121.0",
    "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15",
    "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.2210.61",
    "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",
}

// RandomUserAgent returns a random browser user-agent from the pool.
// Used when Config.Stealth is true.
func RandomUserAgent() string {
    return userAgents[rand.Intn(len(userAgents))]
}

// StealthHeaders returns a minimal headers map with rotated UA and Accept-Language.
func StealthHeaders() map[string]string {
    return map[string]string{
        "User-Agent":      RandomUserAgent(),
        "Accept-Language": "en-US,en;q=0.9",
    }
}
```

Create pkg/recon/stealth_test.go with the three tests. TestRandomUserAgentInPool should loop 100 times and assert each result is present in the `userAgents` slice.
cd /home/salva/Documents/apikey && go test ./pkg/recon/ -run 'TestUAPool|TestRandomUserAgent|TestStealthHeaders' -count=1 Tests pass. Pool has exactly 10 UAs. Random selection always within pool. Task 2: Cross-source finding dedup pkg/recon/dedup.go, pkg/recon/dedup_test.go - Dedup(in []Finding) []Finding drops duplicates keyed by sha256(ProviderName + "|" + KeyMasked + "|" + Source) - First-seen wins: returned slice preserves the first occurrence's metadata (SourceType, DetectedAt, etc.) - Order is preserved from the input (stable dedup) - Nil/empty input returns nil - Tests: - TestDedupEmpty: Dedup(nil) == nil - TestDedupNoDuplicates: 3 distinct findings -> 3 returned - TestDedupAllDuplicates: 3 identical findings -> 1 returned - TestDedupPreservesFirstSeen: two findings with same key, different DetectedAt — the first-seen timestamp wins - TestDedupDifferentSource: same provider/masked, different Source URLs -> both kept Create pkg/recon/dedup.go:
```go
package recon

import (
    "crypto/sha256"
    "encoding/hex"
)

// Dedup removes duplicate findings using SHA256(provider|masked|source) as key.
// Stable: preserves input order and first-seen metadata.
func Dedup(in []Finding) []Finding {
    if len(in) == 0 {
        return nil
    }
    seen := make(map[string]struct{}, len(in))
    out := make([]Finding, 0, len(in))
    for _, f := range in {
        h := sha256.Sum256([]byte(f.ProviderName + "|" + f.KeyMasked + "|" + f.Source))
        k := hex.EncodeToString(h[:])
        if _, dup := seen[k]; dup {
            continue
        }
        seen[k] = struct{}{}
        out = append(out, f)
    }
    return out
}
```

Create pkg/recon/dedup_test.go with the five tests. Use testify require.
cd /home/salva/Documents/apikey && go test ./pkg/recon/ -run TestDedup -count=1 All dedup tests pass. First-seen wins. Different Source URLs are kept separate. - `go test ./pkg/recon/ -run 'TestUAPool|TestRandom|TestStealth|TestDedup' -count=1` passes - `go vet ./pkg/recon/...` clean

<success_criteria>

  • Stealth UA pool (10 entries) exported via RandomUserAgent/StealthHeaders
  • Dedup primitive removes duplicates stably by sha256(provider|masked|source) </success_criteria>
After completion, create `.planning/phases/09-osint-infrastructure/09-03-SUMMARY.md`