mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
feat: add Chromium Browser with new v2 architecture (#530)
* feat: add Chromium Browser implementation with new architecture * refactor: replace Walk with ReadDir+Stat for profile discovery * refactor: remove queries override, use extractors for Yandex passwords * refactor: remove dataSource wrapper, use []sourcePath directly * fix: address Copilot review feedback on chromium_new.go * fix: always call key retriever regardless of Local State existence
This commit is contained in:
+97
-26
@@ -1,37 +1,45 @@
|
||||
package chromium
|
||||
|
||||
import "github.com/moond4rk/hackbrowserdata/types"
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
// dataSource maps a Category to one or more candidate file paths within a profile directory.
|
||||
// paths are tried in order; the first one that exists is used.
|
||||
type dataSource struct {
|
||||
paths []string // candidate relative paths in priority order
|
||||
isDir bool // true for LevelDB directories
|
||||
"github.com/moond4rk/hackbrowserdata/types"
|
||||
)
|
||||
|
||||
// sourcePath describes a single candidate location for browser data,
|
||||
// relative to the profile directory.
|
||||
type sourcePath struct {
|
||||
rel string // relative path from profileDir, e.g. "Network/Cookies"
|
||||
isDir bool // true for directory targets (LevelDB, Session Storage)
|
||||
}
|
||||
|
||||
func file(rel string) sourcePath { return sourcePath{rel: filepath.FromSlash(rel), isDir: false} }
|
||||
func dir(rel string) sourcePath { return sourcePath{rel: filepath.FromSlash(rel), isDir: true} }
|
||||
|
||||
// chromiumSources defines the standard Chromium file layout.
|
||||
var chromiumSources = map[types.Category]dataSource{
|
||||
types.Password: {paths: []string{"Login Data"}},
|
||||
types.Cookie: {paths: []string{"Network/Cookies", "Cookies"}},
|
||||
types.History: {paths: []string{"History"}},
|
||||
types.Download: {paths: []string{"History"}}, // same file, different query
|
||||
types.Bookmark: {paths: []string{"Bookmarks"}},
|
||||
types.CreditCard: {paths: []string{"Web Data"}},
|
||||
types.Extension: {paths: []string{"Secure Preferences"}},
|
||||
types.LocalStorage: {paths: []string{"Local Storage/leveldb"}, isDir: true},
|
||||
types.SessionStorage: {paths: []string{"Session Storage"}, isDir: true},
|
||||
// Each category maps to one or more candidate paths tried in priority order;
|
||||
// the first existing path wins.
|
||||
var chromiumSources = map[types.Category][]sourcePath{
|
||||
types.Password: {file("Login Data")},
|
||||
types.Cookie: {file("Network/Cookies"), file("Cookies")},
|
||||
types.History: {file("History")},
|
||||
types.Download: {file("History")},
|
||||
types.Bookmark: {file("Bookmarks")},
|
||||
types.CreditCard: {file("Web Data")},
|
||||
types.Extension: {file("Secure Preferences")},
|
||||
types.LocalStorage: {dir("Local Storage/leveldb")},
|
||||
types.SessionStorage: {dir("Session Storage")},
|
||||
}
|
||||
|
||||
// yandexSourceOverrides contains only the entries that differ from chromiumSources.
|
||||
// At initialization time, these are merged into a copy of chromiumSources.
|
||||
var yandexSourceOverrides = map[types.Category]dataSource{
|
||||
types.Password: {paths: []string{"Ya Passman Data"}},
|
||||
types.CreditCard: {paths: []string{"Ya Credit Cards"}},
|
||||
var yandexSourceOverrides = map[types.Category][]sourcePath{
|
||||
types.Password: {file("Ya Passman Data")},
|
||||
types.CreditCard: {file("Ya Credit Cards")},
|
||||
}
|
||||
|
||||
// yandexSources returns chromiumSources with Yandex-specific overrides applied.
|
||||
func yandexSources() map[types.Category]dataSource {
|
||||
sources := make(map[types.Category]dataSource, len(chromiumSources))
|
||||
func yandexSources() map[types.Category][]sourcePath {
|
||||
sources := make(map[types.Category][]sourcePath, len(chromiumSources))
|
||||
for k, v := range chromiumSources {
|
||||
sources[k] = v
|
||||
}
|
||||
@@ -41,8 +49,71 @@ func yandexSources() map[types.Category]dataSource {
|
||||
return sources
|
||||
}
|
||||
|
||||
// yandexQueryOverrides provides SQL query overrides for Yandex Browser.
|
||||
// Yandex uses action_url instead of origin_url for password storage.
|
||||
var yandexQueryOverrides = map[types.Category]string{
|
||||
types.Password: `SELECT action_url, username_value, password_value, date_created FROM logins`,
|
||||
// sourcesForKind returns the source mapping for a browser kind.
|
||||
func sourcesForKind(kind types.BrowserKind) map[types.Category][]sourcePath {
|
||||
switch kind {
|
||||
case types.KindChromiumYandex:
|
||||
return yandexSources()
|
||||
default:
|
||||
return chromiumSources
|
||||
}
|
||||
}
|
||||
|
||||
// categoryExtractor extracts data for a single category into BrowserData.
|
||||
// Implementations wrap typed extract functions to provide a uniform dispatch
|
||||
// interface while preserving the original function signatures.
|
||||
//
|
||||
// Use extractorsForKind to register per-Kind overrides. When an extractor
|
||||
// is present for a category, extractCategory uses it instead of the default
|
||||
// switch logic, enabling browser-specific parsing (e.g. Opera's opsettings
|
||||
// for extensions, Yandex's credit card table, QBCI-encrypted bookmarks).
|
||||
type categoryExtractor interface {
|
||||
extract(masterKey []byte, path string, data *types.BrowserData) error
|
||||
}
|
||||
|
||||
// passwordExtractor wraps a custom password extract function.
|
||||
type passwordExtractor struct {
|
||||
fn func(masterKey []byte, path string) ([]types.LoginEntry, error)
|
||||
}
|
||||
|
||||
func (e passwordExtractor) extract(masterKey []byte, path string, data *types.BrowserData) error {
|
||||
var err error
|
||||
data.Passwords, err = e.fn(masterKey, path)
|
||||
return err
|
||||
}
|
||||
|
||||
// extensionExtractor wraps a custom extension extract function.
|
||||
type extensionExtractor struct {
|
||||
fn func(path string) ([]types.ExtensionEntry, error)
|
||||
}
|
||||
|
||||
func (e extensionExtractor) extract(_ []byte, path string, data *types.BrowserData) error {
|
||||
var err error
|
||||
data.Extensions, err = e.fn(path)
|
||||
return err
|
||||
}
|
||||
|
||||
// yandexExtractors overrides Password extraction for Yandex,
|
||||
// which uses action_url instead of origin_url.
|
||||
var yandexExtractors = map[types.Category]categoryExtractor{
|
||||
types.Password: passwordExtractor{fn: extractYandexPasswords},
|
||||
}
|
||||
|
||||
// operaExtractors overrides Extension extraction for Opera,
|
||||
// which stores settings under "extensions.opsettings".
|
||||
var operaExtractors = map[types.Category]categoryExtractor{
|
||||
types.Extension: extensionExtractor{fn: extractOperaExtensions},
|
||||
}
|
||||
|
||||
// extractorsForKind returns custom category extractors for a browser kind.
|
||||
// nil means all categories use the default extractCategory switch logic.
|
||||
func extractorsForKind(kind types.BrowserKind) map[types.Category]categoryExtractor {
|
||||
switch kind {
|
||||
case types.KindChromiumYandex:
|
||||
return yandexExtractors
|
||||
case types.KindChromiumOpera:
|
||||
return operaExtractors
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user