From ad020cf135a8af1cd92a824cc6209e6c9dccd598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?= Date: Tue, 22 Oct 2024 11:13:06 +0800 Subject: [PATCH] chore: downgrade golang version to 1.20, support Windows 7. (#435) * chore: downgrade golang version to 1.20, support windows 7 * chore: Update dependencies for Go project. - Update dependencies in go.sum - Improvements and optimizations in various files - Bug fixes and error handling enhancements * chore: Update modernc.org/sqlite library versions in go.mod and go.sum files - Update version of `modernc.org/sqlite` to `v1.31.1` in `go.mod` and `go.sum` files - Update module hash in `go.sum` file for `modernc.org/sqlite` - Ensure consistency between `go.mod` and `go.sum` files in relation to `modernc.org/sqlite` version * chore: replace log/slog with standard logger (#436) * chore: replace log/slog with standard logger * chore: Update Go dependencies and versions - Update Go version from `1.22.5` to `1.20` and other dependencies - Update critical dependencies to latest versions - Ensure compatibility with new versions of dependencies * chore: Optimize dependency management in workflows - Update build and lint workflows to use `go mod tidy` for getting dependencies - Change modules download mode to `'mod'` in linters configuration - Add step to get dependencies in lint workflow * refactor: Update dependencies and refactor Chromium key deletion logic - Update `modernc.org/sqlite` to `v1.31.1` in `go.mod` and `go.sum` - Increase version number to `0.5.0` in `cmd/hack-browser-data/main.go` - Refactor and update logic for filtering and copying items in `browser/chromium/chromium.go` * Improve logging functionality and data type conversion - Add `String()` method to `DataType` enum in types.go - Update log level to Debug in logger_test.go - Set log level to Debug in `TestLoggerDebug` and `TestLoggerDebugf` functions --- .github/workflows/build.yml | 6 +- .github/workflows/lint.yml | 7 +- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 4 +- .gitignore | 4 +- .golangci.yml | 5 +- README.md | 2 +- browser/browser.go | 20 +- browser/chromium/chromium.go | 16 +- browser/chromium/chromium_darwin.go | 4 +- browser/chromium/chromium_linux.go | 8 +- browser/chromium/chromium_windows.go | 6 +- browser/firefox/firefox.go | 4 +- browserdata/bookmark/bookmark.go | 6 +- browserdata/browserdata.go | 15 +- browserdata/cookie/cookie.go | 8 +- browserdata/creditcard/creditcard.go | 10 +- browserdata/download/download.go | 8 +- browserdata/history/history.go | 6 +- browserdata/localstorage/localstorage.go | 6 +- browserdata/password/password.go | 10 +- browserdata/sessionstorage/sessionstorage.go | 6 +- cmd/hack-browser-data/main.go | 19 +- go.mod | 16 +- go.sum | 46 ++-- log/level/level.go | 37 +++ log/log.go | 46 ++++ log/logger.go | 182 +++++++++++++ log/logger_test.go | 262 +++++++++++++++++++ logger/handler.go | 63 ----- logger/logger.go | 106 -------- logger/logger_test.go | 68 ----- types/types.go | 51 ++++ 33 files changed, 695 insertions(+), 364 deletions(-) create mode 100644 log/level/level.go create mode 100644 log/log.go create mode 100644 log/logger.go create mode 100644 log/logger_test.go delete mode 100644 logger/handler.go delete mode 100644 logger/logger.go delete mode 100644 logger/logger_test.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ad8182..d5b1861 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - goVer: ["1.22.x"] + goVer: ["1.20.x"] steps: - name: Check out code into the Go module directory @@ -43,7 +43,9 @@ jobs: diff -u <(echo -n) <(gofmt -d .) - name: Get dependencies - run: go mod download + run: | + go mod tidy + go mod download - name: Build run: go build -v ./... diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 783d46e..cb703a5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,7 +16,7 @@ jobs: - name: Set Golang uses: actions/setup-go@v5 with: - go-version: "1.22.x" + go-version: "1.20.x" cache: false - name: Check spelling with custom config file @@ -24,6 +24,11 @@ jobs: with: config: ./.typos.toml + - name: Get dependencies + run: | + go mod tidy + go mod download + - name: Lint uses: golangci/golangci-lint-action@v6 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 101799e..3ce734f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.22.x' + go-version: '1.20.x' - name: Check out code uses: actions/checkout@v4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c054c1..5e1dac2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: test: strategy: matrix: - go-version: [ "1.22.x" ] + go-version: [ "1.20.x" ] platform: [ubuntu-latest] runs-on: ${{ matrix.platform }} steps: @@ -35,7 +35,7 @@ jobs: if: success() uses: actions/setup-go@v5 with: - go-version: "1.22.x" + go-version: "1.20.x" - name: Checkout code uses: actions/checkout@v4 - name: Calc coverage diff --git a/.gitignore b/.gitignore index c6a2206..0c4f246 100644 --- a/.gitignore +++ b/.gitignore @@ -205,4 +205,6 @@ hack-browser-data # CICD Config !.typos.toml -!.github/*.yml \ No newline at end of file +!.github/*.yml +!log/ +examples/*.go \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index ecc6ecb..cde0e90 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,7 @@ run: timeout: '5m' allow-parallel-runners: true - modules-download-mode: 'readonly' + modules-download-mode: 'mod' linters: enable: @@ -43,11 +43,8 @@ linters: - 'noctx' - 'sqlclosecheck' - 'staticcheck' - - 'structcheck' - 'stylecheck' - 'unused' - - 'deadcode' - - 'varcheck' - 'paralleltest' issues: diff --git a/README.md b/README.md index 6db4653..7da6673 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ Installation of `HackBrowserData` is dead-simple, just download [the release for ### Building from source -only support `go 1.21+` with go generics and `log/slog` standard library. +only support `go 1.20+` with go generics. ```bash $ git clone https://github.com/moonD4rk/HackBrowserData diff --git a/browser/browser.go b/browser/browser.go index e433c57..ff1149e 100644 --- a/browser/browser.go +++ b/browser/browser.go @@ -1,7 +1,6 @@ package browser import ( - "log/slog" "path/filepath" "sort" "strings" @@ -9,6 +8,7 @@ import ( "github.com/moond4rk/hackbrowserdata/browser/chromium" "github.com/moond4rk/hackbrowserdata/browser/firefox" "github.com/moond4rk/hackbrowserdata/browserdata" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/utils/fileutil" "github.com/moond4rk/hackbrowserdata/utils/typeutil" ) @@ -44,16 +44,16 @@ func pickChromium(name, profile string) []Browser { if name == "all" { for _, v := range chromiumList { if !fileutil.IsDirExists(filepath.Clean(v.profilePath)) { - slog.Warn("find browser failed, profile folder does not exist", "browser", v.name) + log.Warnf("find browser failed, profile folder does not exist, browser %s", v.name) continue } multiChromium, err := chromium.New(v.name, v.storage, v.profilePath, v.dataTypes) if err != nil { - slog.Error("new chromium error", "err", err) + log.Errorf("new chromium error %v", err) continue } for _, b := range multiChromium { - slog.Warn("find browser success", "browser", b.Name()) + log.Warnf("find browser success, browser %s", b.Name()) browsers = append(browsers, b) } } @@ -63,14 +63,14 @@ func pickChromium(name, profile string) []Browser { profile = c.profilePath } if !fileutil.IsDirExists(filepath.Clean(profile)) { - slog.Error("find browser failed, profile folder does not exist", "browser", c.name) + log.Errorf("find browser failed, profile folder does not exist, browser %s", c.name) } chromes, err := chromium.New(c.name, c.storage, profile, c.dataTypes) if err != nil { - slog.Error("new chromium error", "err", err) + log.Errorf("new chromium error %v", err) } for _, chrome := range chromes { - slog.Warn("find browser success", "browser", chrome.Name()) + log.Warnf("find browser success, browser %s", chrome.Name()) browsers = append(browsers, chrome) } } @@ -89,17 +89,17 @@ func pickFirefox(name, profile string) []Browser { } if !fileutil.IsDirExists(filepath.Clean(profile)) { - slog.Warn("find browser failed, profile folder does not exist", "browser", v.name) + log.Warnf("find browser failed, profile folder does not exist, browser %s", v.name) continue } if multiFirefox, err := firefox.New(profile, v.dataTypes); err == nil { for _, b := range multiFirefox { - slog.Warn("find browser success", "browser", b.Name()) + log.Warnf("find browser success, browser %s", b.Name()) browsers = append(browsers, b) } } else { - slog.Error("new firefox error", "err", err) + log.Errorf("new firefox error %v", err) } } diff --git a/browser/chromium/chromium.go b/browser/chromium/chromium.go index a6aa157..ed1e48e 100644 --- a/browser/chromium/chromium.go +++ b/browser/chromium/chromium.go @@ -2,13 +2,12 @@ package chromium import ( "io/fs" - "log/slog" "os" "path/filepath" - "slices" "strings" "github.com/moond4rk/hackbrowserdata/browserdata" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/fileutil" "github.com/moond4rk/hackbrowserdata/utils/typeutil" @@ -53,9 +52,12 @@ func (c *Chromium) Name() string { func (c *Chromium) BrowsingData(isFullExport bool) (*browserdata.BrowserData, error) { // delete chromiumKey from dataTypes, doesn't need to export key - dataTypes := slices.DeleteFunc(c.dataTypes, func(i types.DataType) bool { - return i == types.ChromiumKey - }) + var dataTypes []types.DataType + for _, dt := range c.dataTypes { + if dt != types.ChromiumKey { + dataTypes = append(dataTypes, dt) + } + } if !isFullExport { dataTypes = types.FilterSensitiveItems(c.dataTypes) @@ -96,7 +98,7 @@ func (c *Chromium) copyItemToLocal() error { err = fileutil.CopyFile(path, filename) } if err != nil { - slog.Error("copy item to local error", "path", path, "filename", filename, "err", err) + log.Errorf("copy item to local, path %s, filename %s err %v", path, filename, err) continue } } @@ -139,7 +141,7 @@ func chromiumWalkFunc(items []types.DataType, multiItemPaths map[string]map[type return func(path string, info fs.FileInfo, err error) error { if err != nil { if os.IsPermission(err) { - slog.Warn("skipping walk chromium path permission error", "path", path, "err", err) + log.Warnf("skipping walk chromium path permission error, path %s, err %v", path, err) return nil } return err diff --git a/browser/chromium/chromium_darwin.go b/browser/chromium/chromium_darwin.go index af0b7b9..6e8919c 100644 --- a/browser/chromium/chromium_darwin.go +++ b/browser/chromium/chromium_darwin.go @@ -7,12 +7,12 @@ import ( "crypto/sha1" "errors" "fmt" - "log/slog" "os" "os/exec" "strings" "github.com/moond4rk/hackbrowserdata/crypto" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" ) @@ -54,6 +54,6 @@ func (c *Chromium) GetMasterKey() ([]byte, error) { return nil, errWrongSecurityCommand } c.masterKey = key - slog.Info("get master key success", "browser", c.name) + log.Debugf("get master key success, browser %s", c.name) return key, nil } diff --git a/browser/chromium/chromium_linux.go b/browser/chromium/chromium_linux.go index 70034d8..b654171 100644 --- a/browser/chromium/chromium_linux.go +++ b/browser/chromium/chromium_linux.go @@ -5,13 +5,13 @@ package chromium import ( "crypto/sha1" "fmt" - "log/slog" "os" "github.com/godbus/dbus/v5" keyring "github.com/ppacher/go-dbus-keyring" "github.com/moond4rk/hackbrowserdata/crypto" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" ) @@ -34,7 +34,7 @@ func (c *Chromium) GetMasterKey() ([]byte, error) { } defer func() { if err := session.Close(); err != nil { - slog.Error("close dbus session error", "err", err.Error()) + log.Errorf("close dbus session error: %v", err) } }() collections, err := svc.GetAllCollections() @@ -50,7 +50,7 @@ func (c *Chromium) GetMasterKey() ([]byte, error) { for _, i := range items { label, err := i.GetLabel() if err != nil { - slog.Warn("get label from dbus", "err", err.Error()) + log.Warnf("get label from dbus: %v", err) continue } if label == c.storage { @@ -71,6 +71,6 @@ func (c *Chromium) GetMasterKey() ([]byte, error) { // @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_linux.cc key := crypto.PBKDF2Key(secret, salt, 1, 16, sha1.New) c.masterKey = key - slog.Info("get master key success", "browser", c.name) + log.Debugf("get master key success, browser %s", c.name) return key, nil } diff --git a/browser/chromium/chromium_windows.go b/browser/chromium/chromium_windows.go index b97c992..439eaa2 100644 --- a/browser/chromium/chromium_windows.go +++ b/browser/chromium/chromium_windows.go @@ -5,12 +5,12 @@ package chromium import ( "encoding/base64" "errors" - "log/slog" "os" "github.com/tidwall/gjson" "github.com/moond4rk/hackbrowserdata/crypto" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/fileutil" ) @@ -35,9 +35,9 @@ func (c *Chromium) GetMasterKey() ([]byte, error) { } c.masterKey, err = crypto.DecryptWithDPAPI(key[5:]) if err != nil { - slog.Error("decrypt master key failed", "err", err) + log.Errorf("decrypt master key failed, err %v", err) return nil, err } - slog.Info("get master key success", "browser", c.name) + log.Debugf("get master key success, browser %s", c.name) return c.masterKey, nil } diff --git a/browser/firefox/firefox.go b/browser/firefox/firefox.go index 91ba69c..cc6fa52 100644 --- a/browser/firefox/firefox.go +++ b/browser/firefox/firefox.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io/fs" - "log/slog" "os" "path/filepath" @@ -14,6 +13,7 @@ import ( "github.com/moond4rk/hackbrowserdata/browserdata" "github.com/moond4rk/hackbrowserdata/crypto" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/fileutil" "github.com/moond4rk/hackbrowserdata/utils/typeutil" @@ -62,7 +62,7 @@ func firefoxWalkFunc(items []types.DataType, multiItemPaths map[string]map[types return func(path string, info fs.DirEntry, err error) error { if err != nil { if os.IsPermission(err) { - slog.Warn("skipping walk firefox path permission error", "path", path, "err", err) + log.Warnf("skipping walk firefox path %s permission error: %v", path, err) return nil } return err diff --git a/browserdata/bookmark/bookmark.go b/browserdata/bookmark/bookmark.go index 5a0e7c4..0e7d629 100644 --- a/browserdata/bookmark/bookmark.go +++ b/browserdata/bookmark/bookmark.go @@ -2,7 +2,6 @@ package bookmark import ( "database/sql" - "log/slog" "os" "sort" "time" @@ -11,6 +10,7 @@ import ( _ "modernc.org/sqlite" // import sqlite3 driver "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/fileutil" "github.com/moond4rk/hackbrowserdata/utils/typeutil" @@ -111,7 +111,7 @@ func (f *FirefoxBookmark) Extract(_ []byte) error { defer db.Close() _, err = db.Exec(closeJournalMode) if err != nil { - slog.Error("close journal mode error", "err", err) + log.Errorf("close journal mode error: %v", err) } rows, err := db.Query(queryFirefoxBookMark) if err != nil { @@ -124,7 +124,7 @@ func (f *FirefoxBookmark) Extract(_ []byte) error { title, url string ) if err = rows.Scan(&id, &url, &bt, &dateAdded, &title); err != nil { - slog.Error("scan bookmark error", "err", err) + log.Errorf("scan bookmark error: %v", err) } *f = append(*f, bookmark{ ID: id, diff --git a/browserdata/browserdata.go b/browserdata/browserdata.go index bed2f01..20ab033 100644 --- a/browserdata/browserdata.go +++ b/browserdata/browserdata.go @@ -1,9 +1,8 @@ package browserdata import ( - "log/slog" - "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/fileutil" ) @@ -23,7 +22,7 @@ func New(items []types.DataType) *BrowserData { func (d *BrowserData) Recovery(masterKey []byte) error { for _, source := range d.extractors { if err := source.Extract(masterKey); err != nil { - slog.Error("parse error", "source_data", source.Name(), "err", err.Error()) + log.Errorf("parse %s error: %v", source.Name(), err) continue } } @@ -42,18 +41,18 @@ func (d *BrowserData) Output(dir, browserName, flag string) { f, err := output.CreateFile(dir, filename) if err != nil { - slog.Error("create file error", "filename", filename, "err", err.Error()) + log.Errorf("create file %s error: %v", filename, err) continue } if err := output.Write(source, f); err != nil { - slog.Error("write to file error", "filename", filename, "err", err.Error()) + log.Errorf("write to file %s error: %v", filename, err) continue } if err := f.Close(); err != nil { - slog.Error("close file error", "filename", filename, "err", err.Error()) + log.Errorf("close file %s error: %v", filename, err) continue } - slog.Warn("export success", "filename", filename) + log.Warnf("export success: %s", filename) } } @@ -62,7 +61,7 @@ func (d *BrowserData) addExtractors(items []types.DataType) { if source := extractor.CreateExtractor(itemType); source != nil { d.extractors[itemType] = source } else { - slog.Debug("source not found", "source", itemType) + log.Debugf("source not found: %s", itemType) } } } diff --git a/browserdata/cookie/cookie.go b/browserdata/cookie/cookie.go index 638dbb1..cac4c2e 100644 --- a/browserdata/cookie/cookie.go +++ b/browserdata/cookie/cookie.go @@ -2,7 +2,6 @@ package cookie import ( "database/sql" - "log/slog" "os" "sort" "time" @@ -12,6 +11,7 @@ import ( "github.com/moond4rk/hackbrowserdata/crypto" "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/typeutil" ) @@ -65,7 +65,7 @@ func (c *ChromiumCookie) Extract(masterKey []byte) error { value, encryptValue []byte ) if err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent); err != nil { - slog.Error("scan chromium cookie error", "err", err) + log.Errorf("scan chromium cookie error: %v", err) } cookie := cookie{ @@ -87,7 +87,7 @@ func (c *ChromiumCookie) Extract(masterKey []byte) error { value, err = crypto.DecryptWithChromium(masterKey, encryptValue) } if err != nil { - slog.Error("decrypt chromium cookie error", "err", err) + log.Errorf("decrypt chromium cookie error: %v", err) } } cookie.Value = string(value) @@ -133,7 +133,7 @@ func (f *FirefoxCookie) Extract(_ []byte) error { creationTime, expiry int64 ) if err = rows.Scan(&name, &value, &host, &path, &creationTime, &expiry, &isSecure, &isHTTPOnly); err != nil { - slog.Error("scan firefox cookie error", "err", err) + log.Errorf("scan firefox cookie error: %v", err) } *f = append(*f, cookie{ KeyName: name, diff --git a/browserdata/creditcard/creditcard.go b/browserdata/creditcard/creditcard.go index dc0948c..35adee9 100644 --- a/browserdata/creditcard/creditcard.go +++ b/browserdata/creditcard/creditcard.go @@ -2,7 +2,6 @@ package creditcard import ( "database/sql" - "log/slog" "os" // import sqlite3 driver @@ -10,6 +9,7 @@ import ( "github.com/moond4rk/hackbrowserdata/crypto" "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" ) @@ -57,7 +57,7 @@ func (c *ChromiumCreditCard) Extract(masterKey []byte) error { value, encryptValue []byte ) if err := rows.Scan(&guid, &name, &month, &year, &encryptValue, &address, &nickname); err != nil { - slog.Error("scan chromium credit card error", "err", err) + log.Errorf("scan chromium credit card error: %v", err) } ccInfo := card{ GUID: guid, @@ -74,7 +74,7 @@ func (c *ChromiumCreditCard) Extract(masterKey []byte) error { value, err = crypto.DecryptWithChromium(masterKey, encryptValue) } if err != nil { - slog.Error("decrypt chromium credit card error", "err", err) + log.Errorf("decrypt chromium credit card error: %v", err) } } @@ -112,7 +112,7 @@ func (c *YandexCreditCard) Extract(masterKey []byte) error { value, encryptValue []byte ) if err := rows.Scan(&guid, &name, &month, &year, &encryptValue, &address, &nickname); err != nil { - slog.Error("scan chromium credit card error", "err", err) + log.Errorf("scan chromium credit card error: %v", err) } ccInfo := card{ GUID: guid, @@ -129,7 +129,7 @@ func (c *YandexCreditCard) Extract(masterKey []byte) error { value, err = crypto.DecryptWithChromium(masterKey, encryptValue) } if err != nil { - slog.Error("decrypt chromium credit card error", "err", err) + log.Errorf("decrypt chromium credit card error: %v", err) } } ccInfo.CardNumber = string(value) diff --git a/browserdata/download/download.go b/browserdata/download/download.go index 44a425d..3120821 100644 --- a/browserdata/download/download.go +++ b/browserdata/download/download.go @@ -2,7 +2,6 @@ package download import ( "database/sql" - "log/slog" "os" "sort" "strings" @@ -12,6 +11,7 @@ import ( _ "modernc.org/sqlite" // import sqlite3 driver "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/typeutil" ) @@ -58,7 +58,7 @@ func (c *ChromiumDownload) Extract(_ []byte) error { totalBytes, startTime, endTime int64 ) if err := rows.Scan(&targetPath, &tabURL, &totalBytes, &startTime, &endTime, &mimeType); err != nil { - slog.Warn("scan chromium download error", "err", err) + log.Warnf("scan chromium download error: %v", err) } data := download{ TargetPath: targetPath, @@ -101,7 +101,7 @@ func (f *FirefoxDownload) Extract(_ []byte) error { _, err = db.Exec(closeJournalMode) if err != nil { - slog.Error("close journal mode error", "err", err) + log.Errorf("close journal mode error: %v", err) } rows, err := db.Query(queryFirefoxDownload) if err != nil { @@ -114,7 +114,7 @@ func (f *FirefoxDownload) Extract(_ []byte) error { placeID, dateAdded int64 ) if err = rows.Scan(&placeID, &content, &url, &dateAdded); err != nil { - slog.Warn("scan firefox download error", "err", err) + log.Warnf("scan firefox download error: %v", err) } contentList := strings.Split(content, ",{") if len(contentList) > 1 { diff --git a/browserdata/history/history.go b/browserdata/history/history.go index 7ff624e..952edc7 100644 --- a/browserdata/history/history.go +++ b/browserdata/history/history.go @@ -2,7 +2,6 @@ package history import ( "database/sql" - "log/slog" "os" "sort" "time" @@ -11,6 +10,7 @@ import ( _ "modernc.org/sqlite" "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/typeutil" ) @@ -57,7 +57,7 @@ func (c *ChromiumHistory) Extract(_ []byte) error { lastVisitTime int64 ) if err := rows.Scan(&url, &title, &visitCount, &lastVisitTime); err != nil { - slog.Warn("scan chromium history error", "err", err) + log.Warnf("scan chromium history error: %v", err) } data := history{ URL: url, @@ -113,7 +113,7 @@ func (f *FirefoxHistory) Extract(_ []byte) error { visitCount int ) if err = rows.Scan(&id, &url, &visitDate, &title, &visitCount); err != nil { - slog.Error("scan firefox history error", "err", err) + log.Errorf("scan firefox history error: %v", err) } *f = append(*f, history{ Title: title, diff --git a/browserdata/localstorage/localstorage.go b/browserdata/localstorage/localstorage.go index 5d51476..05e5e18 100644 --- a/browserdata/localstorage/localstorage.go +++ b/browserdata/localstorage/localstorage.go @@ -4,7 +4,6 @@ import ( "bytes" "database/sql" "fmt" - "log/slog" "os" "strings" @@ -13,6 +12,7 @@ import ( "golang.org/x/text/transform" "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/byteutil" "github.com/moond4rk/hackbrowserdata/utils/typeutil" @@ -125,7 +125,7 @@ func (f *FirefoxLocalStorage) Extract(_ []byte) error { _, err = db.Exec(closeJournalMode) if err != nil { - slog.Error("close journal mode error", "err", err) + log.Errorf("close journal mode error: %v", err) } rows, err := db.Query(queryLocalStorage) if err != nil { @@ -135,7 +135,7 @@ func (f *FirefoxLocalStorage) Extract(_ []byte) error { for rows.Next() { var originKey, key, value string if err = rows.Scan(&originKey, &key, &value); err != nil { - slog.Error("scan firefox local storage error", "err", err) + log.Errorf("scan firefox local storage error: %v", err) } s := new(storage) s.fillFirefox(originKey, key, value) diff --git a/browserdata/password/password.go b/browserdata/password/password.go index e8912dd..bedf281 100644 --- a/browserdata/password/password.go +++ b/browserdata/password/password.go @@ -3,7 +3,6 @@ package password import ( "database/sql" "encoding/base64" - "log/slog" "os" "sort" "time" @@ -13,6 +12,7 @@ import ( "github.com/moond4rk/hackbrowserdata/crypto" "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/typeutil" ) @@ -65,7 +65,7 @@ func (c *ChromiumPassword) Extract(masterKey []byte) error { create int64 ) if err := rows.Scan(&url, &username, &pwd, &create); err != nil { - slog.Error("scan chromium password error", "err", err) + log.Errorf("scan chromium password error: %v", err) } login := loginData{ UserName: username, @@ -79,7 +79,7 @@ func (c *ChromiumPassword) Extract(masterKey []byte) error { password, err = crypto.DecryptWithChromium(masterKey, pwd) } if err != nil { - slog.Error("decrypt chromium password error", "err", err) + log.Errorf("decrypt chromium password error: %v", err) } } if create > time.Now().Unix() { @@ -132,7 +132,7 @@ func (c *YandexPassword) Extract(masterKey []byte) error { create int64 ) if err := rows.Scan(&url, &username, &pwd, &create); err != nil { - slog.Error("scan yandex password error", "err", err) + log.Errorf("scan yandex password error: %v", err) } login := loginData{ UserName: username, @@ -147,7 +147,7 @@ func (c *YandexPassword) Extract(masterKey []byte) error { password, err = crypto.DecryptWithChromium(masterKey, pwd) } if err != nil { - slog.Error("decrypt yandex password error", "err", err) + log.Errorf("decrypt yandex password error: %v", err) } } if create > time.Now().Unix() { diff --git a/browserdata/sessionstorage/sessionstorage.go b/browserdata/sessionstorage/sessionstorage.go index c12e73d..e3380ce 100644 --- a/browserdata/sessionstorage/sessionstorage.go +++ b/browserdata/sessionstorage/sessionstorage.go @@ -4,7 +4,6 @@ import ( "bytes" "database/sql" "fmt" - "log/slog" "os" "strings" @@ -13,6 +12,7 @@ import ( "golang.org/x/text/transform" "github.com/moond4rk/hackbrowserdata/extractor" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/types" "github.com/moond4rk/hackbrowserdata/utils/byteutil" "github.com/moond4rk/hackbrowserdata/utils/typeutil" @@ -133,7 +133,7 @@ func (f *FirefoxSessionStorage) Extract(_ []byte) error { _, err = db.Exec(closeJournalMode) if err != nil { - slog.Error("close journal mode error", "err", err) + log.Errorf("close journal mode error: %v", err) } rows, err := db.Query(querySessionStorage) if err != nil { @@ -143,7 +143,7 @@ func (f *FirefoxSessionStorage) Extract(_ []byte) error { for rows.Next() { var originKey, key, value string if err = rows.Scan(&originKey, &key, &value); err != nil { - slog.Error("scan session storage error", "err", err) + log.Errorf("scan session storage error: %v", err) } s := new(session) s.fillFirefox(originKey, key, value) diff --git a/cmd/hack-browser-data/main.go b/cmd/hack-browser-data/main.go index d10ae85..633e164 100644 --- a/cmd/hack-browser-data/main.go +++ b/cmd/hack-browser-data/main.go @@ -1,13 +1,12 @@ package main import ( - "log/slog" "os" "github.com/urfave/cli/v2" "github.com/moond4rk/hackbrowserdata/browser" - "github.com/moond4rk/hackbrowserdata/logger" + "github.com/moond4rk/hackbrowserdata/log" "github.com/moond4rk/hackbrowserdata/utils/fileutil" ) @@ -30,7 +29,7 @@ func Execute() { Name: "hack-browser-data", Usage: "Export passwords|bookmarks|cookies|history|credit cards|download history|localStorage|extensions from browser", UsageText: "[hack-browser-data -b chrome -f json --dir results --zip]\nExport all browsing data (passwords/cookies/history/bookmarks) from browser\nGithub Link: https://github.com/moonD4rk/HackBrowserData", - Version: "0.4.6", + Version: "0.5.0", Flags: []cli.Flag{ &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"}, &cli.BoolFlag{Name: "compress", Aliases: []string{"zip"}, Destination: &compress, Value: false, Usage: "compress result to zip"}, @@ -43,18 +42,18 @@ func Execute() { HideHelpCommand: true, Action: func(c *cli.Context) error { if verbose { - logger.Default.SetVerbose() - logger.Configure(logger.Default) + log.SetVerbose() } browsers, err := browser.PickBrowsers(browserName, profilePath) if err != nil { - slog.Error("pick browsers error", "err", err) + log.Errorf("pick browsers %v", err) + return err } for _, b := range browsers { data, err := b.BrowsingData(isFullExport) if err != nil { - slog.Error("get browsing data error", "err", err) + log.Errorf("get browsing data error %v", err) continue } data.Output(outputDir, b.Name(), outputFormat) @@ -62,15 +61,15 @@ func Execute() { if compress { if err = fileutil.CompressDir(outputDir); err != nil { - slog.Error("compress error", "err", err) + log.Errorf("compress error %v", err) } - slog.Info("compress success") + log.Debug("compress success") } return nil }, } err := app.Run(os.Args) if err != nil { - panic(err) + log.Fatalf("run app error %v", err) } } diff --git a/go.mod b/go.mod index d914f19..c52b969 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/moond4rk/hackbrowserdata -go 1.22.5 +go 1.20 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 @@ -13,11 +13,11 @@ require ( github.com/tidwall/gjson v1.18.0 github.com/urfave/cli/v2 v2.27.4 golang.org/x/text v0.19.0 - modernc.org/sqlite v1.33.1 + modernc.org/sqlite v1.31.1 ) require ( - github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect @@ -29,15 +29,13 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect - golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + golang.org/x/sys v0.22.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 // indirect - modernc.org/libc v1.61.0 // indirect + modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect + modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect modernc.org/strutil v1.2.0 // indirect diff --git a/go.sum b/go.sum index da5c4c4..e48850b 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= -github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= -github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -16,7 +16,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -36,7 +35,6 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= -github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/ppacher/go-dbus-keyring v1.0.1 h1:dM4dMfP5w9MxY+foFHCQiN7izEGpFdKr3tZeMGmvqD0= @@ -53,17 +51,13 @@ github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8= github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= -golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw= -golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -71,46 +65,38 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= -modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.21.0 h1:kKPI3dF7RIag8YcToh5ZwDcVMIv6VGa0ED5cvh0LMW4= -modernc.org/ccgo/v4 v4.21.0/go.mod h1:h6kt6H/A2+ew/3MW/p6KEoQmrq/i3pr0J/SiwiaF/g0= +modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.5.0 h1:bJ9ChznK1L1mUtAQtxi0wi5AtAs5jQuw4PrPHO5pb6M= -modernc.org/gc/v2 v2.5.0/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= -modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 h1:IYXPPTTjjoSHvUClZIYexDiO7g+4x+XveKT4gCIAwiY= -modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.61.0 h1:eGFcvWpqlnoGwzZeZe3PWJkkKbM/3SUGyk1DVZQ0TpE= -modernc.org/libc v1.61.0/go.mod h1:DvxVX89wtGTu+r72MLGhygpfi3aUGgZRdAYGCAVVud0= +modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= -modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= -modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs= +modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/log/level/level.go b/log/level/level.go new file mode 100644 index 0000000..3b0ee5e --- /dev/null +++ b/log/level/level.go @@ -0,0 +1,37 @@ +package level + +// Level defines all the available levels we can log at +type Level int32 + +const ( + // DebugLevel is the lowest level of logging. + // Debug logs are intended for debugging and development purposes. + DebugLevel Level = iota + 1 + + // WarnLevel is used for undesired but relatively expected events, + // which may indicate a problem. + WarnLevel + + // ErrorLevel is used for undesired and unexpected events that + // the program can recover from. + ErrorLevel + + // FatalLevel is used for undesired and unexpected events that + // the program cannot recover from. + FatalLevel +) + +func (l Level) String() string { + switch l { + case DebugLevel: + return "DEBUG" + case WarnLevel: + return "WARN" + case ErrorLevel: + return "ERROR" + case FatalLevel: + return "FATAL" + default: + return "UNKNOWN" + } +} diff --git a/log/log.go b/log/log.go new file mode 100644 index 0000000..a89e32d --- /dev/null +++ b/log/log.go @@ -0,0 +1,46 @@ +package log + +import ( + "github.com/moond4rk/hackbrowserdata/log/level" +) + +var ( + // defaultLogger is the default logger used by the package-level functions. + defaultLogger = NewLogger(nil) +) + +func SetVerbose() { + defaultLogger.SetLevel(level.DebugLevel) +} + +func Debug(args ...any) { + defaultLogger.Debug(args...) +} + +func Debugf(format string, args ...any) { + defaultLogger.Debugf(format, args...) +} + +func Warn(args ...any) { + defaultLogger.Warn(args...) +} + +func Warnf(format string, args ...any) { + defaultLogger.Warnf(format, args...) +} + +func Error(args ...any) { + defaultLogger.Error(args...) +} + +func Errorf(format string, args ...any) { + defaultLogger.Errorf(format, args...) +} + +func Fatal(args ...any) { + defaultLogger.Fatal(args...) +} + +func Fatalf(format string, args ...any) { + defaultLogger.Fatalf(format, args...) +} diff --git a/log/logger.go b/log/logger.go new file mode 100644 index 0000000..8e7243d --- /dev/null +++ b/log/logger.go @@ -0,0 +1,182 @@ +package log + +import ( + "fmt" + "io" + stdlog "log" + "os" + "runtime" + "strings" + "sync/atomic" + + "github.com/moond4rk/hackbrowserdata/log/level" +) + +// NewLogger creates and returns a new instance of Logger. +// Log level is set to DebugLevel by default. +func NewLogger(base Base) *Logger { + if base == nil { + base = newBase(os.Stderr) + } + return &Logger{base: base, minLevel: level.WarnLevel} +} + +// Logger logs message to io.Writer at various log levels. +type Logger struct { + base Base + + // Minimum log level for this logger. + // Message with level lower than this level won't be outputted. + minLevel level.Level +} + +// canLogAt reports whether logger can log at level v. +func (l *Logger) canLogAt(v level.Level) bool { + return v >= level.Level(atomic.LoadInt32((*int32)(&l.minLevel))) +} + +// SetLevel sets the logger level. +// It panics if v is less than DebugLevel or greater than FatalLevel. +func (l *Logger) SetLevel(v level.Level) { + if v < level.DebugLevel || v > level.FatalLevel { + panic("log: invalid log level") + } + atomic.StoreInt32((*int32)(&l.minLevel), int32(v)) +} + +func (l *Logger) Debug(args ...any) { + if !l.canLogAt(level.DebugLevel) { + return + } + l.base.Debug(args...) +} + +func (l *Logger) Warn(args ...any) { + if !l.canLogAt(level.WarnLevel) { + return + } + l.base.Warn(args...) +} + +func (l *Logger) Error(args ...any) { + if !l.canLogAt(level.ErrorLevel) { + return + } + l.base.Error(args...) +} + +func (l *Logger) Fatal(args ...any) { + if !l.canLogAt(level.FatalLevel) { + return + } + l.base.Fatal(args...) +} + +func (l *Logger) Debugf(format string, args ...any) { + if !l.canLogAt(level.DebugLevel) { + return + } + l.base.Debug(fmt.Sprintf(format, args...)) +} + +func (l *Logger) Warnf(format string, args ...any) { + if !l.canLogAt(level.WarnLevel) { + return + } + l.base.Warn(fmt.Sprintf(format, args...)) +} + +func (l *Logger) Errorf(format string, args ...any) { + if !l.canLogAt(level.ErrorLevel) { + return + } + l.base.Error(fmt.Sprintf(format, args...)) +} + +func (l *Logger) Fatalf(format string, args ...any) { + if !l.canLogAt(level.FatalLevel) { + return + } + l.base.Fatal(fmt.Sprintf(format, args...)) +} + +type Base interface { + Debug(args ...any) + Warn(args ...any) + Error(args ...any) + Fatal(args ...any) +} + +// baseLogger is a wrapper object around log.Logger from the standard library. +// It supports logging at various log levels. +type baseLogger struct { + *stdlog.Logger + callDepth int +} + +func newBase(out io.Writer) *baseLogger { + prefix := "[hack-browser-data] " + base := &baseLogger{ + Logger: stdlog.New(out, prefix, stdlog.Lshortfile), + } + base.callDepth = base.calculateCallDepth() + return base +} + +// calculateCallDepth returns the call depth for the logger. +func (l *baseLogger) calculateCallDepth() int { + return l.getCallDepth() +} + +func (l *baseLogger) prefixPrint(prefix string, args ...any) { + args = append([]any{prefix}, args...) + if err := l.Output(l.callDepth, fmt.Sprint(args...)); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "log output error: %v\n", err) + } +} + +func (l *baseLogger) getCallDepth() int { + var defaultCallDepth = 2 + pcs := make([]uintptr, 10) + n := runtime.Callers(defaultCallDepth, pcs) + frames := runtime.CallersFrames(pcs[:n]) + for i := 0; i < n; i++ { + frame, more := frames.Next() + if !l.isLoggerPackage(frame.Function) { + return i + 1 + } + if !more { + break + } + } + return defaultCallDepth +} + +func (l *baseLogger) isLoggerPackage(funcName string) bool { + const loggerFuncName = "hackbrowserdata/log" + return strings.Contains(funcName, loggerFuncName) +} + +// Debug logs a message at Debug level. +func (l *baseLogger) Debug(args ...any) { + l.prefixPrint("DEBUG: ", args...) +} + +// Warn logs a message at Warning level. +func (l *baseLogger) Warn(args ...any) { + l.prefixPrint("WARN: ", args...) +} + +// Error logs a message at Error level. +func (l *baseLogger) Error(args ...any) { + l.prefixPrint("ERROR: ", args...) +} + +var osExit = os.Exit + +// Fatal logs a message at Fatal level +// and process will exit with status set to 1. +func (l *baseLogger) Fatal(args ...any) { + l.prefixPrint("FATAL: ", args...) + osExit(1) +} diff --git a/log/logger_test.go b/log/logger_test.go new file mode 100644 index 0000000..65e2cd1 --- /dev/null +++ b/log/logger_test.go @@ -0,0 +1,262 @@ +package log + +import ( + "bytes" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + + level2 "github.com/moond4rk/hackbrowserdata/log/level" +) + +const ( + pattern = `^\[hack\-browser\-data] \w+\.go:\d+:` +) + +type baseTestCase struct { + description string + message string + suffix string + level level2.Level + wantedPattern string +} + +var ( + baseTestCases = []baseTestCase{ + { + description: "without trailing newline, logger adds newline", + message: "hello, hacker!", + suffix: "", + }, + { + description: "with trailing newline, logger preserves newline", + message: "hello, hacker!", + suffix: "\n", + }, + } +) + +func TestLoggerDebug(t *testing.T) { + for _, tc := range baseTestCases { + tc := tc + tc.level = level2.DebugLevel + message := tc.message + tc.suffix + tc.wantedPattern = fmt.Sprintf("%s %s: %s\n$", pattern, tc.level, tc.message) + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + logger := NewLogger(newBase(&buf)) + logger.SetLevel(level2.DebugLevel) + logger.Debug(message) + got := buf.String() + assert.Regexp(t, tc.wantedPattern, got) + }) + } +} + +func TestLoggerWarn(t *testing.T) { + for _, tc := range baseTestCases { + tc := tc + tc.level = level2.WarnLevel + message := tc.message + tc.suffix + tc.wantedPattern = fmt.Sprintf("%s %s: %s\n$", pattern, tc.level, tc.message) + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + logger := NewLogger(newBase(&buf)) + logger.Warn(message) + got := buf.String() + assert.Regexp(t, tc.wantedPattern, got) + }) + } +} + +func TestLoggerError(t *testing.T) { + for _, tc := range baseTestCases { + tc := tc + tc.level = level2.ErrorLevel + message := tc.message + tc.suffix + tc.wantedPattern = fmt.Sprintf("%s %s: %s\n$", pattern, tc.level, tc.message) + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + logger := NewLogger(newBase(&buf)) + logger.Error(message) + got := buf.String() + assert.Regexp(t, tc.wantedPattern, got) + }) + } +} + +func TestLoggerFatal(t *testing.T) { + originalOsExit := osExit + defer func() { osExit = originalOsExit }() + + for _, tc := range baseTestCases { + tc := tc + tc.level = level2.FatalLevel + message := tc.message + tc.suffix + tc.wantedPattern = fmt.Sprintf("%s %s: %s\n$", pattern, tc.level, tc.message) + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + exitCalled := false + exitCode := 0 + osExit = func(code int) { + exitCalled = true + exitCode = code + } + logger := NewLogger(newBase(&buf)) + logger.Fatal(message) + got := buf.String() + assert.Regexp(t, tc.wantedPattern, got) + assert.True(t, exitCalled) + assert.Equal(t, 1, exitCode) + }) + } +} + +type formatTestCase struct { + description string + format string + args []interface{} + level level2.Level + wantedPattern string +} + +var ( + formatTestCases = []formatTestCase{ + { + description: "message with format prefix", + format: "hello, %s!", + args: []any{"Hacker"}, + }, + { + description: "message with format prefix", + format: "hello, %d,%d,%d!", + args: []any{1, 2, 3}, + }, + { + description: "message with format prefix", + format: "hello, %s,%d,%d!", + args: []any{"Hacker", 2, 3}, + }, + } +) + +func TestLoggerDebugf(t *testing.T) { + for _, tc := range formatTestCases { + tc := tc + tc.level = level2.DebugLevel + message := fmt.Sprintf(tc.format, tc.args...) + tc.wantedPattern = fmt.Sprintf("%s %s: %s\n$", pattern, tc.level, message) + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + logger := NewLogger(newBase(&buf)) + logger.SetLevel(level2.DebugLevel) + logger.Debugf(tc.format, tc.args...) + got := buf.String() + assert.Regexp(t, tc.wantedPattern, got) + }) + } +} + +func TestLoggerWarnf(t *testing.T) { + for _, tc := range formatTestCases { + tc := tc + tc.level = level2.WarnLevel + message := fmt.Sprintf(tc.format, tc.args...) + tc.wantedPattern = fmt.Sprintf("%s %s: %s\n$", pattern, tc.level, message) + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + logger := NewLogger(newBase(&buf)) + logger.Warnf(tc.format, tc.args...) + got := buf.String() + assert.Regexp(t, tc.wantedPattern, got) + }) + } +} + +func TestLoggerErrorf(t *testing.T) { + for _, tc := range formatTestCases { + tc := tc + tc.level = level2.ErrorLevel + message := fmt.Sprintf(tc.format, tc.args...) + tc.wantedPattern = fmt.Sprintf("%s %s: %s\n$", pattern, tc.level, message) + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + logger := NewLogger(newBase(&buf)) + logger.Errorf(tc.format, tc.args...) + got := buf.String() + assert.Regexp(t, tc.wantedPattern, got) + }) + } +} + +func TestLoggerFatalf(t *testing.T) { + originalOsExit := osExit + defer func() { osExit = originalOsExit }() + for _, tc := range formatTestCases { + tc := tc + tc.level = level2.FatalLevel + message := fmt.Sprintf(tc.format, tc.args...) + tc.wantedPattern = fmt.Sprintf("%s %s: %s\n$", pattern, tc.level, message) + t.Run(tc.description, func(t *testing.T) { + var buf bytes.Buffer + exitCalled := false + exitCode := 0 + osExit = func(code int) { + exitCalled = true + exitCode = code + } + logger := NewLogger(newBase(&buf)) + logger.Fatalf(tc.format, tc.args...) + got := buf.String() + assert.Regexp(t, tc.wantedPattern, got) + assert.True(t, exitCalled) + assert.Equal(t, 1, exitCode) + }) + } +} + +func TestLoggerWithLowerLevels(t *testing.T) { + // Logger should not log messages at a level + // lower than the specified level. + levels := []level2.Level{level2.DebugLevel, level2.WarnLevel, level2.ErrorLevel, level2.FatalLevel} + ops := []struct { + op string + level level2.Level + logFunc func(*Logger) + expected bool + }{ + {"Debug", level2.DebugLevel, func(l *Logger) { l.Debug("hello") }, false}, + {"Warn", level2.WarnLevel, func(l *Logger) { l.Warn("hello") }, false}, + {"Error", level2.ErrorLevel, func(l *Logger) { l.Error("hello") }, false}, + {"Fatal", level2.FatalLevel, func(l *Logger) { l.Fatal("hello") }, false}, + } + + for _, setLevel := range levels { + for _, op := range ops { + var buf bytes.Buffer + logger := NewLogger(newBase(&buf)) + logger.SetLevel(setLevel) + + expectedOutput := op.level >= setLevel + exitCalled := false + exitCode := 0 + osExit = func(code int) { + exitCalled = true + exitCode = code + } + op.logFunc(logger) + + output := buf.String() + if expectedOutput { + assert.NotEmpty(t, output) + } else { + assert.Empty(t, output) + } + if op.op == "Fatal" { + assert.True(t, exitCalled) + assert.Equal(t, 1, exitCode) + } + } + } +} diff --git a/logger/handler.go b/logger/handler.go deleted file mode 100644 index ee76e97..0000000 --- a/logger/handler.go +++ /dev/null @@ -1,63 +0,0 @@ -package logger - -import ( - "context" - "log/slog" - "os" -) - -var _ slog.Handler = (*LogHandler)(nil) - -// LogHandler is a slog.Handler implementation that can be used to log to a file. -type LogHandler struct { - handler slog.Handler -} - -func NewHandler(logger *Logger) LogHandler { - if logger == nil { - logger = Default - } - - level := logger.Level - if logger.IsVerbose { - level = slog.LevelDebug - } - - output := logger.Output - if output == nil { - output = os.Stderr - } - - handlerOptions := &slog.HandlerOptions{ - AddSource: logger.AddSource, - Level: level, - ReplaceAttr: logger.ReplaceAttr, - } - - if logger.IsJSONHandler { - return LogHandler{ - handler: slog.NewJSONHandler(output, handlerOptions), - } - } - return LogHandler{ - handler: slog.NewTextHandler(output, handlerOptions), - } -} - -var _ slog.Handler = (*LogHandler)(nil) - -func (t LogHandler) Handle(ctx context.Context, r slog.Record) error { - return t.handler.Handle(ctx, r) -} - -func (t LogHandler) Enabled(ctx context.Context, l slog.Level) bool { - return t.handler.Enabled(ctx, l) -} - -func (t LogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { - return LogHandler{handler: t.handler.WithAttrs(attrs)} -} - -func (t LogHandler) WithGroup(name string) slog.Handler { - return LogHandler{handler: t.handler.WithGroup(name)} -} diff --git a/logger/logger.go b/logger/logger.go deleted file mode 100644 index 0ef09b5..0000000 --- a/logger/logger.go +++ /dev/null @@ -1,106 +0,0 @@ -package logger - -import ( - "io" - "log/slog" - "os" - "path/filepath" -) - -// Default is the default *Logger for the default handler. -var Default = &Logger{ - AddSource: true, - IsVerbose: false, - IsJSONHandler: false, - Level: slog.LevelWarn, - ReplaceAttr: defaultReplaceAttrFunc, - Output: os.Stderr, -} - -func init() { - Configure(Default) -} - -// Configure configures the logger by the given options. -func Configure(opts *Logger) { - customHandler := NewHandler(opts) - slog.SetDefault(slog.New(customHandler)) -} - -type Logger struct { - // AddSource indicates whether to add source code location to the log. - AddSource bool - - // IsVerbose indicates whether to enable verbose mode. If true, debug level will be enabled. - // If false, only warn and error level will be enabled. - IsVerbose bool - - // Level indicates the log level of the handler. If IsVerbose is true, Level will be slog.LevelDebug. - Level slog.Level - - // IsJSONHandler indicates whether to use JSON format for log output. - IsJSONHandler bool - - // ReplaceAttr is a function that can be used to replace the value of an attribute. - ReplaceAttr func(groups []string, a slog.Attr) slog.Attr - - // Output is the writer to write the log to. If nil, os.Stderr will be used. - Output io.Writer -} - -func (o *Logger) clone() *Logger { - return &Logger{ - AddSource: o.AddSource, - IsVerbose: o.IsVerbose, - IsJSONHandler: o.IsJSONHandler, - ReplaceAttr: o.ReplaceAttr, - Output: o.Output, - } -} - -// SetMaxLevel sets the max logging level for logger, default is slog.LevelWarn. -// if IsVerbose is true, level will be slog.LevelDebug. -func (o *Logger) SetMaxLevel(level slog.Level) { - o.Level = level -} - -func (o *Logger) SetJSONHandler() { - o.IsJSONHandler = true -} - -func (o *Logger) SetTextHandler() { - o.IsJSONHandler = false -} - -func (o *Logger) SetOutput(output io.Writer) { - o.Output = output -} - -func (o *Logger) SetVerbose() { - o.IsVerbose = true - o.Level = slog.LevelDebug -} - -func (o *Logger) SetReplaceAttrFunc(replaceAttrFunc func(groups []string, a slog.Attr) slog.Attr) { - o.ReplaceAttr = replaceAttrFunc -} - -// defaultReplaceAttrFunc is a function that can be used to replace the value of an attribute. -// remove time key and source prefix -var defaultReplaceAttrFunc = func(groups []string, a slog.Attr) slog.Attr { - // Remove time attributes from the log. - if a.Key == slog.TimeKey { - return slog.Attr{} - } - // Remove source filepath prefix attributes from the log. - if a.Key == slog.SourceKey { - source, ok := a.Value.Any().(*slog.Source) - if !ok { - return slog.Attr{} - } - if source != nil { - source.File = filepath.Base(source.File) - } - } - return a -} diff --git a/logger/logger_test.go b/logger/logger_test.go deleted file mode 100644 index 7409d07..0000000 --- a/logger/logger_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package logger - -import ( - "bytes" - "log/slog" - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestConfigure(t *testing.T) { - asserts := assert.New(t) - buf := new(bytes.Buffer) - - opts := &Logger{ - AddSource: true, - IsVerbose: false, - IsJSONHandler: true, - Output: buf, - } - Configure(opts) - - slog.Warn("test message") - - output := buf.String() - asserts.Contains(output, "test message", "Log output should contain the test message") -} - -func TestSetVerbose(t *testing.T) { - asserts := assert.New(t) - buf := new(bytes.Buffer) - - logger := Default.clone() - logger.SetVerbose() - logger.SetOutput(buf) - Configure(logger) - - slog.Debug("verbose test") - - output := buf.String() - asserts.Contains(output, "verbose test", "Verbose mode should enable debug level logs") -} - -func TestLogger_SetJSONHandler(t *testing.T) { - asserts := assert.New(t) - - logger := Default.clone() - logger.SetJSONHandler() - asserts.True(logger.IsJSONHandler, "IsJSONHandler should be true") -} - -func TestOptionsClone(t *testing.T) { - asserts := assert.New(t) - - original := &Logger{ - AddSource: true, - IsVerbose: true, - IsJSONHandler: true, - Output: os.Stdout, - } - cloned := original.clone() - - asserts.Equal(original.AddSource, cloned.AddSource, "AddSource should be equal") - asserts.Equal(original.IsVerbose, cloned.IsVerbose, "IsVerbose should be equal") - asserts.Equal(original.IsJSONHandler, cloned.IsJSONHandler, "IsJSONHandler should be equal") - asserts.Equal(original.Output, cloned.Output, "Output should be equal") -} diff --git a/types/types.go b/types/types.go index 457614a..c955252 100644 --- a/types/types.go +++ b/types/types.go @@ -60,6 +60,57 @@ var itemFileNames = map[DataType]string{ FirefoxCreditCard: UnsupportedItem, } +func (i DataType) String() string { + switch i { + case ChromiumKey: + return "ChromiumKey" + case ChromiumPassword: + return "ChromiumPassword" + case ChromiumCookie: + return "ChromiumCookie" + case ChromiumBookmark: + return "ChromiumBookmark" + case ChromiumHistory: + return "ChromiumHistory" + case ChromiumDownload: + return "ChromiumDownload" + case ChromiumCreditCard: + return "ChromiumCreditCard" + case ChromiumLocalStorage: + return "ChromiumLocalStorage" + case ChromiumSessionStorage: + return "ChromiumSessionStorage" + case ChromiumExtension: + return "ChromiumExtension" + case YandexPassword: + return "YandexPassword" + case YandexCreditCard: + return "YandexCreditCard" + case FirefoxKey4: + return "FirefoxKey4" + case FirefoxPassword: + return "FirefoxPassword" + case FirefoxCookie: + return "FirefoxCookie" + case FirefoxBookmark: + return "FirefoxBookmark" + case FirefoxHistory: + return "FirefoxHistory" + case FirefoxDownload: + return "FirefoxDownload" + case FirefoxCreditCard: + return "FirefoxCreditCard" + case FirefoxLocalStorage: + return "FirefoxLocalStorage" + case FirefoxSessionStorage: + return "FirefoxSessionStorage" + case FirefoxExtension: + return "FirefoxExtension" + default: + return "UnsupportedItem" + } +} + // Filename returns the filename for the item, defined by browser // chromium local storage is a folder, so it returns the file name of the folder func (i DataType) Filename() string {