mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
feat: add types.Category, data models, and browserdata.Data (#512)
* feat: add new types.Category, data models, and browserdata.Data Phase 1 of architecture refactoring (RFC-001/RFC-002): - types/category.go: Category enum (9 values) replacing DataType (22 values) with String(), IsSensitive(), AllCategories, NonSensitiveCategories() - types/models.go: browser-agnostic data models (LoginEntry, CookieEntry, BookmarkEntry, HistoryEntry, DownloadEntry, CreditCardEntry, StorageEntry, ExtensionEntry) — no encrypted fields, no browser prefixes - types/category_test.go: tests for Category methods - browserdata/browser_data.go: new Data struct with typed slices, coexists with old BrowserData during migration * docs: replace Coveralls badge with Codecov in README * fix: apply review suggestions (is_http_only tag, json tags on Data)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
# HackBrowserData
|
||||
|
||||
[](https://github.com/moonD4rk/HackBrowserData/actions/workflows/lint.yml) [](https://github.com/moonD4rk/HackBrowserData/actions/workflows/build.yml) [](https://github.com/moonD4rk/HackBrowserData/actions/workflows/release.yml) [](https://github.com/moonD4rk/HackBrowserData/actions/workflows/test.yml) [](https://coveralls.io/github/moonD4rk/HackBrowserData)
|
||||
[](https://github.com/moonD4rk/HackBrowserData/actions/workflows/lint.yml) [](https://github.com/moonD4rk/HackBrowserData/actions/workflows/build.yml) [](https://github.com/moonD4rk/HackBrowserData/actions/workflows/release.yml) [](https://github.com/moonD4rk/HackBrowserData/actions/workflows/test.yml) [](https://codecov.io/gh/moonD4rk/HackBrowserData)
|
||||
|
||||
`HackBrowserData` is a command-line tool for decrypting and exporting browser data (passwords, history, cookies, bookmarks, credit cards, download history, localStorage and extensions) from the browser. It supports the most popular browsers on the market and runs on Windows, macOS and Linux.
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package browserdata
|
||||
|
||||
import "github.com/moond4rk/hackbrowserdata/types"
|
||||
|
||||
// Data holds all extracted data from one browser profile.
|
||||
// Each field is a slice that may be nil (not supported) or empty (no data found).
|
||||
// This struct will replace the current BrowserData once the refactoring is complete.
|
||||
type Data struct {
|
||||
Passwords []types.LoginEntry `json:"passwords,omitempty"`
|
||||
Cookies []types.CookieEntry `json:"cookies,omitempty"`
|
||||
Bookmarks []types.BookmarkEntry `json:"bookmarks,omitempty"`
|
||||
Histories []types.HistoryEntry `json:"histories,omitempty"`
|
||||
Downloads []types.DownloadEntry `json:"downloads,omitempty"`
|
||||
CreditCards []types.CreditCardEntry `json:"credit_cards,omitempty"`
|
||||
Extensions []types.ExtensionEntry `json:"extensions,omitempty"`
|
||||
LocalStorage []types.StorageEntry `json:"local_storage,omitempty"`
|
||||
SessionStorage []types.StorageEntry `json:"session_storage,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package types
|
||||
|
||||
// Category represents a kind of browser data.
|
||||
// It is browser-agnostic — a password is a password regardless of which browser it came from.
|
||||
type Category int
|
||||
|
||||
const (
|
||||
Password Category = iota
|
||||
Cookie
|
||||
Bookmark
|
||||
History
|
||||
Download
|
||||
CreditCard
|
||||
Extension
|
||||
LocalStorage
|
||||
SessionStorage
|
||||
)
|
||||
|
||||
// AllCategories returns all supported data categories.
|
||||
var AllCategories = []Category{
|
||||
Password, Cookie, Bookmark, History, Download,
|
||||
CreditCard, Extension, LocalStorage, SessionStorage,
|
||||
}
|
||||
|
||||
// String returns the human-readable name of the category.
|
||||
func (c Category) String() string {
|
||||
switch c {
|
||||
case Password:
|
||||
return "password"
|
||||
case Cookie:
|
||||
return "cookie"
|
||||
case Bookmark:
|
||||
return "bookmark"
|
||||
case History:
|
||||
return "history"
|
||||
case Download:
|
||||
return "download"
|
||||
case CreditCard:
|
||||
return "creditcard"
|
||||
case Extension:
|
||||
return "extension"
|
||||
case LocalStorage:
|
||||
return "localstorage"
|
||||
case SessionStorage:
|
||||
return "sessionstorage"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// IsSensitive returns whether the category contains sensitive data
|
||||
// that requires explicit opt-in to export.
|
||||
func (c Category) IsSensitive() bool {
|
||||
switch c {
|
||||
case Password, Cookie, CreditCard:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// NonSensitiveCategories returns categories that are safe to export by default.
|
||||
func NonSensitiveCategories() []Category {
|
||||
var cats []Category
|
||||
for _, c := range AllCategories {
|
||||
if !c.IsSensitive() {
|
||||
cats = append(cats, c)
|
||||
}
|
||||
}
|
||||
return cats
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCategory_String(t *testing.T) {
|
||||
tests := []struct {
|
||||
cat Category
|
||||
want string
|
||||
}{
|
||||
{Password, "password"},
|
||||
{Cookie, "cookie"},
|
||||
{Bookmark, "bookmark"},
|
||||
{History, "history"},
|
||||
{Download, "download"},
|
||||
{CreditCard, "creditcard"},
|
||||
{Extension, "extension"},
|
||||
{LocalStorage, "localstorage"},
|
||||
{SessionStorage, "sessionstorage"},
|
||||
{Category(999), "unknown"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
assert.Equal(t, tt.want, tt.cat.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCategory_IsSensitive(t *testing.T) {
|
||||
sensitive := []Category{Password, Cookie, CreditCard}
|
||||
for _, c := range sensitive {
|
||||
assert.True(t, c.IsSensitive(), "%s should be sensitive", c)
|
||||
}
|
||||
|
||||
notSensitive := []Category{Bookmark, History, Download, Extension, LocalStorage, SessionStorage}
|
||||
for _, c := range notSensitive {
|
||||
assert.False(t, c.IsSensitive(), "%s should not be sensitive", c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllCategories(t *testing.T) {
|
||||
assert.Len(t, AllCategories, 9)
|
||||
}
|
||||
|
||||
func TestNonSensitiveCategories(t *testing.T) {
|
||||
cats := NonSensitiveCategories()
|
||||
assert.Len(t, cats, 6)
|
||||
for _, c := range cats {
|
||||
assert.False(t, c.IsSensitive())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package types
|
||||
|
||||
import "time"
|
||||
|
||||
// LoginEntry represents a single saved login credential.
|
||||
type LoginEntry struct {
|
||||
URL string `json:"url" csv:"url"`
|
||||
Username string `json:"username" csv:"username"`
|
||||
Password string `json:"password" csv:"password"`
|
||||
CreatedAt time.Time `json:"created_at" csv:"created_at"`
|
||||
}
|
||||
|
||||
// CookieEntry represents a single browser cookie.
|
||||
type CookieEntry struct {
|
||||
Host string `json:"host" csv:"host"`
|
||||
Path string `json:"path" csv:"path"`
|
||||
Name string `json:"name" csv:"name"`
|
||||
Value string `json:"value" csv:"value"`
|
||||
IsSecure bool `json:"is_secure" csv:"is_secure"`
|
||||
IsHTTPOnly bool `json:"is_http_only" csv:"is_http_only"`
|
||||
ExpireAt time.Time `json:"expire_at" csv:"expire_at"`
|
||||
CreatedAt time.Time `json:"created_at" csv:"created_at"`
|
||||
}
|
||||
|
||||
// BookmarkEntry represents a single browser bookmark.
|
||||
type BookmarkEntry struct {
|
||||
Name string `json:"name" csv:"name"`
|
||||
URL string `json:"url" csv:"url"`
|
||||
Folder string `json:"folder" csv:"folder"`
|
||||
CreatedAt time.Time `json:"created_at" csv:"created_at"`
|
||||
}
|
||||
|
||||
// HistoryEntry represents a single browser history record.
|
||||
type HistoryEntry struct {
|
||||
URL string `json:"url" csv:"url"`
|
||||
Title string `json:"title" csv:"title"`
|
||||
VisitCount int `json:"visit_count" csv:"visit_count"`
|
||||
LastVisit time.Time `json:"last_visit" csv:"last_visit"`
|
||||
}
|
||||
|
||||
// DownloadEntry represents a single browser download record.
|
||||
type DownloadEntry struct {
|
||||
URL string `json:"url" csv:"url"`
|
||||
TargetPath string `json:"target_path" csv:"target_path"`
|
||||
TotalBytes int64 `json:"total_bytes" csv:"total_bytes"`
|
||||
StartTime time.Time `json:"start_time" csv:"start_time"`
|
||||
EndTime time.Time `json:"end_time" csv:"end_time"`
|
||||
}
|
||||
|
||||
// CreditCardEntry represents a single saved credit card.
|
||||
type CreditCardEntry struct {
|
||||
Name string `json:"name" csv:"name"`
|
||||
Number string `json:"number" csv:"number"`
|
||||
ExpMonth string `json:"exp_month" csv:"exp_month"`
|
||||
ExpYear string `json:"exp_year" csv:"exp_year"`
|
||||
}
|
||||
|
||||
// StorageEntry represents a single key-value pair from local or session storage.
|
||||
type StorageEntry struct {
|
||||
URL string `json:"url" csv:"url"`
|
||||
Key string `json:"key" csv:"key"`
|
||||
Value string `json:"value" csv:"value"`
|
||||
}
|
||||
|
||||
// ExtensionEntry represents a single browser extension.
|
||||
type ExtensionEntry struct {
|
||||
Name string `json:"name" csv:"name"`
|
||||
ID string `json:"id" csv:"id"`
|
||||
Description string `json:"description" csv:"description"`
|
||||
Version string `json:"version" csv:"version"`
|
||||
}
|
||||
Reference in New Issue
Block a user