refactor: naming cleanup and crypto package improvements (#551)

* refactor: naming cleanup across all packages
This commit is contained in:
Roger
2026-04-05 16:51:56 +08:00
committed by GitHub
parent 4af2ded428
commit 410bffe643
49 changed files with 716 additions and 510 deletions
+3 -3
View File
@@ -48,7 +48,7 @@ func pickFromConfigs(configs []types.BrowserConfig, opts PickOptions) ([]Browser
}
if opts.ProfilePath != "" && name != "all" {
if cfg.Kind == types.KindFirefox {
if cfg.Kind == types.Firefox {
cfg.UserDataDir = filepath.Dir(filepath.Clean(opts.ProfilePath))
} else {
cfg.UserDataDir = opts.ProfilePath
@@ -76,7 +76,7 @@ func pickFromConfigs(configs []types.BrowserConfig, opts PickOptions) ([]Browser
// newBrowsers dispatches to the correct engine based on BrowserKind.
func newBrowsers(cfg types.BrowserConfig) ([]Browser, error) {
switch cfg.Kind {
case types.KindChromium, types.KindChromiumYandex, types.KindChromiumOpera:
case types.Chromium, types.ChromiumYandex, types.ChromiumOpera:
bs, err := chromium.NewBrowsers(cfg)
if err != nil {
return nil, err
@@ -87,7 +87,7 @@ func newBrowsers(cfg types.BrowserConfig) ([]Browser, error) {
}
return browsers, nil
case types.KindFirefox:
case types.Firefox:
bs, err := firefox.NewBrowsers(cfg)
if err != nil {
return nil, err
+12 -12
View File
@@ -11,84 +11,84 @@ func platformBrowsers() []types.BrowserConfig {
{
Key: "chrome",
Name: chromeName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Chrome",
UserDataDir: homeDir + "/Library/Application Support/Google/Chrome",
},
{
Key: "edge",
Name: edgeName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Microsoft Edge",
UserDataDir: homeDir + "/Library/Application Support/Microsoft Edge",
},
{
Key: "chromium",
Name: chromiumName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Chromium",
UserDataDir: homeDir + "/Library/Application Support/Chromium",
},
{
Key: "chrome-beta",
Name: chromeBetaName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Chrome",
UserDataDir: homeDir + "/Library/Application Support/Google/Chrome Beta",
},
{
Key: "opera",
Name: operaName,
Kind: types.KindChromiumOpera,
Kind: types.ChromiumOpera,
Storage: "Opera",
UserDataDir: homeDir + "/Library/Application Support/com.operasoftware.Opera",
},
{
Key: "opera-gx",
Name: operaGXName,
Kind: types.KindChromiumOpera,
Kind: types.ChromiumOpera,
Storage: "Opera",
UserDataDir: homeDir + "/Library/Application Support/com.operasoftware.OperaGX",
},
{
Key: "vivaldi",
Name: vivaldiName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Vivaldi",
UserDataDir: homeDir + "/Library/Application Support/Vivaldi",
},
{
Key: "coccoc",
Name: coccocName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "CocCoc",
UserDataDir: homeDir + "/Library/Application Support/Coccoc",
},
{
Key: "brave",
Name: braveName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Brave",
UserDataDir: homeDir + "/Library/Application Support/BraveSoftware/Brave-Browser",
},
{
Key: "yandex",
Name: yandexName,
Kind: types.KindChromiumYandex,
Kind: types.ChromiumYandex,
Storage: "Yandex",
UserDataDir: homeDir + "/Library/Application Support/Yandex/YandexBrowser",
},
{
Key: "arc",
Name: arcName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Arc",
UserDataDir: homeDir + "/Library/Application Support/Arc/User Data",
},
{
Key: "firefox",
Name: firefoxName,
Kind: types.KindFirefox,
Kind: types.Firefox,
UserDataDir: homeDir + "/Library/Application Support/Firefox/Profiles",
},
}
+8 -8
View File
@@ -11,56 +11,56 @@ func platformBrowsers() []types.BrowserConfig {
{
Key: "chrome",
Name: chromeName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Chrome Safe Storage",
UserDataDir: homeDir + "/.config/google-chrome",
},
{
Key: "edge",
Name: edgeName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Chromium Safe Storage",
UserDataDir: homeDir + "/.config/microsoft-edge",
},
{
Key: "chromium",
Name: chromiumName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Chromium Safe Storage",
UserDataDir: homeDir + "/.config/chromium",
},
{
Key: "chrome-beta",
Name: chromeBetaName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Chrome Safe Storage",
UserDataDir: homeDir + "/.config/google-chrome-beta",
},
{
Key: "opera",
Name: operaName,
Kind: types.KindChromiumOpera,
Kind: types.ChromiumOpera,
Storage: "Chromium Safe Storage",
UserDataDir: homeDir + "/.config/opera",
},
{
Key: "vivaldi",
Name: vivaldiName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Chrome Safe Storage",
UserDataDir: homeDir + "/.config/vivaldi",
},
{
Key: "brave",
Name: braveName,
Kind: types.KindChromium,
Kind: types.Chromium,
Storage: "Brave Safe Storage",
UserDataDir: homeDir + "/.config/BraveSoftware/Brave-Browser",
},
{
Key: "firefox",
Name: firefoxName,
Kind: types.KindFirefox,
Kind: types.Firefox,
UserDataDir: homeDir + "/.mozilla/firefox",
},
}
+9 -9
View File
@@ -32,8 +32,8 @@ func TestPickFromConfigs_NameFilter(t *testing.T) {
mkFile(t, dir, "Default", "History")
configs := []types.BrowserConfig{
{Key: "chrome", Name: "Chrome", Kind: types.KindChromium, UserDataDir: dir},
{Key: "edge", Name: "Edge", Kind: types.KindChromium, UserDataDir: dir},
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: dir},
{Key: "edge", Name: "Edge", Kind: types.Chromium, UserDataDir: dir},
}
tests := []struct {
@@ -102,7 +102,7 @@ func TestPickFromConfigs_BrowserKind(t *testing.T) {
{
name: "chromium multi-profile",
configs: []types.BrowserConfig{
{Key: "chrome", Name: "Chrome", Kind: types.KindChromium, UserDataDir: chromeDir},
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: chromeDir},
},
wantNames: []string{"Chrome", "Chrome"},
wantProfiles: []string{"Default", "Profile 1"},
@@ -110,7 +110,7 @@ func TestPickFromConfigs_BrowserKind(t *testing.T) {
{
name: "firefox random dir",
configs: []types.BrowserConfig{
{Key: "firefox", Name: "Firefox", Kind: types.KindFirefox, UserDataDir: firefoxDir},
{Key: "firefox", Name: "Firefox", Kind: types.Firefox, UserDataDir: firefoxDir},
},
wantNames: []string{"Firefox"},
wantProfiles: []string{"abc123.default-release"},
@@ -118,7 +118,7 @@ func TestPickFromConfigs_BrowserKind(t *testing.T) {
{
name: "yandex variant",
configs: []types.BrowserConfig{
{Key: "yandex", Name: "Yandex", Kind: types.KindChromiumYandex, UserDataDir: yandexDir},
{Key: "yandex", Name: "Yandex", Kind: types.ChromiumYandex, UserDataDir: yandexDir},
},
wantNames: []string{"Yandex"},
wantProfiles: []string{"Default"},
@@ -126,7 +126,7 @@ func TestPickFromConfigs_BrowserKind(t *testing.T) {
{
name: "nonexistent dir",
configs: []types.BrowserConfig{
{Key: "chrome", Name: "Chrome", Kind: types.KindChromium, UserDataDir: "/nonexistent"},
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: "/nonexistent"},
},
},
}
@@ -164,7 +164,7 @@ func TestPickFromConfigs_ProfilePath(t *testing.T) {
{
name: "chromium uses path directly",
configs: []types.BrowserConfig{
{Key: "chrome", Name: "Chrome", Kind: types.KindChromium, UserDataDir: "/wrong"},
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: "/wrong"},
},
pickName: "chrome",
profilePath: filepath.Join(chromeDir, "Default"),
@@ -174,7 +174,7 @@ func TestPickFromConfigs_ProfilePath(t *testing.T) {
{
name: "firefox uses parent dir",
configs: []types.BrowserConfig{
{Key: "firefox", Name: "Firefox", Kind: types.KindFirefox, UserDataDir: "/wrong"},
{Key: "firefox", Name: "Firefox", Kind: types.Firefox, UserDataDir: "/wrong"},
},
pickName: "firefox",
profilePath: filepath.Join(firefoxDir, "abc123.default-release"),
@@ -184,7 +184,7 @@ func TestPickFromConfigs_ProfilePath(t *testing.T) {
{
name: "ignored when name is all",
configs: []types.BrowserConfig{
{Key: "chrome", Name: "Chrome", Kind: types.KindChromium, UserDataDir: chromeDir},
{Key: "chrome", Name: "Chrome", Kind: types.Chromium, UserDataDir: chromeDir},
},
pickName: "all",
profilePath: "/some/override",
+18 -18
View File
@@ -11,97 +11,97 @@ func platformBrowsers() []types.BrowserConfig {
{
Key: "chrome",
Name: chromeName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/Google/Chrome/User Data",
},
{
Key: "edge",
Name: edgeName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/Microsoft/Edge/User Data",
},
{
Key: "chromium",
Name: chromiumName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/Chromium/User Data",
},
{
Key: "chrome-beta",
Name: chromeBetaName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/Google/Chrome Beta/User Data",
},
{
Key: "opera",
Name: operaName,
Kind: types.KindChromiumOpera,
Kind: types.ChromiumOpera,
UserDataDir: homeDir + "/AppData/Roaming/Opera Software/Opera Stable",
},
{
Key: "opera-gx",
Name: operaGXName,
Kind: types.KindChromiumOpera,
Kind: types.ChromiumOpera,
UserDataDir: homeDir + "/AppData/Roaming/Opera Software/Opera GX Stable",
},
{
Key: "vivaldi",
Name: vivaldiName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/Vivaldi/User Data",
},
{
Key: "coccoc",
Name: coccocName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/CocCoc/Browser/User Data",
},
{
Key: "brave",
Name: braveName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/BraveSoftware/Brave-Browser/User Data",
},
{
Key: "yandex",
Name: yandexName,
Kind: types.KindChromiumYandex,
Kind: types.ChromiumYandex,
UserDataDir: homeDir + "/AppData/Local/Yandex/YandexBrowser/User Data",
},
{
Key: "360x",
Name: speed360XName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/360ChromeX/Chrome/User Data",
},
{
Key: "360",
Name: speed360Name,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/360chrome/Chrome/User Data",
},
{
Key: "qq",
Name: qqBrowserName,
Kind: types.KindChromium,
Name: qqName,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/Tencent/QQBrowser/User Data",
},
{
Key: "dc",
Name: dcBrowserName,
Kind: types.KindChromium,
Name: dcName,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/DCBrowser/User Data",
},
{
Key: "sogou",
Name: sogouName,
Kind: types.KindChromium,
Kind: types.Chromium,
UserDataDir: homeDir + "/AppData/Local/Sogou/SogouExplorer/User Data",
},
{
Key: "firefox",
Name: firefoxName,
Kind: types.KindFirefox,
Kind: types.Firefox,
UserDataDir: homeDir + "/AppData/Roaming/Mozilla/Firefox/Profiles",
},
}
+17 -1
View File
@@ -3,6 +3,7 @@ package chromium
import (
"os"
"path/filepath"
"time"
"github.com/moond4rk/hackbrowserdata/crypto/keyretriever"
"github.com/moond4rk/hackbrowserdata/filemanager"
@@ -125,7 +126,7 @@ func (b *Browser) getMasterKey(session *filemanager.Session) ([]byte, error) {
var localStateDst string
for _, dir := range []string{filepath.Dir(b.profileDir), b.profileDir} {
candidate := filepath.Join(dir, "Local State")
if fileutil.IsFileExists(candidate) {
if fileutil.FileExists(candidate) {
localStateDst = filepath.Join(session.TempDir(), "Local State")
if err := session.Acquire(candidate, localStateDst, false); err != nil {
return nil, err
@@ -273,3 +274,18 @@ func isSkippedDir(name string) bool {
}
return false
}
// timeEpoch converts a WebKit/Chromium epoch timestamp (microseconds since
// 1601-01-01) to a time.Time.
func timeEpoch(epoch int64) time.Time {
maxTime := int64(99633311740000000)
if epoch > maxTime {
return time.Date(2049, 1, 1, 1, 1, 1, 1, time.Local)
}
t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.Local)
d := time.Duration(epoch)
for i := 0; i < 1000; i++ {
t = t.Add(d)
}
return t
}
+16 -16
View File
@@ -142,7 +142,7 @@ func TestNewBrowsers(t *testing.T) {
{
name: "chrome multi-profile",
dir: fixture.chrome,
kind: types.KindChromium,
kind: types.Chromium,
wantProfiles: []string{"Default", "Profile 1", "Profile 3"},
wantCats: map[string][]string{
"Default": {"Login Data", "Cookies", "History", "Bookmarks", "Web Data", "Secure Preferences", "leveldb", "Session Storage"},
@@ -153,7 +153,7 @@ func TestNewBrowsers(t *testing.T) {
{
name: "opera with Default",
dir: fixture.opera,
kind: types.KindChromium,
kind: types.Chromium,
wantProfiles: []string{"Default"},
wantCats: map[string][]string{
"Default": {"Login Data", "History", "Bookmarks", "Cookies"},
@@ -162,7 +162,7 @@ func TestNewBrowsers(t *testing.T) {
{
name: "opera flat layout",
dir: fixture.operaFlat,
kind: types.KindChromium,
kind: types.Chromium,
wantProfiles: []string{filepath.Base(fixture.operaFlat)}, // userDataDir itself
wantCats: map[string][]string{
filepath.Base(fixture.operaFlat): {"Login Data", "History", "Cookies"},
@@ -171,7 +171,7 @@ func TestNewBrowsers(t *testing.T) {
{
name: "yandex custom files",
dir: fixture.yandex,
kind: types.KindChromiumYandex,
kind: types.ChromiumYandex,
wantProfiles: []string{"Default"},
wantCats: map[string][]string{
"Default": {"Ya Passman Data", "Ya Credit Cards", "History", "Cookies", "Bookmarks"},
@@ -180,38 +180,38 @@ func TestNewBrowsers(t *testing.T) {
{
name: "old cookies fallback",
dir: fixture.oldCookies,
kind: types.KindChromium,
kind: types.Chromium,
wantProfiles: []string{"Default"},
},
{
name: "cookie priority",
dir: fixture.bothCookies,
kind: types.KindChromium,
kind: types.Chromium,
wantProfiles: []string{"Default"},
},
{
name: "leveldb directories",
dir: fixture.leveldb,
kind: types.KindChromium,
kind: types.Chromium,
wantProfiles: []string{"Default"},
wantDirs: []types.Category{types.LocalStorage, types.SessionStorage},
},
{
name: "leveldb only",
dir: fixture.leveldbOnly,
kind: types.KindChromium,
kind: types.Chromium,
wantProfiles: []string{"Default"},
wantDirs: []types.Category{types.LocalStorage, types.SessionStorage},
},
{
name: "empty dir",
dir: fixture.empty,
kind: types.KindChromium,
kind: types.Chromium,
},
{
name: "nonexistent dir",
dir: "/nonexistent/path",
kind: types.KindChromium,
kind: types.Chromium,
},
}
@@ -321,8 +321,8 @@ func TestSharedSourceFile(t *testing.T) {
// ---------------------------------------------------------------------------
func TestSourcesForKind(t *testing.T) {
chromium := sourcesForKind(types.KindChromium)
yandex := sourcesForKind(types.KindChromiumYandex)
chromium := sourcesForKind(types.Chromium)
yandex := sourcesForKind(types.ChromiumYandex)
assert.Equal(t, "Login Data", chromium[types.Password][0].rel)
assert.Equal(t, "Ya Passman Data", yandex[types.Password][0].rel)
@@ -331,13 +331,13 @@ func TestSourcesForKind(t *testing.T) {
}
func TestExtractorsForKind(t *testing.T) {
assert.Nil(t, extractorsForKind(types.KindChromium))
assert.Nil(t, extractorsForKind(types.Chromium))
yandexExt := extractorsForKind(types.KindChromiumYandex)
yandexExt := extractorsForKind(types.ChromiumYandex)
require.NotNil(t, yandexExt)
assert.Contains(t, yandexExt, types.Password)
operaExt := extractorsForKind(types.KindChromiumOpera)
operaExt := extractorsForKind(types.ChromiumOpera)
require.NotNil(t, operaExt)
assert.Contains(t, operaExt, types.Extension)
}
@@ -425,7 +425,7 @@ func TestLocalStatePath(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
browsers, err := NewBrowsers(types.BrowserConfig{Name: "Test", Kind: types.KindChromium, UserDataDir: tt.dir})
browsers, err := NewBrowsers(types.BrowserConfig{Name: "Test", Kind: types.Chromium, UserDataDir: tt.dir})
require.NoError(t, err)
require.NotEmpty(t, browsers)
+2 -2
View File
@@ -17,12 +17,12 @@ func decryptValue(masterKey, ciphertext []byte) ([]byte, error) {
version := crypto.DetectVersion(ciphertext)
switch version {
case crypto.CipherV10:
return crypto.DecryptWithChromium(masterKey, ciphertext)
return crypto.DecryptChromium(masterKey, ciphertext)
case crypto.CipherV20:
// TODO: implement App-Bound Encryption (Chrome 127+)
return nil, fmt.Errorf("v20 App-Bound Encryption not yet supported")
case crypto.CipherDPAPI:
return crypto.DecryptWithDPAPI(ciphertext)
return crypto.DecryptDPAPI(ciphertext)
default:
return nil, fmt.Errorf("unsupported cipher version: %s", version)
}
+4 -6
View File
@@ -12,14 +12,12 @@ import (
"github.com/moond4rk/hackbrowserdata/crypto"
)
// testCBCIV is the fixed IV Chrome uses on macOS/Linux (16 space bytes).
var testCBCIV = bytes.Repeat([]byte{0x20}, 16)
func TestDecryptValue_V10(t *testing.T) {
plaintext := []byte("test_secret_value")
encrypted, err := crypto.AES128CBCEncrypt(testAESKey, testCBCIV, plaintext)
testCBCIV := bytes.Repeat([]byte{0x20}, 16)
cbcEncrypted, err := crypto.AESCBCEncrypt(testAESKey, testCBCIV, plaintext)
require.NoError(t, err)
v10Ciphertext := append([]byte("v10"), encrypted...)
v10Ciphertext := append([]byte("v10"), cbcEncrypted...)
tests := []struct {
name string
@@ -35,7 +33,7 @@ func TestDecryptValue_V10(t *testing.T) {
{
name: "wrong key returns padding error",
key: []byte("wrong_key_1234!!"),
wantErrMsg: "pkcs5UnPadding",
wantErrMsg: "invalid PKCS5 padding",
},
}
+3 -3
View File
@@ -15,7 +15,7 @@ import (
)
// encryptWithDPAPI encrypts data using Windows DPAPI (CryptProtectData).
// This is the reverse of crypto.DecryptWithDPAPI, used only for testing.
// This is the reverse of DecryptDPAPI, used only for testing.
func encryptWithDPAPI(plaintext []byte) ([]byte, error) {
crypt32 := syscall.NewLazyDLL("Crypt32.dll")
kernel32 := syscall.NewLazyDLL("Kernel32.dll")
@@ -57,11 +57,11 @@ func TestDecryptValue_V10_Windows(t *testing.T) {
plaintext := []byte("test_secret_value")
nonce := []byte("123456789012") // 12-byte nonce
encrypted, err := crypto.AESGCMEncrypt(testAESKey, nonce, plaintext)
gcmEncrypted, err := crypto.AESGCMEncrypt(testAESKey, nonce, plaintext)
require.NoError(t, err)
// v10 format on Windows: "v10" + nonce(12) + encrypted
ciphertext := append([]byte("v10"), append(nonce, encrypted...)...)
ciphertext := append([]byte("v10"), append(nonce, gcmEncrypted...)...)
got, err := decryptValue(testAESKey, ciphertext)
require.NoError(t, err)
+1 -2
View File
@@ -7,7 +7,6 @@ import (
"github.com/tidwall/gjson"
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
func extractBookmarks(path string) ([]types.BookmarkEntry, error) {
@@ -39,7 +38,7 @@ func walkBookmarks(node gjson.Result, folder string, out *[]types.BookmarkEntry)
Type: nodeType,
URL: node.Get("url").String(),
Folder: folder,
CreatedAt: typeutil.TimeEpoch(node.Get("date_added").Int()),
CreatedAt: timeEpoch(node.Get("date_added").Int()),
})
}
+2 -3
View File
@@ -9,7 +9,6 @@ import (
"github.com/moond4rk/hackbrowserdata/log"
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const defaultCookieQuery = `SELECT name, encrypted_value, host_key, path,
@@ -46,8 +45,8 @@ func extractCookies(masterKey []byte, path string) ([]types.CookieEntry, error)
IsHTTPOnly: isHTTPOnly != 0,
HasExpire: hasExpire != 0,
IsPersistent: isPersistent != 0,
ExpireAt: typeutil.TimeEpoch(expireAt),
CreatedAt: typeutil.TimeEpoch(createdAt),
ExpireAt: timeEpoch(expireAt),
CreatedAt: timeEpoch(createdAt),
}, nil
})
if err != nil {
+3 -3
View File
@@ -14,9 +14,9 @@ const defaultCreditCardQuery = `SELECT COALESCE(guid, ''), name_on_card, expirat
func extractCreditCards(masterKey []byte, path string) ([]types.CreditCardEntry, error) {
return sqliteutil.QueryRows(path, false, defaultCreditCardQuery,
func(rows *sql.Rows) (types.CreditCardEntry, error) {
var guid, name, month, year, nickName, address string
var guid, name, month, year, nickname, address string
var encNumber []byte
if err := rows.Scan(&guid, &name, &month, &year, &encNumber, &nickName, &address); err != nil {
if err := rows.Scan(&guid, &name, &month, &year, &encNumber, &nickname, &address); err != nil {
return types.CreditCardEntry{}, err
}
number, err := decryptValue(masterKey, encNumber)
@@ -29,7 +29,7 @@ func extractCreditCards(masterKey []byte, path string) ([]types.CreditCardEntry,
Number: string(number),
ExpMonth: month,
ExpYear: year,
NickName: nickName,
NickName: nickname,
Address: address,
}, nil
})
+2 -3
View File
@@ -6,7 +6,6 @@ import (
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const defaultDownloadQuery = `SELECT target_path, tab_url, total_bytes, start_time, end_time,
@@ -25,8 +24,8 @@ func extractDownloads(path string) ([]types.DownloadEntry, error) {
TargetPath: targetPath,
MimeType: mimeType,
TotalBytes: totalBytes,
StartTime: typeutil.TimeEpoch(startTime),
EndTime: typeutil.TimeEpoch(endTime),
StartTime: timeEpoch(startTime),
EndTime: timeEpoch(endTime),
}, nil
})
if err != nil {
+1 -2
View File
@@ -6,7 +6,6 @@ import (
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const defaultHistoryQuery = `SELECT url, title, visit_count, last_visit_time FROM urls`
@@ -24,7 +23,7 @@ func extractHistories(path string) ([]types.HistoryEntry, error) {
URL: url,
Title: title,
VisitCount: visitCount,
LastVisit: typeutil.TimeEpoch(lastVisit),
LastVisit: timeEpoch(lastVisit),
}, nil
})
if err != nil {
+1 -2
View File
@@ -7,7 +7,6 @@ import (
"github.com/moond4rk/hackbrowserdata/log"
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const defaultLoginQuery = `SELECT origin_url, username_value, password_value, date_created FROM logins`
@@ -33,7 +32,7 @@ func extractPasswordsWithQuery(masterKey []byte, path, query string) ([]types.Lo
URL: url,
Username: username,
Password: string(password),
CreatedAt: typeutil.TimeEpoch(created),
CreatedAt: timeEpoch(created),
}, nil
})
if err != nil {
+3 -3
View File
@@ -52,7 +52,7 @@ func yandexSources() map[types.Category][]sourcePath {
// sourcesForKind returns the source mapping for a browser kind.
func sourcesForKind(kind types.BrowserKind) map[types.Category][]sourcePath {
switch kind {
case types.KindChromiumYandex:
case types.ChromiumYandex:
return yandexSources()
default:
return chromiumSources
@@ -109,9 +109,9 @@ var operaExtractors = map[types.Category]categoryExtractor{
// nil means all categories use the default extractCategory switch logic.
func extractorsForKind(kind types.BrowserKind) map[types.Category]categoryExtractor {
switch kind {
case types.KindChromiumYandex:
case types.ChromiumYandex:
return yandexExtractors
case types.KindChromiumOpera:
case types.ChromiumOpera:
return operaExtractors
default:
return nil
+2 -2
View File
@@ -21,8 +21,8 @@ const (
firefoxName = "Firefox"
speed360Name = "360 Speed"
speed360XName = "360 Speed X"
qqBrowserName = "QQ"
dcBrowserName = "DC"
qqName = "QQ"
dcName = "DC"
sogouName = "Sogou"
arcName = "Arc"
)
+1 -2
View File
@@ -6,7 +6,6 @@ import (
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const firefoxBookmarkQuery = `SELECT id, url, type, dateAdded, COALESCE(title, '')
@@ -25,7 +24,7 @@ func extractBookmarks(path string) ([]types.BookmarkEntry, error) {
Name: title,
URL: url,
Folder: bookmarkType(bt),
CreatedAt: typeutil.TimeStamp(dateAdded / 1000000),
CreatedAt: timestamp(dateAdded / 1000000),
}, nil
})
if err != nil {
+2 -3
View File
@@ -6,7 +6,6 @@ import (
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const firefoxCookieQuery = `SELECT name, value, host, path,
@@ -34,8 +33,8 @@ func extractCookies(path string) ([]types.CookieEntry, error) {
IsHTTPOnly: isHTTPOnly != 0,
HasExpire: hasExpire,
IsPersistent: hasExpire,
ExpireAt: typeutil.TimeStamp(expiry),
CreatedAt: typeutil.TimeStamp(createdAt / 1000000),
ExpireAt: timestamp(expiry),
CreatedAt: timestamp(createdAt / 1000000),
}, nil
})
if err != nil {
+2 -3
View File
@@ -9,7 +9,6 @@ import (
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const firefoxDownloadQuery = `SELECT place_id, GROUP_CONCAT(content), url, dateAdded
@@ -27,7 +26,7 @@ func extractDownloads(path string) ([]types.DownloadEntry, error) {
entry := types.DownloadEntry{
URL: url,
StartTime: typeutil.TimeStamp(dateAdded / 1000000),
StartTime: timestamp(dateAdded / 1000000),
}
// Firefox stores download metadata as: "target_path,{json}"
@@ -37,7 +36,7 @@ func extractDownloads(path string) ([]types.DownloadEntry, error) {
entry.TargetPath = contentList[0]
json := "{" + contentList[1]
entry.TotalBytes = gjson.Get(json, "fileSize").Int()
entry.EndTime = typeutil.TimeStamp(gjson.Get(json, "endTime").Int() / 1000)
entry.EndTime = timestamp(gjson.Get(json, "endTime").Int() / 1000)
} else {
entry.TargetPath = content
}
+1 -2
View File
@@ -6,7 +6,6 @@ import (
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const firefoxHistoryQuery = `SELECT url, COALESCE(last_visit_date, 0),
@@ -25,7 +24,7 @@ func extractHistories(path string) ([]types.HistoryEntry, error) {
URL: url,
Title: title,
VisitCount: visitCount,
LastVisit: typeutil.TimeStamp(lastVisit / 1000000),
LastVisit: timestamp(lastVisit / 1000000),
}, nil
})
if err != nil {
+1 -2
View File
@@ -11,7 +11,6 @@ import (
"github.com/moond4rk/hackbrowserdata/crypto"
"github.com/moond4rk/hackbrowserdata/log"
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
// decryptPBE combines base64 decode + ASN1 PBE parse + decrypt into one call.
@@ -57,7 +56,7 @@ func extractPasswords(masterKey []byte, path string) ([]types.LoginEntry, error)
URL: url,
Username: string(user),
Password: string(pwd),
CreatedAt: typeutil.TimeStamp(v.Get("timeCreated").Int() / 1000),
CreatedAt: timestamp(v.Get("timeCreated").Int() / 1000),
})
}
+9 -2
View File
@@ -7,7 +7,6 @@ import (
"github.com/moond4rk/hackbrowserdata/types"
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
"github.com/moond4rk/hackbrowserdata/utils/typeutil"
)
const firefoxLocalStorageQuery = `SELECT originKey, key, value FROM webappsstore2`
@@ -27,6 +26,14 @@ func extractLocalStorage(path string) ([]types.StorageEntry, error) {
})
}
func reverseString(s string) string {
b := []byte(s)
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
b[i], b[j] = b[j], b[i]
}
return string(b)
}
// parseOriginKey converts Firefox's reversed origin format to a URL.
// Example: "moc.buhtig.:https:443" → "https://github.com:443"
func parseOriginKey(originKey string) string {
@@ -34,7 +41,7 @@ func parseOriginKey(originKey string) string {
if len(parts) < 2 {
return originKey
}
host := string(typeutil.Reverse([]byte(parts[0])))
host := reverseString(parts[0])
host = strings.TrimPrefix(host, ".")
scheme := parts[1]
if len(parts) == 3 {
+11 -1
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"time"
"github.com/moond4rk/hackbrowserdata/filemanager"
"github.com/moond4rk/hackbrowserdata/log"
@@ -106,7 +107,7 @@ func (b *Browser) acquireFiles(session *filemanager.Session, categories []types.
// is validated by attempting to decrypt an actual login entry.
func (b *Browser) getMasterKey(session *filemanager.Session, tempPaths map[types.Category]string) ([]byte, error) {
key4Src := filepath.Join(b.profileDir, "key4.db")
if !fileutil.IsFileExists(key4Src) {
if !fileutil.FileExists(key4Src) {
return nil, nil
}
key4Dst := filepath.Join(session.TempDir(), "key4.db")
@@ -236,3 +237,12 @@ func resolveSourcePaths(sources map[types.Category][]sourcePath, profileDir stri
}
return resolved
}
// timestamp converts a Unix epoch timestamp (seconds) to a time.Time.
func timestamp(stamp int64) time.Time {
s := time.Unix(stamp, 0)
if s.Local().Year() > 9999 {
return time.Date(9999, 12, 13, 23, 59, 59, 0, time.Local)
}
return s
}
+1 -1
View File
@@ -115,7 +115,7 @@ func TestNewBrowsers(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := types.BrowserConfig{Name: "Firefox", Kind: types.KindFirefox, UserDataDir: tt.dir}
cfg := types.BrowserConfig{Name: "Firefox", Kind: types.Firefox, UserDataDir: tt.dir}
browsers, err := NewBrowsers(cfg)
require.NoError(t, err)