mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-07-06 21:37:47 +02:00
Merge pull request #200 from moonD4rk/fix/profile-folder
feat: add full-export browsing data option
This commit is contained in:
@@ -40,7 +40,7 @@ func (c *ChromiumBookmark) Parse(masterKey []byte) error {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// TODO: refactor with go generics
|
|
||||||
sort.Slice(*c, func(i, j int) bool {
|
sort.Slice(*c, func(i, j int) bool {
|
||||||
return (*c)[i].DateAdded.After((*c)[j].DateAdded)
|
return (*c)[i].DateAdded.After((*c)[j].DateAdded)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ type Source interface {
|
|||||||
Length() int
|
Length() int
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(sources []item.Item) *Data {
|
func New(items []item.Item) *Data {
|
||||||
bd := &Data{
|
bd := &Data{
|
||||||
sources: make(map[item.Item]Source),
|
sources: make(map[item.Item]Source),
|
||||||
}
|
}
|
||||||
bd.addSource(sources)
|
bd.addSources(items)
|
||||||
return bd
|
return bd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ func (d *Data) Recovery(masterKey []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Data) Output(dir, browserName, flag string) {
|
func (d *Data) Output(dir, browserName, flag string) {
|
||||||
output := NewOutPutter(flag)
|
output := newOutPutter(flag)
|
||||||
|
|
||||||
for _, source := range d.sources {
|
for _, source := range d.sources {
|
||||||
if source.Length() == 0 {
|
if source.Length() == 0 {
|
||||||
@@ -72,8 +72,8 @@ func (d *Data) Output(dir, browserName, flag string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Data) addSource(Sources []item.Item) {
|
func (d *Data) addSources(items []item.Item) {
|
||||||
for _, source := range Sources {
|
for _, source := range items {
|
||||||
switch source {
|
switch source {
|
||||||
case item.ChromiumPassword:
|
case item.ChromiumPassword:
|
||||||
d.sources[source] = &password.ChromiumPassword{}
|
d.sources[source] = &password.ChromiumPassword{}
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ import (
|
|||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OutPutter struct {
|
type outPutter struct {
|
||||||
json bool
|
json bool
|
||||||
csv bool
|
csv bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutPutter(flag string) *OutPutter {
|
func newOutPutter(flag string) *outPutter {
|
||||||
o := &OutPutter{}
|
o := &outPutter{}
|
||||||
if flag == "json" {
|
if flag == "json" {
|
||||||
o.json = true
|
o.json = true
|
||||||
} else {
|
} else {
|
||||||
@@ -28,7 +28,7 @@ func NewOutPutter(flag string) *OutPutter {
|
|||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OutPutter) Write(data Source, writer io.Writer) error {
|
func (o *outPutter) Write(data Source, writer io.Writer) error {
|
||||||
switch o.json {
|
switch o.json {
|
||||||
case true:
|
case true:
|
||||||
encoder := json.NewEncoder(writer)
|
encoder := json.NewEncoder(writer)
|
||||||
@@ -45,7 +45,7 @@ func (o *OutPutter) Write(data Source, writer io.Writer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OutPutter) CreateFile(dir, filename string) (*os.File, error) {
|
func (o *outPutter) CreateFile(dir, filename string) (*os.File, error) {
|
||||||
if filename == "" {
|
if filename == "" {
|
||||||
return nil, errors.New("empty filename")
|
return nil, errors.New("empty filename")
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ func (o *OutPutter) CreateFile(dir, filename string) (*os.File, error) {
|
|||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OutPutter) Ext() string {
|
func (o *outPutter) Ext() string {
|
||||||
if o.json {
|
if o.json {
|
||||||
return "json"
|
return "json"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
func TestNewOutPutter(t *testing.T) {
|
func TestNewOutPutter(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
out := NewOutPutter("json")
|
out := newOutPutter("json")
|
||||||
if out == nil {
|
if out == nil {
|
||||||
t.Error("New() returned nil")
|
t.Error("New() returned nil")
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-12
@@ -17,9 +17,10 @@ type Browser interface {
|
|||||||
// Name is browser's name
|
// Name is browser's name
|
||||||
Name() string
|
Name() string
|
||||||
// BrowsingData returns all browsing data in the browser.
|
// BrowsingData returns all browsing data in the browser.
|
||||||
BrowsingData() (*browingdata.Data, error)
|
BrowsingData(isFullExport bool) (*browingdata.Data, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PickBrowsers returns a list of browsers that match the name and profile.
|
||||||
func PickBrowsers(name, profile string) ([]Browser, error) {
|
func PickBrowsers(name, profile string) ([]Browser, error) {
|
||||||
var browsers []Browser
|
var browsers []Browser
|
||||||
clist := pickChromium(name, profile)
|
clist := pickChromium(name, profile)
|
||||||
@@ -42,18 +43,18 @@ func pickChromium(name, profile string) []Browser {
|
|||||||
name = strings.ToLower(name)
|
name = strings.ToLower(name)
|
||||||
if name == "all" {
|
if name == "all" {
|
||||||
for _, v := range chromiumList {
|
for _, v := range chromiumList {
|
||||||
if !fileutil.FolderExists(filepath.Clean(v.profilePath)) {
|
if !fileutil.IsDirExists(filepath.Clean(v.profilePath)) {
|
||||||
log.Noticef("find browser %s failed, profile folder does not exist", v.name)
|
log.Noticef("find browser %s failed, profile folder does not exist", v.name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if multiChromium, err := chromium.New(v.name, v.storage, v.profilePath, v.items); err == nil {
|
multiChromium, err := chromium.New(v.name, v.storage, v.profilePath, v.items)
|
||||||
log.Noticef("find browser %s success", v.name)
|
if err != nil {
|
||||||
for _, b := range multiChromium {
|
log.Errorf("new chromium error: %v", err)
|
||||||
log.Noticef("find browser %s success", b.Name())
|
continue
|
||||||
browsers = append(browsers, b)
|
}
|
||||||
}
|
for _, b := range multiChromium {
|
||||||
} else {
|
log.Noticef("find browser %s success", b.Name())
|
||||||
log.Errorf("new chromium error: %s", err.Error())
|
browsers = append(browsers, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,7 +62,7 @@ func pickChromium(name, profile string) []Browser {
|
|||||||
if profile == "" {
|
if profile == "" {
|
||||||
profile = c.profilePath
|
profile = c.profilePath
|
||||||
}
|
}
|
||||||
if !fileutil.FolderExists(filepath.Clean(profile)) {
|
if !fileutil.IsDirExists(filepath.Clean(profile)) {
|
||||||
log.Fatalf("find browser %s failed, profile folder does not exist", c.name)
|
log.Fatalf("find browser %s failed, profile folder does not exist", c.name)
|
||||||
}
|
}
|
||||||
chromiumList, err := chromium.New(c.name, c.storage, profile, c.items)
|
chromiumList, err := chromium.New(c.name, c.storage, profile, c.items)
|
||||||
@@ -86,7 +87,7 @@ func pickFirefox(name, profile string) []Browser {
|
|||||||
} else {
|
} else {
|
||||||
profile = fileutil.ParentDir(profile)
|
profile = fileutil.ParentDir(profile)
|
||||||
}
|
}
|
||||||
if !fileutil.FolderExists(filepath.Clean(profile)) {
|
if !fileutil.IsDirExists(filepath.Clean(profile)) {
|
||||||
log.Noticef("find browser firefox %s failed, profile folder does not exist", v.name)
|
log.Noticef("find browser firefox %s failed, profile folder does not exist", v.name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func New(name, storage, profilePath string, items []item.Item) ([]*Chromium, err
|
|||||||
profilePath: profilePath,
|
profilePath: profilePath,
|
||||||
items: items,
|
items: items,
|
||||||
}
|
}
|
||||||
multiItemPaths, err := c.getMultiItemPath(c.profilePath, c.items)
|
multiItemPaths, err := c.userItemPaths(c.profilePath, c.items)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -48,8 +48,13 @@ func (c *Chromium) Name() string {
|
|||||||
return c.name
|
return c.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Chromium) BrowsingData() (*browingdata.Data, error) {
|
func (c *Chromium) BrowsingData(isFullExport bool) (*browingdata.Data, error) {
|
||||||
b := browingdata.New(c.items)
|
items := c.items
|
||||||
|
if !isFullExport {
|
||||||
|
items = item.FilterSensitiveItems(c.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
data := browingdata.New(items)
|
||||||
|
|
||||||
if err := c.copyItemToLocal(); err != nil {
|
if err := c.copyItemToLocal(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -61,10 +66,10 @@ func (c *Chromium) BrowsingData() (*browingdata.Data, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.masterKey = masterKey
|
c.masterKey = masterKey
|
||||||
if err := b.Recovery(c.masterKey); err != nil {
|
if err := data.Recovery(c.masterKey); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return b, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Chromium) copyItemToLocal() error {
|
func (c *Chromium) copyItemToLocal() error {
|
||||||
@@ -72,7 +77,7 @@ func (c *Chromium) copyItemToLocal() error {
|
|||||||
filename := i.String()
|
filename := i.String()
|
||||||
var err error
|
var err error
|
||||||
switch {
|
switch {
|
||||||
case fileutil.FolderExists(path):
|
case fileutil.IsDirExists(path):
|
||||||
if i == item.ChromiumLocalStorage {
|
if i == item.ChromiumLocalStorage {
|
||||||
err = fileutil.CopyDir(path, filename, "lock")
|
err = fileutil.CopyDir(path, filename, "lock")
|
||||||
}
|
}
|
||||||
@@ -89,8 +94,8 @@ func (c *Chromium) copyItemToLocal() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Chromium) getMultiItemPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
|
// userItemPaths return a map of user to item path, map[profile 1][item's name & path key pair]
|
||||||
// multiItemPaths is a map of user to item path, map[profile 1][item's name & path key pair]
|
func (c *Chromium) userItemPaths(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
|
||||||
multiItemPaths := make(map[string]map[item.Item]string)
|
multiItemPaths := make(map[string]map[item.Item]string)
|
||||||
parentDir := fileutil.ParentDir(profilePath)
|
parentDir := fileutil.ParentDir(profilePath)
|
||||||
err := filepath.Walk(parentDir, chromiumWalkFunc(items, multiItemPaths))
|
err := filepath.Walk(parentDir, chromiumWalkFunc(items, multiItemPaths))
|
||||||
@@ -120,6 +125,7 @@ func (c *Chromium) getMultiItemPath(profilePath string, items []item.Item) (map[
|
|||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// chromiumWalkFunc return a filepath.WalkFunc to find item's path
|
||||||
func chromiumWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
|
func chromiumWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
|
||||||
return func(path string, info fs.FileInfo, err error) error {
|
return func(path string, info fs.FileInfo, err error) error {
|
||||||
for _, v := range items {
|
for _, v := range items {
|
||||||
@@ -145,7 +151,7 @@ func chromiumWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item
|
|||||||
func fillLocalStoragePath(itemPaths map[item.Item]string, storage item.Item) {
|
func fillLocalStoragePath(itemPaths map[item.Item]string, storage item.Item) {
|
||||||
if p, ok := itemPaths[item.ChromiumHistory]; ok {
|
if p, ok := itemPaths[item.ChromiumHistory]; ok {
|
||||||
lsp := filepath.Join(filepath.Dir(p), storage.FileName())
|
lsp := filepath.Join(filepath.Dir(p), storage.FileName())
|
||||||
if fileutil.FolderExists(lsp) {
|
if fileutil.IsDirExists(lsp) {
|
||||||
itemPaths[item.ChromiumLocalStorage] = lsp
|
itemPaths[item.ChromiumLocalStorage] = lsp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -22,34 +23,34 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *Chromium) GetMasterKey() ([]byte, error) {
|
func (c *Chromium) GetMasterKey() ([]byte, error) {
|
||||||
var (
|
|
||||||
cmd *exec.Cmd
|
|
||||||
stdout, stderr bytes.Buffer
|
|
||||||
)
|
|
||||||
// don't need chromium key file for macOS
|
// don't need chromium key file for macOS
|
||||||
defer os.Remove(item.TempChromiumKey)
|
defer os.Remove(item.TempChromiumKey)
|
||||||
// Get the master key from the keychain
|
// Get the master key from the keychain
|
||||||
// $ security find-generic-password -wa 'Chrome'
|
// $ security find-generic-password -wa 'Chrome'
|
||||||
cmd = exec.Command("security", "find-generic-password", "-wa", strings.TrimSpace(c.storage)) //nolint:gosec
|
var (
|
||||||
|
stdout, stderr bytes.Buffer
|
||||||
|
)
|
||||||
|
cmd := exec.Command("security", "find-generic-password", "-wa", strings.TrimSpace(c.storage)) //nolint:gosec
|
||||||
cmd.Stdout = &stdout
|
cmd.Stdout = &stdout
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
err := cmd.Run()
|
if err := cmd.Run(); err != nil {
|
||||||
if err != nil {
|
return nil, fmt.Errorf("run security command failed: %w, message %s", err, stderr.String())
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if stderr.Len() > 0 {
|
if stderr.Len() > 0 {
|
||||||
if strings.Contains(stderr.String(), "could not be found") {
|
if strings.Contains(stderr.String(), "could not be found") {
|
||||||
return nil, errCouldNotFindInKeychain
|
return nil, errCouldNotFindInKeychain
|
||||||
}
|
}
|
||||||
return nil, errors.New(stderr.String())
|
return nil, errors.New(stderr.String())
|
||||||
}
|
}
|
||||||
chromeSecret := bytes.TrimSpace(stdout.Bytes())
|
|
||||||
if chromeSecret == nil {
|
secret := bytes.TrimSpace(stdout.Bytes())
|
||||||
|
if len(secret) == 0 {
|
||||||
return nil, errWrongSecurityCommand
|
return nil, errWrongSecurityCommand
|
||||||
}
|
}
|
||||||
chromeSalt := []byte("saltysalt")
|
salt := []byte("saltysalt")
|
||||||
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_mac.mm;l=157
|
// @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)
|
key := pbkdf2.Key(secret, salt, 1003, 16, sha1.New)
|
||||||
if key == nil {
|
if key == nil {
|
||||||
return nil, errWrongSecurityCommand
|
return nil, errWrongSecurityCommand
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package chromium
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"errors"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/godbus/dbus/v5"
|
"github.com/godbus/dbus/v5"
|
||||||
@@ -17,12 +17,13 @@ import (
|
|||||||
|
|
||||||
func (c *Chromium) GetMasterKey() ([]byte, error) {
|
func (c *Chromium) GetMasterKey() ([]byte, error) {
|
||||||
// what is d-bus @https://dbus.freedesktop.org/
|
// what is d-bus @https://dbus.freedesktop.org/
|
||||||
var chromiumSecret []byte
|
// don't need chromium key file for Linux
|
||||||
|
defer os.Remove(item.TempChromiumKey)
|
||||||
|
|
||||||
conn, err := dbus.SessionBus()
|
conn, err := dbus.SessionBus()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer os.Remove(item.TempChromiumKey)
|
|
||||||
svc, err := keyring.GetSecretService(conn)
|
svc, err := keyring.GetSecretService(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -40,6 +41,7 @@ func (c *Chromium) GetMasterKey() ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var secret []byte
|
||||||
for _, col := range collections {
|
for _, col := range collections {
|
||||||
items, err := col.GetAllItems()
|
items, err := col.GetAllItems()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -54,19 +56,20 @@ func (c *Chromium) GetMasterKey() ([]byte, error) {
|
|||||||
if label == c.storage {
|
if label == c.storage {
|
||||||
se, err := i.GetSecret(session.Path())
|
se, err := i.GetSecret(session.Path())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("get storage from dbus error:" + err.Error())
|
return nil, fmt.Errorf("get storage from dbus error: %v" + err.Error())
|
||||||
}
|
}
|
||||||
chromiumSecret = se.Value
|
secret = se.Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if chromiumSecret == nil {
|
|
||||||
// @https://source.chromium.org/chromium/chromium/src/+/main:components/os_crypt/os_crypt_linux.cc;l=100
|
if len(secret) == 0 {
|
||||||
chromiumSecret = []byte("peanuts")
|
// set default secret @https://source.chromium.org/chromium/chromium/src/+/main:components/os_crypt/os_crypt_linux.cc;l=100
|
||||||
|
secret = []byte("peanuts")
|
||||||
}
|
}
|
||||||
chromiumSalt := []byte("saltysalt")
|
salt := []byte("saltysalt")
|
||||||
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_linux.cc
|
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_linux.cc
|
||||||
key := pbkdf2.Key(chromiumSecret, chromiumSalt, 1, 16, sha1.New)
|
key := pbkdf2.Key(secret, salt, 1, 16, sha1.New)
|
||||||
c.masterKey = key
|
c.masterKey = key
|
||||||
log.Infof("%s initialized master key success", c.name)
|
log.Infof("%s initialized master key success", c.name)
|
||||||
return key, nil
|
return key, nil
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
|
"github.com/moond4rk/HackBrowserData/crypto"
|
||||||
"github.com/moond4rk/HackBrowserData/item"
|
"github.com/moond4rk/HackBrowserData/item"
|
||||||
"github.com/moond4rk/HackBrowserData/log"
|
"github.com/moond4rk/HackBrowserData/log"
|
||||||
"github.com/moond4rk/HackBrowserData/utils/fileutil"
|
"github.com/moond4rk/HackBrowserData/utils/fileutil"
|
||||||
@@ -17,20 +18,22 @@ import (
|
|||||||
var errDecodeMasterKeyFailed = errors.New("decode master key failed")
|
var errDecodeMasterKeyFailed = errors.New("decode master key failed")
|
||||||
|
|
||||||
func (c *Chromium) GetMasterKey() ([]byte, error) {
|
func (c *Chromium) GetMasterKey() ([]byte, error) {
|
||||||
keyFile, err := fileutil.ReadFile(item.TempChromiumKey)
|
b, err := fileutil.ReadFile(item.TempChromiumKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer os.Remove(keyFile)
|
defer os.Remove(item.TempChromiumKey)
|
||||||
encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key")
|
|
||||||
|
encryptedKey := gjson.Get(b, "os_crypt.encrypted_key")
|
||||||
if !encryptedKey.Exists() {
|
if !encryptedKey.Exists() {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
|
|
||||||
|
key, err := base64.StdEncoding.DecodeString(encryptedKey.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errDecodeMasterKeyFailed
|
return nil, errDecodeMasterKeyFailed
|
||||||
}
|
}
|
||||||
c.masterKey, err = crypto.DPAPI(pureKey[5:])
|
c.masterKey, err = crypto.DPAPI(key[5:])
|
||||||
log.Infof("%s initialized master key success", c.name)
|
log.Infof("%s initialized master key success", c.name)
|
||||||
return c.masterKey, err
|
return c.masterKey, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func New(name, storage, profilePath string, items []item.Item) ([]*Firefox, erro
|
|||||||
firefoxList := make([]*Firefox, 0, len(multiItemPaths))
|
firefoxList := make([]*Firefox, 0, len(multiItemPaths))
|
||||||
for name, itemPaths := range multiItemPaths {
|
for name, itemPaths := range multiItemPaths {
|
||||||
firefoxList = append(firefoxList, &Firefox{
|
firefoxList = append(firefoxList, &Firefox{
|
||||||
name: fmt.Sprintf("Firefox-%s", name),
|
name: fmt.Sprintf("firefox-%s", name),
|
||||||
items: typeutil.Keys(itemPaths),
|
items: typeutil.Keys(itemPaths),
|
||||||
itemPaths: itemPaths,
|
itemPaths: itemPaths,
|
||||||
})
|
})
|
||||||
@@ -87,8 +87,13 @@ func (f *Firefox) Name() string {
|
|||||||
return f.name
|
return f.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firefox) BrowsingData() (*browingdata.Data, error) {
|
func (f *Firefox) BrowsingData(isFullExport bool) (*browingdata.Data, error) {
|
||||||
b := browingdata.New(f.items)
|
items := f.items
|
||||||
|
if !isFullExport {
|
||||||
|
items = item.FilterSensitiveItems(f.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := browingdata.New(items)
|
||||||
|
|
||||||
if err := f.copyItemToLocal(); err != nil {
|
if err := f.copyItemToLocal(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ var (
|
|||||||
verbose bool
|
verbose bool
|
||||||
compress bool
|
compress bool
|
||||||
profilePath string
|
profilePath string
|
||||||
|
isFullExport bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -36,27 +37,26 @@ func Execute() {
|
|||||||
&cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &outputDir, Value: "results", Usage: "export dir"},
|
&cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &outputDir, Value: "results", Usage: "export dir"},
|
||||||
&cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "file name csv|json"},
|
&cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "file name csv|json"},
|
||||||
&cli.StringFlag{Name: "profile-path", Aliases: []string{"p"}, Destination: &profilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
|
&cli.StringFlag{Name: "profile-path", Aliases: []string{"p"}, Destination: &profilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
|
||||||
|
&cli.BoolFlag{Name: "full-export", Aliases: []string{"full"}, Destination: &isFullExport, Value: true, Usage: "is export full browsing data"},
|
||||||
},
|
},
|
||||||
HideHelpCommand: true,
|
HideHelpCommand: true,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
if verbose {
|
if verbose {
|
||||||
log.Init("debug")
|
log.SetVerbose()
|
||||||
} else {
|
|
||||||
log.Init("notice")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
browsers, err := browser.PickBrowsers(browserName, profilePath)
|
browsers, err := browser.PickBrowsers(browserName, profilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, b := range browsers {
|
for _, b := range browsers {
|
||||||
data, err := b.BrowsingData()
|
data, err := b.BrowsingData(isFullExport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
data.Output(outputDir, b.Name(), outputFormat)
|
data.Output(outputDir, b.Name(), outputFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
if compress {
|
if compress {
|
||||||
if err = fileutil.CompressDir(outputDir); err != nil {
|
if err = fileutil.CompressDir(outputDir); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
|||||||
+7
-7
@@ -63,15 +63,15 @@ type nssPBE struct {
|
|||||||
func (n nssPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) {
|
func (n nssPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) {
|
||||||
glmp := append(globalSalt, masterPwd...)
|
glmp := append(globalSalt, masterPwd...)
|
||||||
hp := sha1.Sum(glmp)
|
hp := sha1.Sum(glmp)
|
||||||
s := append(hp[:], n.entrySalt()...)
|
s := append(hp[:], n.salt()...)
|
||||||
chp := sha1.Sum(s)
|
chp := sha1.Sum(s)
|
||||||
pes := paddingZero(n.entrySalt(), 20)
|
pes := paddingZero(n.salt(), 20)
|
||||||
tk := hmac.New(sha1.New, chp[:])
|
tk := hmac.New(sha1.New, chp[:])
|
||||||
tk.Write(pes)
|
tk.Write(pes)
|
||||||
pes = append(pes, n.entrySalt()...)
|
pes = append(pes, n.salt()...)
|
||||||
k1 := hmac.New(sha1.New, chp[:])
|
k1 := hmac.New(sha1.New, chp[:])
|
||||||
k1.Write(pes)
|
k1.Write(pes)
|
||||||
tkPlus := append(tk.Sum(nil), n.entrySalt()...)
|
tkPlus := append(tk.Sum(nil), n.salt()...)
|
||||||
k2 := hmac.New(sha1.New, chp[:])
|
k2 := hmac.New(sha1.New, chp[:])
|
||||||
k2.Write(tkPlus)
|
k2.Write(tkPlus)
|
||||||
k := append(k1.Sum(nil), k2.Sum(nil)...)
|
k := append(k1.Sum(nil), k2.Sum(nil)...)
|
||||||
@@ -79,7 +79,7 @@ func (n nssPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) {
|
|||||||
return des3Decrypt(k[:24], iv, n.encrypted())
|
return des3Decrypt(k[:24], iv, n.encrypted())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n nssPBE) entrySalt() []byte {
|
func (n nssPBE) salt() []byte {
|
||||||
return n.AlgoAttr.SaltAttr.EntrySalt
|
return n.AlgoAttr.SaltAttr.EntrySalt
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,12 +136,12 @@ type slatAttr struct {
|
|||||||
|
|
||||||
func (m metaPBE) Decrypt(globalSalt, masterPwd []byte) (key2 []byte, err error) {
|
func (m metaPBE) Decrypt(globalSalt, masterPwd []byte) (key2 []byte, err error) {
|
||||||
k := sha1.Sum(globalSalt)
|
k := sha1.Sum(globalSalt)
|
||||||
key := pbkdf2.Key(k[:], m.entrySalt(), m.iterationCount(), m.keySize(), sha256.New)
|
key := pbkdf2.Key(k[:], m.salt(), m.iterationCount(), m.keySize(), sha256.New)
|
||||||
iv := append([]byte{4, 14}, m.iv()...)
|
iv := append([]byte{4, 14}, m.iv()...)
|
||||||
return aes128CBCDecrypt(key, iv, m.encrypted())
|
return aes128CBCDecrypt(key, iv, m.encrypted())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m metaPBE) entrySalt() []byte {
|
func (m metaPBE) salt() []byte {
|
||||||
return m.AlgoAttr.Data.Data.SlatAttr.EntrySalt
|
return m.AlgoAttr.Data.Data.SlatAttr.EntrySalt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
|
var iv = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
|
||||||
|
|
||||||
func Chromium(key, encryptPass []byte) ([]byte, error) {
|
func Chromium(key, encryptPass []byte) ([]byte, error) {
|
||||||
if len(encryptPass) <= 3 {
|
if len(encryptPass) <= 3 {
|
||||||
return nil, errPasswordIsEmpty
|
return nil, errPasswordIsEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
iv := []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
|
|
||||||
return aes128CBCDecrypt(key, iv, encryptPass[3:])
|
return aes128CBCDecrypt(key, iv, encryptPass[3:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
|
var iv = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
|
||||||
|
|
||||||
func Chromium(key, encryptPass []byte) ([]byte, error) {
|
func Chromium(key, encryptPass []byte) ([]byte, error) {
|
||||||
if len(encryptPass) < 3 {
|
if len(encryptPass) < 3 {
|
||||||
return nil, errPasswordIsEmpty
|
return nil, errPasswordIsEmpty
|
||||||
}
|
}
|
||||||
|
return aes128CBCDecrypt(key, iv, encryptPass[3:])
|
||||||
chromeIV := []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
|
|
||||||
return aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DPAPI(data []byte) ([]byte, error) {
|
func DPAPI(data []byte) ([]byte, error) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Chromium(key, encryptPass []byte) ([]byte, error) {
|
func Chromium(key, encryptPass []byte) ([]byte, error) {
|
||||||
if len(encryptPass) < 3 {
|
if len(encryptPass) < 15 {
|
||||||
return nil, errPasswordIsEmpty
|
return nil, errPasswordIsEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ type dataBlob struct {
|
|||||||
pbData *byte
|
pbData *byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlob(d []byte) *dataBlob {
|
func newBlob(d []byte) *dataBlob {
|
||||||
if len(d) == 0 {
|
if len(d) == 0 {
|
||||||
return &dataBlob{}
|
return &dataBlob{}
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ func DPAPI(data []byte) ([]byte, error) {
|
|||||||
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
|
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
|
||||||
procLocalFree := dllKernel.NewProc("LocalFree")
|
procLocalFree := dllKernel.NewProc("LocalFree")
|
||||||
var outBlob dataBlob
|
var outBlob dataBlob
|
||||||
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
|
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(newBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
|
||||||
if r == 0 {
|
if r == 0 {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ require (
|
|||||||
github.com/ppacher/go-dbus-keyring v1.0.1
|
github.com/ppacher/go-dbus-keyring v1.0.1
|
||||||
github.com/syndtr/goleveldb v1.0.0
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
github.com/tidwall/gjson v1.14.4
|
github.com/tidwall/gjson v1.14.4
|
||||||
github.com/urfave/cli/v2 v2.23.0
|
github.com/urfave/cli/v2 v2.25.0
|
||||||
golang.org/x/crypto v0.7.0
|
golang.org/x/crypto v0.7.0
|
||||||
golang.org/x/exp v0.0.0-20230307190834-24139beb5833
|
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0
|
||||||
golang.org/x/text v0.8.0
|
golang.org/x/text v0.8.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
|||||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
github.com/urfave/cli/v2 v2.23.0 h1:pkly7gKIeYv3olPAeNajNpLjeJrmTPYCoZWaV+2VfvE=
|
github.com/urfave/cli/v2 v2.25.0 h1:ykdZKuQey2zq0yin/l7JOm9Mh+pg72ngYMeB0ABn6q8=
|
||||||
github.com/urfave/cli/v2 v2.23.0/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
|
github.com/urfave/cli/v2 v2.25.0/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||||
@@ -65,8 +65,8 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRT
|
|||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
|
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 h1:LGJsf5LRplCck6jUCH3dBL2dmycNruWNF5xugkSlfXw=
|
||||||
golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
|||||||
@@ -121,6 +121,31 @@ func (i Item) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSensitive returns whether the item is sensitive data
|
||||||
|
// password, cookie, credit card, master key is unlimited
|
||||||
|
func (i Item) IsSensitive() bool {
|
||||||
|
switch i {
|
||||||
|
case ChromiumKey, ChromiumCookie, ChromiumPassword, ChromiumCreditCard,
|
||||||
|
FirefoxKey4, FirefoxPassword, FirefoxCookie, FirefoxCreditCard,
|
||||||
|
YandexPassword, YandexCreditCard:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterSensitiveItems returns the sensitive items
|
||||||
|
func FilterSensitiveItems(items []Item) []Item {
|
||||||
|
var filtered []Item
|
||||||
|
for _, item := range items {
|
||||||
|
if item.IsSensitive() {
|
||||||
|
filtered = append(filtered, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultFirefox returns the default items for the firefox browser
|
||||||
var DefaultFirefox = []Item{
|
var DefaultFirefox = []Item{
|
||||||
FirefoxKey4,
|
FirefoxKey4,
|
||||||
FirefoxPassword,
|
FirefoxPassword,
|
||||||
@@ -133,6 +158,7 @@ var DefaultFirefox = []Item{
|
|||||||
FirefoxExtension,
|
FirefoxExtension,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultYandex returns the default items for the yandex browser
|
||||||
var DefaultYandex = []Item{
|
var DefaultYandex = []Item{
|
||||||
ChromiumKey,
|
ChromiumKey,
|
||||||
ChromiumCookie,
|
ChromiumCookie,
|
||||||
@@ -145,6 +171,7 @@ var DefaultYandex = []Item{
|
|||||||
YandexCreditCard,
|
YandexCreditCard,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultChromium returns the default items for the chromium browser
|
||||||
var DefaultChromium = []Item{
|
var DefaultChromium = []Item{
|
||||||
ChromiumKey,
|
ChromiumKey,
|
||||||
ChromiumPassword,
|
ChromiumPassword,
|
||||||
|
|||||||
+9
-8
@@ -8,19 +8,20 @@ import (
|
|||||||
|
|
||||||
var std = &slog.SugaredLogger{}
|
var std = &slog.SugaredLogger{}
|
||||||
|
|
||||||
func Init(l string) {
|
func init() {
|
||||||
if l == "debug" {
|
std = newStdLogger(slog.NoticeLevel)
|
||||||
std = newStdLogger(slog.DebugLevel)
|
}
|
||||||
} else {
|
|
||||||
std = newStdLogger(slog.NoticeLevel)
|
// SetVerbose set log level to debug
|
||||||
}
|
func SetVerbose() {
|
||||||
|
std = newStdLogger(slog.DebugLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
const template = "[{{level}}] [{{caller}}] {{message}} {{data}} {{extra}}\n"
|
const template = "[{{level}}] [{{caller}}] {{message}} {{data}} {{extra}}\n"
|
||||||
|
|
||||||
// NewStdLogger instance
|
// newStdLogger is a new std logger
|
||||||
func newStdLogger(level slog.Level) *slog.SugaredLogger {
|
func newStdLogger(level slog.Level) *slog.SugaredLogger {
|
||||||
return slog.NewSugaredLogger(os.Stdout, level).Configure(func(sl *slog.SugaredLogger) {
|
return slog.NewSugaredLogger(os.Stdout, level).Config(func(sl *slog.SugaredLogger) {
|
||||||
sl.SetName("stdLogger")
|
sl.SetName("stdLogger")
|
||||||
sl.ReportCaller = true
|
sl.ReportCaller = true
|
||||||
sl.CallerSkip = 7
|
sl.CallerSkip = 7
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
cp "github.com/otiai10/copy"
|
cp "github.com/otiai10/copy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileExists checks if the file exists in the provided path
|
// IsFileExists checks if the file exists in the provided path
|
||||||
func FileExists(filename string) bool {
|
func IsFileExists(filename string) bool {
|
||||||
info, err := os.Stat(filename)
|
info, err := os.Stat(filename)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return false
|
return false
|
||||||
@@ -25,9 +25,9 @@ func FileExists(filename string) bool {
|
|||||||
return !info.IsDir()
|
return !info.IsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FolderExists checks if the folder exists
|
// IsDirExists checks if the folder exists
|
||||||
func FolderExists(foldername string) bool {
|
func IsDirExists(folder string) bool {
|
||||||
info, err := os.Stat(foldername)
|
info, err := os.Stat(folder)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -39,8 +39,8 @@ func FolderExists(foldername string) bool {
|
|||||||
|
|
||||||
// FilesInFolder returns the filepath contains in the provided folder
|
// FilesInFolder returns the filepath contains in the provided folder
|
||||||
func FilesInFolder(dir, filename string) ([]string, error) {
|
func FilesInFolder(dir, filename string) ([]string, error) {
|
||||||
if !FolderExists(dir) {
|
if !IsDirExists(dir) {
|
||||||
return nil, errors.New(dir + " folder does not exist")
|
return nil, errors.New(dir + "folder does not exist")
|
||||||
}
|
}
|
||||||
var files []string
|
var files []string
|
||||||
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
|
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
|
||||||
@@ -114,7 +114,7 @@ func ItemName(browser, item, ext string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BrowserName(browser, user string) string {
|
func BrowserName(browser, user string) string {
|
||||||
replace := strings.NewReplacer(" ", "_", ".", "_", "-", "_", "Profile", "User")
|
replace := strings.NewReplacer(" ", "_", ".", "_", "-", "_", "Profile", "user")
|
||||||
return strings.ToLower(fmt.Sprintf("%s_%s", replace.Replace(browser), replace.Replace(user)))
|
return strings.ToLower(fmt.Sprintf("%s_%s", replace.Replace(browser), replace.Replace(user)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user