feat: add output package with Formatter interface (#537)

* docs: add RFC-004 for CLI (cobra) and output design
* feat: add output package with Formatter interface and BrowserData.Each
* fix: golangci config array syntax + add output package tests
* refactor: encapsulated Output as Writer, collect-then-write pattern
* refactor: unified row type with reflection-based CSV/JSON output
* fix: ProfileName empty guard, writeFile close error check, sync RFC-004
This commit is contained in:
Roger
2026-04-04 01:17:55 +08:00
committed by moonD4rk
parent 1a3aea553e
commit 00ad0e0bd4
16 changed files with 1290 additions and 52 deletions
+9 -7
View File
@@ -14,7 +14,6 @@ import (
// Browser represents a single Chromium profile ready for extraction.
type Browser struct {
cfg types.BrowserConfig
name string // display name: "Chrome-Default"
profileDir string // absolute path to profile directory
sources map[types.Category][]sourcePath // Category → candidate paths (priority order)
extractors map[types.Category]categoryExtractor // Category → custom extract function override
@@ -41,7 +40,6 @@ func NewBrowsers(cfg types.BrowserConfig) ([]*Browser, error) {
}
browsers = append(browsers, &Browser{
cfg: cfg,
name: cfg.Name + "-" + filepath.Base(profileDir),
profileDir: profileDir,
sources: sources,
extractors: extractors,
@@ -51,8 +49,12 @@ func NewBrowsers(cfg types.BrowserConfig) ([]*Browser, error) {
return browsers, nil
}
func (b *Browser) Name() string {
return b.name
func (b *Browser) BrowserName() string { return b.cfg.Name }
func (b *Browser) ProfileName() string {
if b.profileDir == "" {
return ""
}
return filepath.Base(b.profileDir)
}
// Extract copies browser files to a temp directory, retrieves the master key,
@@ -68,7 +70,7 @@ func (b *Browser) Extract(categories []types.Category) (*types.BrowserData, erro
masterKey, err := b.getMasterKey(session)
if err != nil {
log.Debugf("get master key for %s: %v", b.name, err)
log.Debugf("get master key for %s: %v", b.BrowserName()+"/"+b.ProfileName(), err)
}
data := &types.BrowserData{}
@@ -134,7 +136,7 @@ func (b *Browser) getMasterKey(session *filemanager.Session) ([]byte, error) {
func (b *Browser) extractCategory(data *types.BrowserData, cat types.Category, masterKey []byte, path string) {
if ext, ok := b.extractors[cat]; ok {
if err := ext.extract(masterKey, path, data); err != nil {
log.Debugf("extract %s for %s: %v", cat, b.name, err)
log.Debugf("extract %s for %s: %v", cat, b.BrowserName()+"/"+b.ProfileName(), err)
}
return
}
@@ -161,7 +163,7 @@ func (b *Browser) extractCategory(data *types.BrowserData, cat types.Category, m
data.SessionStorage, err = extractSessionStorage(path)
}
if err != nil {
log.Debugf("extract %s for %s: %v", cat, b.name, err)
log.Debugf("extract %s for %s: %v", cat, b.BrowserName()+"/"+b.ProfileName(), err)
}
}
-1
View File
@@ -369,7 +369,6 @@ func TestExtractCategory_DefaultFallback(t *testing.T) {
)
b := &Browser{
name: "Test",
extractors: nil, // no custom extractors
}