mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
chore: update golangci-lint config and fix lint issues (#542)
* chore: update golangci-lint config and fix lint issues
This commit is contained in:
+32
-66
@@ -10,7 +10,7 @@ run:
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
# Default tier
|
||||
# Default tier — must-have for any Go project
|
||||
- errcheck
|
||||
- govet
|
||||
- staticcheck
|
||||
@@ -21,11 +21,18 @@ linters:
|
||||
- errorlint
|
||||
- gosec
|
||||
- sqlclosecheck
|
||||
- nilerr
|
||||
- bodyclose
|
||||
- durationcheck
|
||||
- errchkjson
|
||||
- exhaustive
|
||||
- forcetypeassert
|
||||
|
||||
# Code quality
|
||||
- depguard
|
||||
- dogsled
|
||||
- dupl
|
||||
- dupword
|
||||
- errname
|
||||
- funlen
|
||||
- gocheckcompilerdirectives
|
||||
@@ -35,20 +42,24 @@ linters:
|
||||
- godox
|
||||
- goprintffuncname
|
||||
- lll
|
||||
- mirror
|
||||
- misspell
|
||||
- nakedret
|
||||
- predeclared
|
||||
- revive
|
||||
- testifylint
|
||||
- unconvert
|
||||
- unparam
|
||||
- usestdlibvars
|
||||
- wastedassign
|
||||
- whitespace
|
||||
|
||||
# Complexity
|
||||
- gocognit
|
||||
- nestif
|
||||
|
||||
# Note: copyloopvar, intrange, modernize, perfsprint require Go 1.22+
|
||||
# They will be enabled when Go version constraint is lifted
|
||||
# They will be enabled when Go version constraint is lifted.
|
||||
|
||||
settings:
|
||||
depguard:
|
||||
@@ -61,6 +72,8 @@ linters:
|
||||
desc: Deprecated since Go 1.16. Use io and os packages instead.
|
||||
- pkg: "github.com/instana/testify"
|
||||
desc: Use github.com/stretchr/testify instead.
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
dupl:
|
||||
threshold: 100
|
||||
funlen:
|
||||
@@ -82,17 +95,15 @@ linters:
|
||||
disabled-checks:
|
||||
- dupImport
|
||||
- hugeParam
|
||||
- rangeValCopy
|
||||
- ifElseChain
|
||||
- octalLiteral
|
||||
- rangeValCopy # keychainbreaker structs are large by design
|
||||
- unnamedResult # crypto functions returning (key, iv) are clear without names
|
||||
- whyNoLint
|
||||
- singleCaseSwitch
|
||||
- exitAfterDefer
|
||||
- commentedOutCode
|
||||
lll:
|
||||
line-length: 140
|
||||
gocognit:
|
||||
min-complexity: 30
|
||||
nestif:
|
||||
min-complexity: 5
|
||||
godox:
|
||||
keywords:
|
||||
- FIXME
|
||||
@@ -103,17 +114,17 @@ linters:
|
||||
asserts: false
|
||||
gosec:
|
||||
excludes:
|
||||
- G101
|
||||
- G104
|
||||
- G304
|
||||
- G401
|
||||
- G405
|
||||
- G501
|
||||
- G502
|
||||
- G505
|
||||
- G115
|
||||
- G117
|
||||
- G204
|
||||
- G101 # hardcoded credentials — false positives on const names
|
||||
- G115 # integer overflow on conversion — false positives on safe narrowing
|
||||
- G117 # struct field matches secret pattern — false positive on Password fields
|
||||
- G204 # exec.Command with variable — required for macOS `security` command
|
||||
- G304 # file inclusion via variable — required for dynamic browser paths
|
||||
- G401 # weak crypto SHA1 — required for Chromium PBKDF2 key derivation
|
||||
- G402 # TLS MinVersion — not applicable (no TLS in this tool)
|
||||
- G405 # weak crypto DES — required for Firefox 3DES decryption
|
||||
- G501 # blocklisted import crypto/md5 — not used, keep for safety
|
||||
- G502 # blocklisted import crypto/des — required for Firefox decryption
|
||||
- G505 # blocklisted import crypto/sha1 — required for PBKDF2
|
||||
errcheck:
|
||||
check-type-assertions: true
|
||||
exclude-functions:
|
||||
@@ -127,22 +138,13 @@ linters:
|
||||
rules:
|
||||
- name: indent-error-flow
|
||||
- name: unexported-return
|
||||
disabled: true
|
||||
- name: unused-parameter
|
||||
disabled: true
|
||||
- name: package-comments
|
||||
disabled: true
|
||||
- name: exported
|
||||
disabled: true
|
||||
staticcheck:
|
||||
checks:
|
||||
- "all"
|
||||
- "-ST1000"
|
||||
- "-ST1003"
|
||||
- "-ST1016"
|
||||
- "-ST1020"
|
||||
- "-ST1021"
|
||||
- "-ST1022"
|
||||
- "-ST1000" # package comment — not a public library
|
||||
- "-ST1003" # naming convention — allow platform-specific names
|
||||
|
||||
exclusions:
|
||||
presets:
|
||||
@@ -157,7 +159,6 @@ linters:
|
||||
- funlen
|
||||
- gosec
|
||||
- errcheck
|
||||
- testifylint
|
||||
- lll
|
||||
- source: "defer"
|
||||
linters:
|
||||
@@ -165,47 +166,12 @@ linters:
|
||||
- text: "SELECT"
|
||||
linters:
|
||||
- gosec
|
||||
# Temporary: known issues in pre-refactoring code (will be removed during refactoring)
|
||||
- text: "result 0 .* is always nil"
|
||||
linters:
|
||||
- unparam
|
||||
- text: "result 0 .* is never used"
|
||||
linters:
|
||||
- unparam
|
||||
- path: "browser/firefox/firefox.go"
|
||||
text: "field .* is unused"
|
||||
linters:
|
||||
- unused
|
||||
- path: "browserdata/sessionstorage/"
|
||||
text: "is unused"
|
||||
linters:
|
||||
- unused
|
||||
- path: "cmd/hack-browser-data/main.go"
|
||||
linters:
|
||||
- lll
|
||||
# Temporary: pre-refactoring code issues (all will be rewritten)
|
||||
- path: "browserdata/"
|
||||
linters:
|
||||
- dupl
|
||||
- gochecknoinits
|
||||
- goconst
|
||||
- lll
|
||||
- path: "browser/firefox/"
|
||||
linters:
|
||||
- gocritic
|
||||
- path: "crypto/"
|
||||
linters:
|
||||
- gocritic
|
||||
- path: "crypto/keyretriever/gcoredump_darwin.go"
|
||||
linters:
|
||||
- gocognit
|
||||
# Temporary: new v2 extract files have no callers until Phase 8 wiring
|
||||
- path: "browser/chromium/(source|decrypt|extract_.*)\\.go"
|
||||
linters:
|
||||
- unused
|
||||
- path: "browser/firefox/(source|extract_.*)\\.go"
|
||||
linters:
|
||||
- unused
|
||||
|
||||
formatters:
|
||||
enable:
|
||||
|
||||
@@ -21,7 +21,7 @@ func mkFile(t *testing.T, parts ...string) {
|
||||
|
||||
func TestListBrowsers(t *testing.T) {
|
||||
list := ListBrowsers()
|
||||
assert.True(t, len(list) > 0)
|
||||
assert.NotEmpty(t, list)
|
||||
assert.True(t, sort.StringsAreSorted(list))
|
||||
}
|
||||
|
||||
|
||||
@@ -399,7 +399,7 @@ func TestAcquireFiles(t *testing.T) {
|
||||
assert.Len(t, paths, len(cats))
|
||||
for _, p := range paths {
|
||||
_, err := os.Stat(p)
|
||||
assert.NoError(t, err, "acquired file should exist")
|
||||
require.NoError(t, err, "acquired file should exist")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,5 +40,5 @@ func TestExtractHistories_NullFields(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got, 1)
|
||||
assert.Equal(t, "https://null.test", got[0].URL)
|
||||
assert.Equal(t, "", got[0].Title)
|
||||
assert.Empty(t, got[0].Title)
|
||||
}
|
||||
|
||||
+23
-22
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -74,14 +75,14 @@ var (
|
||||
func TestNewASN1PBE(t *testing.T) {
|
||||
for _, tc := range nssPBETestCases {
|
||||
nssRaw, err := hex.DecodeString(tc.RawHexPBE)
|
||||
assert.Equal(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
pbe, err := NewASN1PBE(nssRaw)
|
||||
assert.Equal(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
nssPBETC, ok := pbe.(nssPBE)
|
||||
assert.Equal(t, true, ok)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, nssPBETC.Encrypted, tc.Encrypted)
|
||||
assert.Equal(t, nssPBETC.AlgoAttr.SaltAttr.EntrySalt, tc.GlobalSalt)
|
||||
assert.Equal(t, nssPBETC.AlgoAttr.SaltAttr.Len, 20)
|
||||
assert.Equal(t, 20, nssPBETC.AlgoAttr.SaltAttr.Len)
|
||||
assert.Equal(t, nssPBETC.AlgoAttr.ObjectIdentifier, tc.ObjectIdentifier)
|
||||
}
|
||||
}
|
||||
@@ -108,8 +109,8 @@ func TestNssPBE_Encrypt(t *testing.T) {
|
||||
},
|
||||
}
|
||||
encrypted, err := nssPBETC.Encrypt(tc.GlobalSalt, tc.Plaintext)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(encrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, encrypted)
|
||||
assert.Equal(t, nssPBETC.Encrypted, encrypted)
|
||||
}
|
||||
}
|
||||
@@ -136,8 +137,8 @@ func TestNssPBE_Decrypt(t *testing.T) {
|
||||
},
|
||||
}
|
||||
decrypted, err := nssPBETC.Decrypt(tc.GlobalSalt)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(decrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, decrypted)
|
||||
assert.Equal(t, pbePlaintext, decrypted)
|
||||
}
|
||||
}
|
||||
@@ -145,11 +146,11 @@ func TestNssPBE_Decrypt(t *testing.T) {
|
||||
func TestNewASN1PBE_MetaPBE(t *testing.T) {
|
||||
for _, tc := range metaPBETestCases {
|
||||
metaRaw, err := hex.DecodeString(tc.RawHexPBE)
|
||||
assert.Equal(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
pbe, err := NewASN1PBE(metaRaw)
|
||||
assert.Equal(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
metaPBETC, ok := pbe.(metaPBE)
|
||||
assert.Equal(t, true, ok)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, metaPBETC.Encrypted, tc.Encrypted)
|
||||
assert.Equal(t, metaPBETC.AlgoAttr.Data.IVData.IV, tc.IV)
|
||||
assert.Equal(t, metaPBETC.AlgoAttr.Data.IVData.ObjectIdentifier, objWithSHA256AndAES)
|
||||
@@ -193,8 +194,8 @@ func TestMetaPBE_Encrypt(t *testing.T) {
|
||||
Encrypted: tc.Encrypted,
|
||||
}
|
||||
encrypted, err := metaPBETC.Encrypt(tc.GlobalSalt, tc.Plaintext)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(encrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, encrypted)
|
||||
assert.Equal(t, metaPBETC.Encrypted, encrypted)
|
||||
}
|
||||
}
|
||||
@@ -236,8 +237,8 @@ func TestMetaPBE_Decrypt(t *testing.T) {
|
||||
Encrypted: tc.Encrypted,
|
||||
}
|
||||
decrypted, err := metaPBETC.Decrypt(tc.GlobalSalt)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(decrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, decrypted)
|
||||
assert.Equal(t, pbePlaintext, decrypted)
|
||||
}
|
||||
}
|
||||
@@ -245,11 +246,11 @@ func TestMetaPBE_Decrypt(t *testing.T) {
|
||||
func TestNewASN1PBE_LoginPBE(t *testing.T) {
|
||||
for _, tc := range loginPBETestCases {
|
||||
loginRaw, err := hex.DecodeString(tc.RawHexPBE)
|
||||
assert.Equal(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
pbe, err := NewASN1PBE(loginRaw)
|
||||
assert.Equal(t, nil, err)
|
||||
require.NoError(t, err)
|
||||
loginPBETC, ok := pbe.(loginPBE)
|
||||
assert.Equal(t, true, ok)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, loginPBETC.Encrypted, tc.Encrypted)
|
||||
assert.Equal(t, loginPBETC.Data.IV, tc.IV)
|
||||
assert.Equal(t, loginPBETC.Data.ObjectIdentifier, objWithMD5AndDESCBC)
|
||||
@@ -270,8 +271,8 @@ func TestLoginPBE_Encrypt(t *testing.T) {
|
||||
Encrypted: tc.Encrypted,
|
||||
}
|
||||
encrypted, err := loginPBETC.Encrypt(tc.GlobalSalt, plainText)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(encrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, encrypted)
|
||||
assert.Equal(t, loginPBETC.Encrypted, encrypted)
|
||||
}
|
||||
}
|
||||
@@ -290,8 +291,8 @@ func TestLoginPBE_Decrypt(t *testing.T) {
|
||||
Encrypted: tc.Encrypted,
|
||||
}
|
||||
decrypted, err := loginPBETC.Decrypt(tc.GlobalSalt)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(decrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, decrypted)
|
||||
assert.Equal(t, pbePlaintext, decrypted)
|
||||
}
|
||||
}
|
||||
|
||||
+13
-12
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const baseKey = "moond4rk"
|
||||
@@ -28,45 +29,45 @@ var (
|
||||
|
||||
func TestAES128CBCEncrypt(t *testing.T) {
|
||||
encrypted, err := AES128CBCEncrypt(aesKey, aesIV, plainText)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(encrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, encrypted)
|
||||
assert.Equal(t, aes128Ciphertext, fmt.Sprintf("%x", encrypted))
|
||||
}
|
||||
|
||||
func TestAES128CBCDecrypt(t *testing.T) {
|
||||
ciphertext, _ := hex.DecodeString(aes128Ciphertext)
|
||||
decrypted, err := AES128CBCDecrypt(aesKey, aesIV, ciphertext)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(decrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, decrypted)
|
||||
assert.Equal(t, plainText, decrypted)
|
||||
}
|
||||
|
||||
func TestDES3Encrypt(t *testing.T) {
|
||||
encrypted, err := DES3Encrypt(des3Key, des3IV, plainText)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(encrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, encrypted)
|
||||
assert.Equal(t, des3Ciphertext, fmt.Sprintf("%x", encrypted))
|
||||
}
|
||||
|
||||
func TestDES3Decrypt(t *testing.T) {
|
||||
ciphertext, _ := hex.DecodeString(des3Ciphertext)
|
||||
decrypted, err := DES3Decrypt(des3Key, des3IV, ciphertext)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(decrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, decrypted)
|
||||
assert.Equal(t, plainText, decrypted)
|
||||
}
|
||||
|
||||
func TestAESGCMEncrypt(t *testing.T) {
|
||||
encrypted, err := AESGCMEncrypt(aesKey, aesGCMNonce, plainText)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(encrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, encrypted)
|
||||
assert.Equal(t, aesGCMCiphertext, fmt.Sprintf("%x", encrypted))
|
||||
}
|
||||
|
||||
func TestAESGCMDecrypt(t *testing.T) {
|
||||
ciphertext, _ := hex.DecodeString(aesGCMCiphertext)
|
||||
decrypted, err := AESGCMDecrypt(aesKey, aesGCMNonce, ciphertext)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, len(decrypted) > 0)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, decrypted)
|
||||
assert.Equal(t, plainText, decrypted)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestChainRetriever_AllFail(t *testing.T) {
|
||||
&mockRetriever{err: errors.New("second failed")},
|
||||
)
|
||||
key, err := chain.RetrieveKey("Chrome", "")
|
||||
assert.Error(t, err)
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, key)
|
||||
assert.Contains(t, err.Error(), "all retrievers failed")
|
||||
assert.Contains(t, err.Error(), "first failed")
|
||||
@@ -64,6 +64,6 @@ func TestChainRetriever_SkipEmptyKey(t *testing.T) {
|
||||
func TestChainRetriever_Empty(t *testing.T) {
|
||||
chain := NewChain()
|
||||
key, err := chain.RetrieveKey("Chrome", "")
|
||||
assert.Error(t, err)
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, key)
|
||||
}
|
||||
|
||||
@@ -25,12 +25,12 @@ func TestCopyLocked_ExclusiveLock(t *testing.T) {
|
||||
|
||||
// Normal copy should fail
|
||||
err := copyFile(src, filepath.Join(dir, "normal_copy.db"))
|
||||
assert.Error(t, err, "normal copy should fail on exclusively locked file")
|
||||
require.Error(t, err, "normal copy should fail on exclusively locked file")
|
||||
|
||||
// copyLocked should succeed via DuplicateHandle + FileMapping
|
||||
lockedDst := filepath.Join(dir, "locked_copy.db")
|
||||
err = copyLocked(src, lockedDst)
|
||||
assert.NoError(t, err, "copyLocked should bypass exclusive lock")
|
||||
require.NoError(t, err, "copyLocked should bypass exclusive lock")
|
||||
|
||||
copied, err := os.ReadFile(lockedDst)
|
||||
require.NoError(t, err)
|
||||
@@ -62,7 +62,7 @@ func TestCopyLocked_WriteThenRead(t *testing.T) {
|
||||
// copyLocked should read the full content including appended data
|
||||
lockedDst := filepath.Join(dir, "modified_copy.db")
|
||||
copyErr := copyLocked(src, lockedDst)
|
||||
assert.NoError(t, copyErr)
|
||||
require.NoError(t, copyErr)
|
||||
|
||||
copied, err := os.ReadFile(lockedDst)
|
||||
require.NoError(t, err)
|
||||
@@ -86,17 +86,17 @@ func TestCopyLocked_LargeFile(t *testing.T) {
|
||||
|
||||
lockedDst := filepath.Join(dir, "large_copy.db")
|
||||
err := copyLocked(src, lockedDst)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
copied, err := os.ReadFile(lockedDst)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(data), len(copied), "file sizes should match")
|
||||
assert.Len(t, copied, len(data), "file sizes should match")
|
||||
assert.True(t, bytes.Equal(data, copied), "file content should match byte-for-byte")
|
||||
}
|
||||
|
||||
func TestCopyLocked_FileNotFound(t *testing.T) {
|
||||
err := copyLocked("/nonexistent/file.db", filepath.Join(t.TempDir(), "dst.db"))
|
||||
assert.Error(t, err)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAcquire_FallbackToLocked(t *testing.T) {
|
||||
@@ -115,7 +115,7 @@ func TestAcquire_FallbackToLocked(t *testing.T) {
|
||||
|
||||
dst := filepath.Join(session.TempDir(), "cookies.db")
|
||||
err = session.Acquire(src, dst, false)
|
||||
assert.NoError(t, err, "Acquire should succeed via locked fallback")
|
||||
require.NoError(t, err, "Acquire should succeed via locked fallback")
|
||||
|
||||
copied, err := os.ReadFile(dst)
|
||||
require.NoError(t, err)
|
||||
@@ -136,7 +136,7 @@ func TestAcquire_NormalCopyWhenNotLocked(t *testing.T) {
|
||||
|
||||
dst := filepath.Join(session.TempDir(), "unlocked.db")
|
||||
err = session.Acquire(src, dst, false)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
copied, err := os.ReadFile(dst)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestSession_Acquire_File(t *testing.T) {
|
||||
// Acquire it
|
||||
dst := filepath.Join(s.TempDir(), "Login Data")
|
||||
err = s.Acquire(srcFile, dst, false)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify copy
|
||||
data, err := os.ReadFile(dst)
|
||||
@@ -63,7 +63,7 @@ func TestSession_Acquire_WAL(t *testing.T) {
|
||||
|
||||
dst := filepath.Join(s.TempDir(), "Cookies")
|
||||
err = s.Acquire(srcFile, dst, false)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Main file copied
|
||||
assert.FileExists(t, dst)
|
||||
@@ -85,7 +85,7 @@ func TestSession_Acquire_Dir(t *testing.T) {
|
||||
|
||||
dst := filepath.Join(s.TempDir(), "leveldb")
|
||||
err = s.Acquire(srcDir, dst, true)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Data file copied
|
||||
assert.FileExists(t, filepath.Join(dst, "000001.ldb"))
|
||||
@@ -99,5 +99,5 @@ func TestSession_Acquire_NotFound(t *testing.T) {
|
||||
|
||||
dst := filepath.Join(s.TempDir(), "nope")
|
||||
err = s.Acquire("/nonexistent/file", dst, false)
|
||||
assert.Error(t, err)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
+15
-5
@@ -7,17 +7,27 @@ import (
|
||||
"github.com/moond4rk/hackbrowserdata/types"
|
||||
)
|
||||
|
||||
type cookieEditorFormatter struct{}
|
||||
// cookieEditorFormatter outputs cookies in the CookieEditor browser extension
|
||||
// format. Non-cookie categories fall back to standard JSON output.
|
||||
type cookieEditorFormatter struct {
|
||||
fallback *jsonFormatter
|
||||
}
|
||||
|
||||
func (f *cookieEditorFormatter) ext() string { return "json" }
|
||||
|
||||
func (f *cookieEditorFormatter) format(w io.Writer, rows []row) error {
|
||||
if len(rows) == 0 {
|
||||
return nil
|
||||
}
|
||||
// aggregate() guarantees all rows in a batch share the same type;
|
||||
// check the first row to decide the format.
|
||||
if _, ok := rows[0].entry.(types.CookieEntry); !ok {
|
||||
return f.fallback.format(w, rows)
|
||||
}
|
||||
|
||||
entries := make([]cookieEditorEntry, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
c, ok := r.entry.(types.CookieEntry)
|
||||
if !ok {
|
||||
return nil // not cookies, skip
|
||||
}
|
||||
c, _ := r.entry.(types.CookieEntry)
|
||||
var expDate float64
|
||||
if !c.ExpireAt.IsZero() {
|
||||
expDate = float64(c.ExpireAt.Unix())
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ func newFormatter(name string) (formatter, error) {
|
||||
case "json":
|
||||
return &jsonFormatter{}, nil
|
||||
case "cookie-editor":
|
||||
return &cookieEditorFormatter{}, nil
|
||||
return &cookieEditorFormatter{fallback: &jsonFormatter{}}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported format: %s", name)
|
||||
}
|
||||
|
||||
@@ -65,10 +65,10 @@ func TestNew(t *testing.T) {
|
||||
t.Run(tt.format, func(t *testing.T) {
|
||||
out, err := NewWriter(t.TempDir(), tt.format)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, out)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, out)
|
||||
}
|
||||
})
|
||||
@@ -142,7 +142,7 @@ func TestWrite_CSV_UTF8BOM(t *testing.T) {
|
||||
|
||||
raw, err := os.ReadFile(filepath.Join(dir, "password.csv"))
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(raw) >= 3)
|
||||
require.GreaterOrEqual(t, len(raw), 3)
|
||||
assert.Equal(t, utf8BOM, raw[:3], "CSV should start with UTF-8 BOM")
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ func TestWrite_CookieEditor(t *testing.T) {
|
||||
}, entries[0])
|
||||
}
|
||||
|
||||
func TestWrite_CookieEditor_SkipsNonCookie(t *testing.T) {
|
||||
func TestWrite_CookieEditor_FallbackJSON(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
out, err := NewWriter(dir, "cookie-editor")
|
||||
require.NoError(t, err)
|
||||
@@ -258,9 +258,9 @@ func TestWrite_CookieEditor_SkipsNonCookie(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, out.Write())
|
||||
|
||||
// password file should not be created (cookie-editor only exports cookies)
|
||||
// non-cookie categories fall back to standard JSON format
|
||||
_, err = os.Stat(filepath.Join(dir, "password.json"))
|
||||
assert.True(t, os.IsNotExist(err))
|
||||
assert.False(t, os.IsNotExist(err), "password.json should be created via JSON fallback")
|
||||
}
|
||||
|
||||
// --- File creation ---
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestCompressDir(t *testing.T) {
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
err := CompressDir(tempDir)
|
||||
assert.NoError(t, err, "compressDir should not return an error")
|
||||
require.NoError(t, err, "compressDir should not return an error")
|
||||
|
||||
// Check if the zip file exists
|
||||
zipFile := filepath.Join(tempDir, filepath.Base(tempDir)+".zip")
|
||||
@@ -38,7 +38,7 @@ func TestCompressDir(t *testing.T) {
|
||||
|
||||
t.Run("Directory Does Not Exist", func(t *testing.T) {
|
||||
err := CompressDir("/path/to/nonexistent/directory")
|
||||
assert.Error(t, err, "should return an error for non-existent directory")
|
||||
require.Error(t, err, "should return an error for non-existent directory")
|
||||
})
|
||||
|
||||
t.Run("Empty Directory", func(t *testing.T) {
|
||||
@@ -47,6 +47,6 @@ func TestCompressDir(t *testing.T) {
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
err = CompressDir(tempDir)
|
||||
assert.Error(t, err, "should return an error for an empty directory")
|
||||
require.Error(t, err, "should return an error for an empty directory")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestQuerySQLite(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"alpha", "beta", "gamma"}, names)
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func TestQuerySQLite_JournalOff(t *testing.T) {
|
||||
values = append(values, v)
|
||||
return nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"ok"}, values)
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func TestQuerySQLite_FileNotFound(t *testing.T) {
|
||||
err := QuerySQLite("/nonexistent/path.db", false, "SELECT 1", func(rows *sql.Rows) error {
|
||||
return nil
|
||||
})
|
||||
assert.Error(t, err)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestQuerySQLite_BadQuery(t *testing.T) {
|
||||
@@ -83,7 +83,7 @@ func TestQuerySQLite_BadQuery(t *testing.T) {
|
||||
err = QuerySQLite(dbPath, false, "SELECT nonexistent FROM t", func(rows *sql.Rows) error {
|
||||
return nil
|
||||
})
|
||||
assert.Error(t, err)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestQueryRows(t *testing.T) {
|
||||
@@ -110,7 +110,7 @@ func TestQueryRows(t *testing.T) {
|
||||
return u, err
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []user{{"alice", 30}, {"bob", 25}}, users)
|
||||
}
|
||||
|
||||
@@ -133,6 +133,6 @@ func TestQueryRows_Empty(t *testing.T) {
|
||||
return v, nil
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, results)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user