This repository has been archived by the owner on Nov 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
firefox.go
124 lines (109 loc) · 3.2 KB
/
firefox.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"github.com/rusq/dlog"
"github.com/rusq/gonss3"
)
type BaseFirefox struct{}
// Firefox is a firefox with a go decoding.
type Firefox struct {
BaseFirefox
files []string
}
type FirefoxLogins struct {
NextID int64 `json:"nextId"`
Logins []Login `json:"logins"`
PotentiallyVulnerablePasswords []interface{} `json:"potentiallyVulnerablePasswords"`
DismissedBreachAlertsByLoginGUID interface{} `json:"dismissedBreachAlertsByLoginGUID"`
Version int64 `json:"version"`
}
type Login struct {
ID int64 `json:"id"`
Hostname string `json:"hostname"`
HTTPRealm interface{} `json:"httpRealm"`
FormSubmitURL string `json:"formSubmitURL"`
UsernameField string `json:"usernameField"`
PasswordField string `json:"passwordField"`
EncryptedUsername string `json:"encryptedUsername"`
EncryptedPassword string `json:"encryptedPassword"`
GUID string `json:"guid"`
EncType int64 `json:"encType"`
TimeCreated int64 `json:"timeCreated"`
TimeLastUsed int64 `json:"timeLastUsed"`
TimePasswordChanged int64 `json:"timePasswordChanged"`
TimesUsed int64 `json:"timesUsed"`
}
type DecryptError struct {
msg string
nssError error
}
var errNothingToDo = errors.New("nothing to do")
func (e *DecryptError) Error() string {
return fmt.Sprintf("%s: %s", e.msg, e.nssError)
}
func newDecryptError(msg string, err error) *DecryptError {
return &DecryptError{msg, err}
}
// loginFiles returns the list of profile login data files
func (f *BaseFirefox) loginFiles() ([]string, error) {
files, err := filepath.Glob(f.dbPathGlob())
dlog.Debugf("loginFiles() error: %s", err)
return files, err
}
func NewFirefox() (*Firefox, error) {
f := &Firefox{}
return f, nil
}
func (f *Firefox) Decrypt() <-chan *LoginInfo {
results := make(chan *LoginInfo)
go func() {
defer close(results)
files, err := f.loginFiles()
if err != nil {
results <- &LoginInfo{Err: err}
return
}
for _, file := range files {
li := &LoginInfo{Profile: profileName(file)}
pf, err := gonss3.New(filepath.Dir(file), []byte{})
if err != nil {
results <- li.WithError(err)
continue
}
data, err := ioutil.ReadFile(file)
if err != nil {
results <- li.WithError(err)
continue
}
var logins FirefoxLogins
if err := json.Unmarshal(data, &logins); err != nil {
results <- li.WithError(err)
continue
}
if len(logins.Logins) == 0 {
results <- li.WithError(err)
continue
}
for _, login := range logins.Logins {
li := &LoginInfo{Profile: profileName(file)}
if name, err := pf.DecryptField(login.EncryptedUsername); err != nil {
li.Username = errorField
} else {
li.Username = string(name)
}
if pass, err := pf.DecryptField(login.EncryptedPassword); err != nil {
li.Password = errorField
} else {
li.Password = string(pass)
}
li.Origin = login.Hostname
results <- li
}
}
}()
return results
}