store

package
v0.27.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package store persists flow metadata in SQLite and bodies on disk.

Index

Constants

View Source
const (
	EndpointSearchPath    = "path"    // host, path, method (default)
	EndpointSearchHeaders = "headers" // req/res headers JSON
	EndpointSearchBody    = "body"    // req/res body files (bounded scan)
	EndpointSearchAll     = "all"     // path + headers + body
)

Endpoint search scopes for the attack-surface map.

View Source
const (
	FlagIntercepted  int64 = 1 << iota // request passed through the intercept hold queue
	FlagEdited                         // request was edited before forwarding
	FlagDropped                        // request was dropped by the user (not forwarded)
	FlagCaptureError                   // a body could not be captured; forwarding still succeeded
	FlagTLSFailed                      // TLS interception failed for this flow
	FlagWebSocket                      // a protocol-upgrade (WebSocket) handshake, tunneled transparently
	FlagRepeater                       // a request sent from the Repeater module
	FlagIntruder                       // a request sent from the Intruder module
	FlagImported                       // a flow imported from a HAR file (not proxied)
	FlagActiveScan                     // a probe sent by the active scanner
	FlagAI                             // request originated from the AI assistant (over MCP)
	FlagAuthz                          // a request replayed by the authorization (access-control) tester
	FlagDiscovery                      // an endpoint found by the content-discovery (forced-browse) engine
	FlagTLSBypassed                    // CONNECT tunneled raw (no MITM) — host on the TLS-bypass list
)

Flow flag bits, OR'd into Flow.Flags.

Variables

This section is empty.

Functions

func DecodeNotesImagePayload added in v0.8.0

func DecodeNotesImagePayload(mime, b64 string) (string, []byte, error)

DecodeNotesImagePayload decodes a base64 image upload body.

func FlowSortValue added in v0.12.0

func FlowSortValue(fl *Flow, key string) string

FlowSortValue returns the string form of a flow's sort key (for client cursors).

func NormalizeFlowSortKey added in v0.12.0

func NormalizeFlowSortKey(key string) string

NormalizeFlowSortKey returns a whitelisted sort key (default id).

func NormalizeTags added in v0.11.0

func NormalizeTags(tags []string) []string

NormalizeTags cleans, de-duplicates and sorts a tag list, dropping empties and capping the count. Exposed so callers (API/MCP) can normalize before display.

func SanitizeNotesImageMIME added in v0.10.0

func SanitizeNotesImageMIME(mime string) string

SanitizeNotesImageMIME returns mime when it is an allowlisted raster image type, otherwise "application/octet-stream" (served inert — never as HTML, SVG or script). Applied both on insert and on serve, so already-stored rows with a dangerous MIME are also neutralized.

Types

type APIKey

type APIKey struct {
	ID      int64  `json:"id"`
	Label   string `json:"label"`
	Prefix  string `json:"prefix"`
	Created int64  `json:"created"` // unix millis
}

APIKey is metadata for an issued control-API key. The secret token itself is never stored — only its SHA-256 hash and a short identifying prefix.

type Activity added in v0.6.0

type Activity struct {
	ID      int64  `json:"id"`
	TS      int64  `json:"ts"` // unix millis
	Tool    string `json:"tool"`
	Summary string `json:"summary"`
	OK      bool   `json:"ok"`
	Result  string `json:"result"`
	Ms      int64  `json:"ms"`
	Intent  string `json:"intent,omitempty"` // the AI's stated "why" for a consequential action
}

Activity is one recorded AI (MCP) tool call, persisted per-project so the glass-box feed survives restarts.

type BodyWriter

type BodyWriter struct {
	// contains filtered or unexported fields
}

BodyWriter streams bytes to a temp file while hashing them, then commits the file to a content-addressed path on Finalize. Safe for bounded memory: bytes are never buffered whole.

func (*BodyWriter) Abort

func (w *BodyWriter) Abort()

Abort discards an in-progress body (e.g. on error).

func (*BodyWriter) Finalize

func (w *BodyWriter) Finalize() (string, int64, error)

Finalize commits the body and returns its sha256 hex hash and byte length. If a body with the same hash already exists it is deduplicated.

func (*BodyWriter) Write

func (w *BodyWriter) Write(p []byte) (int, error)

Write implements io.Writer.

type Endpoint added in v0.5.0

type Endpoint struct {
	Host        string `json:"host"`
	Method      string `json:"method"`
	Path        string `json:"path"`
	Scheme      string `json:"scheme"`
	LastStatus  int    `json:"lastStatus"` // status of the most recent hit
	Statuses    []int  `json:"statuses"`   // every distinct status seen, sorted
	Hits        int    `json:"hits"`
	LastFlowID  int64  `json:"lastFlowId"`  // most recent flow, for click-through
	ResBodyHash string `json:"resBodyHash"` // SHA-256 of latest response body (empty if none)
	ResLen      int64  `json:"resLen"`      // length of latest response body
	Soft404     bool   `json:"soft404"`     // 2xx/3xx body matches a "not found" content signature
}

Endpoint is a unique (host, method, path) surface aggregated from flows — the building block of the endpoint map. Repeated hits collapse into one row.

type EndpointFilter added in v0.5.0

type EndpointFilter struct {
	Host          string
	Search        string
	SearchScope   string // path, headers, body, all — see EndpointSearch* constants
	ExcludeFlags  int64
	Tag           string // only endpoints with at least one flow carrying this tag
	HideNoiseOnly bool   // drop endpoints that only ever returned 403/404 (forced-browse noise)
}

EndpointFilter narrows which flows are aggregated into endpoints.

type Finding added in v0.10.0

type Finding struct {
	ID        int64          `json:"id"`
	TS        int64          `json:"ts"`        // created, unix millis
	UpdatedTS int64          `json:"updatedTs"` // last modified, unix millis
	Severity  string         `json:"severity"`  // Critical | High | Medium | Low | Info
	Status    string         `json:"status"`    // open | verified | false_positive | wont_fix | fixed
	Source    string         `json:"source"`    // human | ai | scanner
	Title     string         `json:"title"`
	Target    string         `json:"target"`
	Detail    string         `json:"detail"`         // legacy / MCP compat: first text block synced here
	Evidence  string         `json:"evidence"`       // legacy only
	Fix       string         `json:"fix"`            // back-compat: kept but superseded by Impact
	Impact    string         `json:"impact"`         // security impact — what an attacker gains / business consequence
	Cvss      string         `json:"cvss,omitempty"` // CVSS score or vector string, e.g. "7.5" or "CVSS:3.1/AV:N/..."
	Body      string         `json:"body,omitempty"` // stored JSON blocks (use Blocks for rendering)
	Flows     []FindingFlow  `json:"flows"`          // attached flow metadata (for list sidebar count)
	Blocks    []FindingBlock `json:"blocks"`         // ordered narrative body (source of truth for UI)
}

Finding is a curated vulnerability write-up for a project. Unlike a scanner Issue (auto-generated, ephemeral), a Finding is persistent and human/AI-curated: it carries a status the operator manages and has a narrative body — an ordered sequence of text blocks (markdown) and flow-reference blocks (clickable PoC request/response), freely interleaved.

type FindingBlock added in v0.12.0

type FindingBlock struct {
	Type   string `json:"type"`             // "text" or "flow"
	MD     string `json:"md,omitempty"`     // type=="text": markdown content
	FlowID int64  `json:"flowId,omitempty"` // type=="flow": attached flow
	Note   string `json:"note,omitempty"`   // type=="flow": annotation

	// Enriched at read time from the flows JOIN — never stored in the body JSON.
	Method string `json:"method,omitempty"`
	Host   string `json:"host,omitempty"`
	Path   string `json:"path,omitempty"`
	Status int    `json:"status,omitempty"`

	// Missing is set (type=="flow" only) when the referenced flow no longer exists
	// in the flows table — e.g. it was purged via prune_history / GC. The block and
	// its human annotation are preserved; the UI/report surface that the PoC
	// evidence is gone rather than silently rendering an empty flow.
	Missing bool `json:"missing,omitempty"`
}

FindingBlock is one element in a finding's narrative body.

type FindingFlow added in v0.10.0

type FindingFlow struct {
	FlowID int64  `json:"flowId"`
	Ord    int    `json:"ord"`
	Note   string `json:"note,omitempty"`
	Method string `json:"method,omitempty"`
	Host   string `json:"host,omitempty"`
	Path   string `json:"path,omitempty"`
	Status int    `json:"status,omitempty"`

	// Missing is true when the referenced flow row no longer exists in the flows
	// table (purged via prune_history / GC). The attachment row and note survive.
	Missing bool `json:"missing,omitempty"`
}

FindingFlow is one PoC flow attached to a finding, enriched with a compact flow summary for display (the human selects request/responses to record here).

type Flow

type Flow struct {
	ID          int64
	TS          time.Time
	Method      string
	Scheme      string
	Host        string
	Port        int
	Path        string
	HTTPVersion string
	Status      int
	ReqHeaders  map[string][]string
	ResHeaders  map[string][]string
	ReqBodyHash string
	ResBodyHash string
	ReqLen      int64
	ResLen      int64
	Mime        string
	DurationMs  int64
	ClientAddr  string
	Error       string
	Flags       int64
	Note        string   // free-text annotation an operator (or the AI) attaches to the flow
	Tags        []string // labels attached to the flow (manual or AI); loaded on demand, not a flows column
}

Flow is one captured request/response exchange. Bodies are referenced by content hash, never embedded.

type FlowFilter

type FlowFilter struct {
	Limit        int    // max rows (defaults to 200 when <= 0)
	BeforeID     int64  // legacy cursor: id < BeforeID when sorting id DESC
	CursorID     int64  // keyset cursor flow id (0 = first page)
	CursorVal    string // sort value at the cursor row (required for non-id sorts)
	SortKey      string // id|method|host|path|status|size|time|mime
	SortDir      int    // +1 asc, -1 desc; 0 = default for the key
	Method       string // exact method match
	Host         string // case-insensitive substring of host
	Search       string // FTS on host/path/method/note, or exact id when SearchScope=id / #id / id:N
	SearchScope  string // path (default FTS), body (handled in control), id (exact flow id)
	Scheme       string // exact scheme match ("http"/"https")
	StatusClass  int    // 1..5 → 1xx..5xx; 0 = any
	RequireFlags int64  // only rows with any of these flag bits set
	ExcludeFlags int64  // only rows with none of these flag bits set
	IncludeFlags int64  // rows with any of these bits are kept even if ExcludeFlags also matches
	WithoutFlags int64  // only rows with none of these flag bits set (independent of ExcludeFlags)

	// Negative filters — each entry excludes matching rows; multiples are ANDed.
	NotMethods  []string // exclude these exact methods
	NotHosts    []string // exclude rows whose host contains any of these
	NotPaths    []string // exclude rows whose path contains any of these
	NotStatuses []int    // exclude these exact status codes

	FlowIDs []int64 // when set, only these ids (used for body search results)
	HasNote bool    // only rows with a non-empty note
	Tag     string  // only rows carrying this exact tag
}

FlowFilter selects and pages flows. Zero-valued fields are ignored.

type HostStat added in v0.7.0

type HostStat struct {
	Host  string
	Flows int64
	Bytes int64
}

HostStat aggregates flow counts and approximate byte totals for one host. Bytes is SUM(req_len + res_len) across all flows for that host — an approximation, because content-addressed bodies are deduplicated on disk, so flows sharing a body each contribute to the sum even though only one file exists. Use it for a rough UI size-breakdown, not an exact disk-usage figure.

type Issue

type Issue struct {
	ID       int64  `json:"id"`
	FlowID   int64  `json:"flowId"`
	Severity string `json:"severity"`
	Title    string `json:"title"`
	Target   string `json:"target"`
	Detail   string `json:"detail"`
	Evidence string `json:"evidence"`
	Fix      string `json:"fix"`
}

Issue is one scanner finding. Severity is "High" | "Medium" | "Low" | "Info".

type Rule

type Rule struct {
	ID      int64
	Ord     int
	Enabled bool
	Type    string
	Match   string
	Replace string
}

Rule is one ordered match-&-replace transform. Type is one of "req-header", "req-body" (response-side types are reserved for a later slice).

type SavedView

type SavedView struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
	Data string `json:"data"`
}

SavedView is a named history filter (its Data is an opaque JSON blob the UI understands: scheme/method/status/search/host/inScope).

type ScopeRule

type ScopeRule struct {
	ID      int64  `json:"id"`
	Ord     int    `json:"ord"`
	Enabled bool   `json:"enabled"`
	Action  string `json:"action"`
	Host    string `json:"host"`
	Path    string `json:"path"`
	Scheme  string `json:"scheme"`
	Port    int    `json:"port"`
}

ScopeRule is one target-scope rule. Action is "include" | "exclude". Empty host/path/scheme and port 0 mean "any" for that field.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store owns the SQLite database and the on-disk body directory.

func Open

func Open(dir string) (*Store, error)

Open creates (or opens) the database and body store under dir.

func (*Store) AddFlowTags added in v0.11.0

func (s *Store) AddFlowTags(flowID int64, tags []string) ([]string, error)

AddFlowTags adds tags to a flow (union) and returns the flow's full tag set.

func (*Store) AttachFlow added in v0.10.0

func (s *Store) AttachFlow(findingID, flowID int64, note string, pos int) error

AttachFlow records a flow as a PoC for a finding and inserts (or updates) a flow block in the finding's narrative body. pos is the 0-based block index at which to insert the flow block; pass -1 to append at the end. Idempotent on re-attach — updates the note in both tables and in the body block (position unchanged if the block already exists).

func (*Store) AttachTags added in v0.11.0

func (s *Store) AttachTags(flows []*Flow) error

AttachTags populates each flow's Tags field from one batch query.

func (*Store) BackupTo added in v0.26.0

func (s *Store) BackupTo(destPath string) error

BackupTo writes a consistent, compacted snapshot of the database to destPath using SQLite's `VACUUM INTO`. It is safe to call on a live WAL-mode database: the snapshot is a single self-contained file with every committed row folded in (no separate -wal/-shm needed) and free pages reclaimed, so it is both consistent and typically smaller than a raw file copy.

destPath must not already exist — VACUUM INTO refuses to overwrite. The filename is a SQL string literal (not a bound parameter), so single quotes in the path are escaped to keep it a single literal.

func (*Store) BodiesDir added in v0.26.0

func (s *Store) BodiesDir() string

BodiesDir returns the absolute directory holding content-addressed body blobs for this store. Callers that archive a whole project (DB + bodies) need it.

func (*Store) ClearIssues

func (s *Store) ClearIssues() error

ClearIssues removes all issues.

func (*Store) Close

func (s *Store) Close() error

Close closes the underlying database.

func (*Store) CountFlowsWithFlag added in v0.21.0

func (s *Store) CountFlowsWithFlag(flag int64) (int64, error)

CountFlowsWithFlag returns how many flows have any of the given flag bits set.

func (*Store) CountSuccessfulHTTPS added in v0.21.0

func (s *Store) CountSuccessfulHTTPS(hostSubstring string) (int64, error)

CountSuccessfulHTTPS returns flows where HTTPS MITM completed (non-zero status, not a recorded TLS handshake failure).

func (*Store) CreateAPIKey

func (s *Store) CreateAPIKey(label string) (token string, key APIKey, err error)

CreateAPIKey mints a new key, returning the full token (shown to the user once) and its stored metadata. The token is "ick_" + 48 hex chars.

func (*Store) CreateFinding added in v0.10.0

func (s *Store) CreateFinding(f *Finding) (int64, error)

CreateFinding inserts a finding and sets f.ID/f.TS/f.UpdatedTS. Title is required. If Body is empty it is synthesized from Detail + Evidence so new findings are immediately in the interleaved-body format.

func (*Store) CreateRule

func (s *Store) CreateRule(r *Rule) (int64, error)

CreateRule inserts a rule and returns its id.

func (*Store) CreateScopeRule

func (s *Store) CreateScopeRule(r *ScopeRule) (int64, error)

CreateScopeRule inserts a scope rule and returns its id.

func (*Store) CreateView

func (s *Store) CreateView(v *SavedView) (int64, error)

CreateView stores a named view and returns its id.

func (*Store) DeleteAPIKey

func (s *Store) DeleteAPIKey(id int64) error

DeleteAPIKey revokes a key by id.

func (*Store) DeleteActivity added in v0.6.0

func (s *Store) DeleteActivity() error

DeleteActivity removes every recorded activity row (the user cleared the feed).

func (*Store) DeleteFinding added in v0.10.0

func (s *Store) DeleteFinding(id int64) error

DeleteFinding removes a finding and its PoC attachments.

func (*Store) DeleteFlows added in v0.5.0

func (s *Store) DeleteFlows(ids []int64) (int64, error)

DeleteFlows removes the given flows and returns how many rows were deleted. An empty id list is a no-op. Content-addressed body files are left in place (they are shared/deduplicated across flows); the metadata rows are what go.

func (*Store) DeleteFlowsByHost added in v0.7.0

func (s *Store) DeleteFlowsByHost(hosts []string, keepOnly bool) (int64, error)

DeleteFlowsByHost removes flows by host pattern and returns how many rows were deleted.

  • When keepOnly is false, every flow whose host matches ANY pattern in hosts is deleted. An empty hosts slice is a no-op (returns 0, nil).
  • When keepOnly is true, every flow whose host matches NONE of the patterns is deleted (i.e. the listed hosts are kept, everything else is purged). An empty hosts slice with keepOnly=true is rejected with an error to prevent silently wiping all data.

Pattern matching is case-insensitive and supports leading-wildcard patterns (e.g. "*.example.com" matches "example.com" and all subdomains).

func (*Store) DeleteRule

func (s *Store) DeleteRule(id int64) error

DeleteRule removes a rule by id.

func (*Store) DeleteScopeRule

func (s *Store) DeleteScopeRule(id int64) error

DeleteScopeRule removes a scope rule by id.

func (*Store) DeleteView

func (s *Store) DeleteView(id int64) error

DeleteView removes a view by id.

func (*Store) DetachFlow added in v0.10.0

func (s *Store) DetachFlow(findingID, flowID int64) error

DetachFlow removes a PoC flow from a finding's flow table and body.

func (*Store) DistinctTags added in v0.11.0

func (s *Store) DistinctTags() ([]TagCount, error)

DistinctTags lists every tag in use with its flow count and color, most-used first.

func (*Store) Endpoints added in v0.5.0

func (s *Store) Endpoints(f EndpointFilter) ([]Endpoint, string, error)

Endpoints returns unique endpoints aggregated from flows. When SearchScope is headers, body, or all, Search filters by stored headers and/or body content (body search is bounded — see maxEndpointBodyScanFlows).

func (*Store) FlowCount added in v0.14.0

func (s *Store) FlowCount() (int64, error)

FlowCount returns the total number of captured flows.

func (*Store) FlowIDsBodySearch added in v0.9.0

func (s *Store) FlowIDsBodySearch(f FlowFilter, maxScan int) ([]int64, string, error)

FlowIDsBodySearch returns flow ids whose request or response body contains term (case-insensitive). Other FlowFilter fields apply; Search is the body term.

func (*Store) FlowTags added in v0.11.0

func (s *Store) FlowTags(flowID int64) ([]string, error)

FlowTags returns one flow's tags, sorted.

func (*Store) GCBodies added in v0.7.0

func (s *Store) GCBodies() (removedFiles int64, freedBytes int64, err error)

GCBodies reclaims body files that are no longer referenced by any flow. It walks bodiesDir, collects every file whose name looks like a content hash (a 64-hex-char sha256 stored under a two-level prefix directory), queries the flows table for all referenced hashes, and removes any file whose hash is not among them.

GCBodies returns the number of files removed and the total bytes freed. It is safe to call while the store is in use: it never removes a file that is still referenced, and it never touches files outside bodiesDir or files whose names do not match the content-hash scheme (e.g. ".tmp-*" partials).

func (*Store) GCNotesImages added in v0.8.0

func (s *Store) GCNotesImages(notes string) error

GCNotesImages deletes notebook images no longer referenced in the markdown.

func (*Store) GetFinding added in v0.10.0

func (s *Store) GetFinding(id int64) (*Finding, error)

GetFinding loads one finding with its narrative body blocks and PoC flow list.

func (*Store) GetFlow

func (s *Store) GetFlow(id int64) (*Flow, error)

GetFlow loads a single flow by id.

func (*Store) GetNotesImage added in v0.8.0

func (s *Store) GetNotesImage(id int64) (mime string, data []byte, err error)

GetNotesImage loads a stored notebook image by id.

func (*Store) GetSetting

func (s *Store) GetSetting(key string) (string, bool, error)

GetSetting returns the value and whether it was present.

func (*Store) HasAPIKeys added in v0.6.0

func (s *Store) HasAPIKeys() (bool, error)

HasAPIKeys reports whether any control-API key exists. Auth is opt-in: while this is false the MCP endpoint stays open (loopback trust); once the operator creates a key, a valid bearer token is required.

func (*Store) HostStats added in v0.7.0

func (s *Store) HostStats() ([]HostStat, error)

HostStats returns per-host flow counts and approximate byte totals, sorted descending by bytes. See HostStat for the approximation caveat.

func (*Store) InsertActivity added in v0.6.0

func (s *Store) InsertActivity(a *Activity) (int64, error)

InsertActivity persists an AI tool-call record (a.TS set by the caller) and sets a.ID. Rows older than the most recent activityKeep are pruned so the log can't grow without bound.

func (*Store) InsertFlow

func (s *Store) InsertFlow(f *Flow) (int64, error)

InsertFlow stores a new flow and sets f.ID to the assigned row id.

func (*Store) InsertNotesImage added in v0.8.0

func (s *Store) InsertNotesImage(mime string, data []byte) (int64, error)

InsertNotesImage stores one embedded notebook image and returns its row id.

func (*Store) ListAPIKeys

func (s *Store) ListAPIKeys() ([]APIKey, error)

ListAPIKeys returns all key metadata (never the token or hash), newest first.

func (*Store) ListActivity added in v0.6.0

func (s *Store) ListActivity(limit int) ([]Activity, error)

ListActivity returns recorded activity newest-first, capped at limit.

func (*Store) ListFindings added in v0.10.0

func (s *Store) ListFindings(severity, status string) ([]Finding, error)

ListFindings returns findings ordered by severity (High→Info) then newest, each with its PoC flows and narrative blocks. Empty severity/status means "any".

func (*Store) ListIssues

func (s *Store) ListIssues() ([]Issue, error)

ListIssues returns all issues ordered by severity (High→Info) then id.

func (*Store) ListRules

func (s *Store) ListRules() ([]Rule, error)

ListRules returns all rules ordered by ord then id.

func (*Store) ListScopeRules

func (s *Store) ListScopeRules() ([]ScopeRule, error)

ListScopeRules returns scope rules ordered by ord then id.

func (*Store) ListViews

func (s *Store) ListViews() ([]SavedView, error)

ListViews returns saved views, newest first.

func (*Store) LoadNotes added in v0.8.0

func (s *Store) LoadNotes() (string, error)

LoadNotes returns project notes, migrating any legacy inline data-URL images.

func (*Store) NewBodyWriter

func (s *Store) NewBodyWriter() (*BodyWriter, error)

NewBodyWriter starts a new body capture.

func (*Store) NormalizeNotesMarkdown added in v0.8.0

func (s *Store) NormalizeNotesMarkdown(notes string) (string, error)

NormalizeNotesMarkdown replaces inline data-URL images with /api/notes/images/{id} references backed by SQLite blobs, so the markdown stays small.

func (*Store) NotesImageExists added in v0.8.0

func (s *Store) NotesImageExists(id int64) (bool, error)

NotesImageExists reports whether an image id is present (for tests).

func (*Store) OpenBody

func (s *Store) OpenBody(sum string) (io.ReadCloser, error)

OpenBody returns a reader for the body with the given hash. An empty hash yields an empty reader (no body).

func (*Store) PersistNotes added in v0.8.0

func (s *Store) PersistNotes(notes string) (string, error)

PersistNotes saves normalized markdown and drops orphaned images.

func (*Store) QueryFlows

func (s *Store) QueryFlows(limit int) ([]*Flow, error)

QueryFlows returns up to limit flows, newest first.

func (*Store) QueryFlowsFilter

func (s *Store) QueryFlowsFilter(f FlowFilter) ([]*Flow, error)

QueryFlowsFilter returns flows matching f, newest first. Filtering and paging are pushed down to SQL so large histories never materialize in memory.

func (*Store) QueryFlowsListFilter added in v0.8.0

func (s *Store) QueryFlowsListFilter(f FlowFilter) ([]*Flow, error)

QueryFlowsListFilter is like QueryFlowsFilter but skips req/res header columns.

func (*Store) QueryWSFrames

func (s *Store) QueryWSFrames(flowID int64, limit int) ([]*WSFrame, error)

QueryWSFrames returns up to limit frames for a flow, oldest first.

func (*Store) RemoveFlowTag added in v0.11.0

func (s *Store) RemoveFlowTag(flowID int64, tag string) error

RemoveFlowTag detaches a single tag from a flow.

func (*Store) SaveIssues

func (s *Store) SaveIssues(issues []Issue) error

SaveIssues upserts issues, deduplicated by (title, target).

func (*Store) SaveWSFrame

func (s *Store) SaveWSFrame(f *WSFrame) error

SaveWSFrame records a captured frame, trimming the flow to the most recent wsFramesPerFlow frames.

func (*Store) SetFlowNote added in v0.5.0

func (s *Store) SetFlowNote(id int64, note string) error

SetFlowNote sets (or clears, with "") the free-text note attached to a flow.

func (*Store) SetFlowTags added in v0.11.0

func (s *Store) SetFlowTags(flowID int64, tags []string) ([]string, error)

SetFlowTags replaces a flow's tag set with the normalized `tags` (empty clears).

func (*Store) SetSetting

func (s *Store) SetSetting(key, value string) error

SetSetting upserts a key/value setting.

func (*Store) SetTagColor added in v0.11.0

func (s *Store) SetTagColor(tag, color string) error

SetTagColor sets (or clears, with "") a tag's display color. The value is stored verbatim; callers validate it's a safe CSS color before persisting.

func (*Store) TagsForFlows added in v0.11.0

func (s *Store) TagsForFlows(ids []int64) (map[int64][]string, error)

TagsForFlows batch-loads tags for many flows in one query (no N+1), returning a map from flow id to its sorted tag list. Ids with no tags are absent from the map.

func (*Store) UpdateFinding added in v0.10.0

func (s *Store) UpdateFinding(id int64, severity, status, title, target, detail, evidence, fix, body, impact, cvss *string) error

UpdateFinding applies non-nil fields and bumps updated_ts. body, when set, is stored as the new narrative body (already-serialized JSON). When detail is set but body is nil, the first text block in an existing body is updated (MCP backward-compat: AI updates detail → UI sees the change). When body is set, detail is synced from its first text block so MCP list_findings still shows meaningful text.

func (*Store) UpdateFlow added in v0.3.0

func (s *Store) UpdateFlow(f *Flow) error

UpdateFlow fills in the response-side (and post-send request) fields of a flow that was first inserted at request time, keyed by f.ID. The immutable request identity (ts, scheme, host, port, version, client) is left untouched.

func (*Store) UpdateRule

func (s *Store) UpdateRule(r *Rule) error

UpdateRule overwrites the rule identified by r.ID.

func (*Store) UpdateScopeRule

func (s *Store) UpdateScopeRule(r *ScopeRule) error

UpdateScopeRule overwrites the rule identified by r.ID.

func (*Store) VerifyAPIKey

func (s *Store) VerifyAPIKey(token string) (bool, error)

VerifyAPIKey reports whether token matches a stored key (constant work via the hash index). Intended for gating remote control-API access.

type TagCount added in v0.11.0

type TagCount struct {
	Tag   string `json:"tag"`
	Count int    `json:"count"`
	Color string `json:"color,omitempty"`
}

TagCount is a tag with how many flows carry it and its (optional) color.

type WSFrame

type WSFrame struct {
	ID      int64     `json:"id"`
	FlowID  int64     `json:"flowId"`
	TS      time.Time `json:"-"`
	Dir     string    `json:"dir"`
	Opcode  int       `json:"opcode"`
	Length  int64     `json:"length"`
	Preview string    `json:"preview"`
}

WSFrame is one captured WebSocket frame. Dir is "send" (client→server) or "recv" (server→client). Preview holds a bounded prefix of the (unmasked) payload; Length is the full frame payload length.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL