From 26de1075ee5da30281b8779416d2b70a6fd79fb5 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, 29 Apr 2022 23:59:37 +0800 Subject: [PATCH] feat: support extension for chromium --- .gitignore | 3 + internal/browingdata/browsingdata.go | 3 + internal/browingdata/cookie/cookie.go | 1 - internal/browingdata/extension/extension.go | 51 ++++++++++++++++ internal/browingdata/history/history.go | 1 - internal/browser/browser.go | 1 - internal/browser/chromium/chromium.go | 27 +++++---- internal/browser/firefox/firefox.go | 12 +--- internal/item/filename.go | 1 + internal/item/item.go | 4 +- internal/utils/fileutil/filetutil.go | 64 +++++++++++++++++++++ 11 files changed, 139 insertions(+), 29 deletions(-) create mode 100644 internal/browingdata/extension/extension.go diff --git a/.gitignore b/.gitignore index 2000470..7d7934a 100644 --- a/.gitignore +++ b/.gitignore @@ -188,3 +188,6 @@ History #Firefox* result/ results/ + +hack-browser-data +!/hack-browser-data \ No newline at end of file diff --git a/internal/browingdata/browsingdata.go b/internal/browingdata/browsingdata.go index 444eda9..53cddec 100644 --- a/internal/browingdata/browsingdata.go +++ b/internal/browingdata/browsingdata.go @@ -7,6 +7,7 @@ import ( "hack-browser-data/internal/browingdata/cookie" "hack-browser-data/internal/browingdata/creditcard" "hack-browser-data/internal/browingdata/download" + "hack-browser-data/internal/browingdata/extension" "hack-browser-data/internal/browingdata/history" "hack-browser-data/internal/browingdata/localstorage" "hack-browser-data/internal/browingdata/password" @@ -78,6 +79,8 @@ func (d *Data) addSource(Sources []item.Item) { d.sources[source] = &creditcard.ChromiumCreditCard{} case item.ChromiumLocalStorage: d.sources[source] = &localstorage.ChromiumLocalStorage{} + case item.ChromiumExtension: + d.sources[source] = &extension.ChromiumExtension{} case item.YandexPassword: d.sources[source] = &password.YandexPassword{} case item.YandexCreditCard: diff --git a/internal/browingdata/cookie/cookie.go b/internal/browingdata/cookie/cookie.go index 437b2ff..45a4fbd 100644 --- a/internal/browingdata/cookie/cookie.go +++ b/internal/browingdata/cookie/cookie.go @@ -69,7 +69,6 @@ func (c *ChromiumCookie) Parse(masterKey []byte) error { CreateDate: typeutil.TimeEpoch(createDate), ExpireDate: typeutil.TimeEpoch(expireDate), } - // TODO: replace DPAPI if len(encryptValue) > 0 { var err error if masterKey == nil { diff --git a/internal/browingdata/extension/extension.go b/internal/browingdata/extension/extension.go new file mode 100644 index 0000000..7712560 --- /dev/null +++ b/internal/browingdata/extension/extension.go @@ -0,0 +1,51 @@ +package extension + +import ( + "os" + + "github.com/tidwall/gjson" + + "hack-browser-data/internal/item" + "hack-browser-data/internal/log" + "hack-browser-data/internal/utils/fileutil" +) + +type ChromiumExtension []*extension + +type extension struct { + Name string + Description string + Version string + HomepageURL string +} + +const ( + manifest = "manifest.json" +) + +func (c *ChromiumExtension) Parse(masterKey []byte) error { + files, err := fileutil.FilesInFolder(item.TempChromiumExtension, manifest) + if err != nil { + return err + } + defer os.RemoveAll(item.TempChromiumExtension) + for _, f := range files { + file, err := fileutil.ReadFile(f) + if err != nil { + log.Error("Failed to read file: %s", err) + continue + } + b := gjson.Parse(file) + *c = append(*c, &extension{ + Name: b.Get("name").String(), + Description: b.Get("description").String(), + Version: b.Get("version").String(), + HomepageURL: b.Get("homepage_url").String(), + }) + } + return nil +} + +func (c *ChromiumExtension) Name() string { + return "extension" +} diff --git a/internal/browingdata/history/history.go b/internal/browingdata/history/history.go index c1f5aa7..f5fc6bf 100644 --- a/internal/browingdata/history/history.go +++ b/internal/browingdata/history/history.go @@ -44,7 +44,6 @@ func (c *ChromiumHistory) Parse(masterKey []byte) error { visitCount int lastVisitTime int64 ) - // TODO: handle rows error if err := rows.Scan(&url, &title, &visitCount, &lastVisitTime); err != nil { log.Warn(err) } diff --git a/internal/browser/browser.go b/internal/browser/browser.go index 7871d5f..6cc5cc0 100644 --- a/internal/browser/browser.go +++ b/internal/browser/browser.go @@ -40,7 +40,6 @@ func PickBrowser(name, profile string) ([]Browser, error) { func pickChromium(name, profile string) []Browser { var browsers []Browser name = strings.ToLower(name) - // TODO: add support for 「all」 flag and set profilePath if name == "all" { for _, v := range chromiumList { if !fileutil.FolderExists(filepath.Clean(v.profilePath)) { diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go index b4404a1..d2c0c1c 100644 --- a/internal/browser/chromium/chromium.go +++ b/internal/browser/chromium/chromium.go @@ -1,7 +1,6 @@ package chromium import ( - "io/ioutil" "os" "path/filepath" "strings" @@ -63,21 +62,21 @@ func (c *chromium) BrowsingData() (*browingdata.Data, error) { func (c *chromium) copyItemToLocal() error { for i, path := range c.itemPaths { - if fileutil.FolderExists(path) { - if err := fileutil.CopyDir(path, i.String(), "lock"); err != nil { - return err + filename := i.String() + var err error + switch { + case fileutil.FolderExists(path): + if i == item.ChromiumLocalStorage { + err = fileutil.CopyDir(path, filename, "lock") } - } else { - var filename = i.String() - // TODO: Handle read file error - d, err := ioutil.ReadFile(path) - if err != nil { - return err - } - err = ioutil.WriteFile(filename, d, 0777) - if err != nil { - return err + if i == item.ChromiumExtension { + err = fileutil.CopyDirContains(path, filename, "manifest.json") } + default: + err = fileutil.CopyFile(path, filename) + } + if err != nil { + return err } } return nil diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go index 17878b0..e40db10 100644 --- a/internal/browser/firefox/firefox.go +++ b/internal/browser/firefox/firefox.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "io/fs" - "io/ioutil" "path/filepath" "hack-browser-data/internal/browingdata" @@ -58,15 +57,8 @@ func (f *firefox) getMultiItemPath(profilePath string, items []item.Item) (map[s func (f *firefox) copyItemToLocal() error { for i, path := range f.itemPaths { - // var dstFilename = item.TempName() - var filename = i.String() - // TODO: Handle read file error - d, err := ioutil.ReadFile(path) - if err != nil { - return err - } - err = ioutil.WriteFile(filename, d, 0777) - if err != nil { + filename := i.String() + if err := fileutil.CopyFile(path, filename); err != nil { return err } } diff --git a/internal/item/filename.go b/internal/item/filename.go index 23909bb..3077702 100644 --- a/internal/item/filename.go +++ b/internal/item/filename.go @@ -10,6 +10,7 @@ const ( fileChromiumCookie = "Cookies" fileChromiumBookmark = "Bookmarks" fileChromiumLocalStorage = "Local Storage/leveldb" + fileChromiumExtension = "Extensions" fileYandexPassword = "Ya Passman Data" fileYandexCredit = "Ya Credit Cards" diff --git a/internal/item/item.go b/internal/item/item.go index df8eac3..b39f8a0 100644 --- a/internal/item/item.go +++ b/internal/item/item.go @@ -44,7 +44,7 @@ func (i Item) FileName() string { case ChromiumCreditCard: return fileChromiumCredit case ChromiumExtension: - return UnknownItem + return fileChromiumExtension case ChromiumHistory: return fileChromiumHistory case YandexPassword: @@ -91,7 +91,7 @@ func (i Item) String() string { case ChromiumCreditCard: return TempChromiumCreditCard case ChromiumExtension: - return UnsupportedItem + return TempChromiumExtension case ChromiumHistory: return TempChromiumHistory case YandexPassword: diff --git a/internal/utils/fileutil/filetutil.go b/internal/utils/fileutil/filetutil.go index 135385a..315a122 100644 --- a/internal/utils/fileutil/filetutil.go +++ b/internal/utils/fileutil/filetutil.go @@ -3,6 +3,7 @@ package fileutil import ( "archive/zip" "bytes" + "errors" "fmt" "io/ioutil" "os" @@ -37,12 +38,29 @@ func FolderExists(foldername string) bool { return info.IsDir() } +// FilesInFolder returns the files contains in the provided folder +func FilesInFolder(dir, filename string) ([]string, error) { + if !FolderExists(dir) { + return nil, errors.New(dir + " folder does not exist") + } + var files []string + err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error { + if !f.IsDir() && strings.Contains(path, filename) { + files = append(files, path) + } + return err + }) + return files, err +} + // ReadFile reads the file from the provided path func ReadFile(filename string) (string, error) { s, err := ioutil.ReadFile(filename) return string(s), err } +// CopyDir copies the directory from the source to the destination +// skip the file if you don't want to copy func CopyDir(src, dst, skip string) error { s := cp.Options{Skip: func(src string) (bool, error) { return strings.Contains(strings.ToLower(src), skip), nil @@ -50,23 +68,69 @@ func CopyDir(src, dst, skip string) error { return cp.Copy(src, dst, s) } +// CopyDirContains copies the directory from the source to the destination +// contain is the file if you want to copy +func CopyDirContains(src, dst, contain string) error { + var filelist []string + err := filepath.Walk(src, func(path string, f os.FileInfo, err error) error { + if !f.IsDir() && strings.Contains(strings.ToLower(f.Name()), contain) { + filelist = append(filelist, path) + } + return err + }) + if err != nil { + return err + } + if err := os.MkdirAll(dst, 0755); err != nil { + return err + } + for index, file := range filelist { + // p = dir/index_file + p := fmt.Sprintf("%s/%d_%s", dst, index, BaseDir(file)) + err = CopyFile(file, p) + if err != nil { + return err + } + } + return nil +} + +// CopyFile copies the file from the source to the destination +func CopyFile(src, dst string) error { + // TODO: Handle read file error + d, err := ioutil.ReadFile(src) + if err != nil { + return err + } + err = ioutil.WriteFile(dst, d, 0777) + if err != nil { + return err + } + return nil +} + +// Filename returns the filename from the provided path func Filename(browser, item, ext string) string { replace := strings.NewReplacer(" ", "_", ".", "_", "-", "_") return strings.ToLower(fmt.Sprintf("%s_%s.%s", replace.Replace(browser), item, ext)) } +// ParentDir returns the parent directory of the provided path func ParentDir(p string) string { return filepath.Dir(filepath.Clean(p)) } +// BaseDir returns the base directory of the provided path func BaseDir(p string) string { return filepath.Base(p) } +// ParentBaseDir returns the parent base directory of the provided path func ParentBaseDir(p string) string { return BaseDir(ParentDir(p)) } +// CompressDir compresses the directory into a zip file func CompressDir(dir string) error { files, err := ioutil.ReadDir(dir) if err != nil {