mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-07-08 21:37:49 +02:00
feat: decrypt chrome for linux password with dbus Close #4
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[中文文档](https://github.com/moonD4rk/HackBrowserData/blob/master/README_ZH.md)
|
[中文文档](https://github.com/moonD4rk/HackBrowserData/blob/master/README_ZH.md)
|
||||||
|
|
||||||
hack-browser-data is an open-source tool that could help you export data from browser. It supports the most popular browsers on the market and runs on Windows, macOS and Linux.
|
hack-browser-data is an open-source tool that could help you decrypt data[passwords|bookmarks|cookies|history] from the browser. It supports the most popular browsers on the market and runs on Windows, macOS and Linux.
|
||||||
|
|
||||||
### Supported Browser
|
### Supported Browser
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ go build
|
|||||||
```shell
|
```shell
|
||||||
PS C:\hack> .\hack.exe -h
|
PS C:\hack> .\hack.exe -h
|
||||||
NAME:
|
NAME:
|
||||||
hack-browser-data - Export passwords/cookies/history/bookmarks from browser
|
hack-browser-data - Decrypt passwords/cookies/history/bookmarks from browser
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
[hack-browser-data -b chrome -f json -dir results -e all]
|
[hack-browser-data -b chrome -f json -dir results -e all]
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[中文文档](https://github.com/moonD4rk/HackBrowserData/blob/master/README_ZH.md)
|
[中文文档](https://github.com/moonD4rk/HackBrowserData/blob/master/README_ZH.md)
|
||||||
|
|
||||||
hack-browser-data 是一个浏览器数据(密码|历史记录|Cookies|书签)导出工具,支持全平台主流浏览器。
|
hack-browser-data 是一个解密浏览器数据(密码|历史记录|Cookies|书签)的导出工具,支持全平台主流浏览器。
|
||||||
|
|
||||||
### 各平台浏览器支持情况
|
### 各平台浏览器支持情况
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -23,7 +23,7 @@ func Execute() {
|
|||||||
Name: "hack-browser-data",
|
Name: "hack-browser-data",
|
||||||
Usage: "Export passwords/cookies/history/bookmarks from browser",
|
Usage: "Export passwords/cookies/history/bookmarks from browser",
|
||||||
UsageText: "[hack-browser-data -b chrome -f json -dir results -e all]\n Get all data(password/cookie/history/bookmark) from chrome",
|
UsageText: "[hack-browser-data -b chrome -f json -dir results -e all]\n Get all data(password/cookie/history/bookmark) from chrome",
|
||||||
Version: "0.1.7",
|
Version: "0.1.8",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "Verbose"},
|
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "Verbose"},
|
||||||
&cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browser, Value: "all", Usage: "Available browsers: all|" + strings.Join(core.ListBrowser(), "|")},
|
&cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browser, Value: "all", Usage: "Available browsers: all|" + strings.Join(core.ListBrowser(), "|")},
|
||||||
@@ -63,6 +63,5 @@ func Execute() {
|
|||||||
err := app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
ErrDataNotSupported = errors.New(`not supported, default is "all", choose from history|password|bookmark|cookie`)
|
ErrDataNotSupported = errors.New(`not supported, default is "all", choose from history|password|bookmark|cookie`)
|
||||||
ErrBrowserNotSupported = errors.New("browser not supported")
|
ErrBrowserNotSupported = errors.New("browser not supported")
|
||||||
|
ErrChromeSecretIsEmpty = errors.New("chrome secret is empty")
|
||||||
chromiumParseList = map[string]FileList{
|
chromiumParseList = map[string]FileList{
|
||||||
cookie: {
|
cookie: {
|
||||||
name: cookie,
|
name: cookie,
|
||||||
|
|||||||
@@ -60,10 +60,13 @@ func (c *chromium) InitSecretKey() error {
|
|||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
temp := stdout.Bytes()
|
temp := stdout.Bytes()
|
||||||
chromePass := temp[:len(temp)-1]
|
chromeSecret := temp[:len(temp)-1]
|
||||||
|
if chromeSecret == nil {
|
||||||
|
return ErrChromeSecretIsEmpty
|
||||||
|
}
|
||||||
var chromeSalt = []byte("saltysalt")
|
var chromeSalt = []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(chromePass, chromeSalt, 1003, 16, sha1.New)
|
key := pbkdf2.Key(chromeSecret, chromeSalt, 1003, 16, sha1.New)
|
||||||
c.SecretKey = key
|
c.SecretKey = key
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-23
@@ -1,18 +1,17 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"errors"
|
"github.com/godbus/dbus/v5"
|
||||||
|
keyring "github.com/ppacher/go-dbus-keyring"
|
||||||
"hack-browser-data/log"
|
"hack-browser-data/log"
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fireFoxProfilePath = "/home/*/.mozilla/firefox/*.default-release/"
|
fireFoxProfilePath = "/home/*/.mozilla/firefox/*.default-release/"
|
||||||
fireFoxCommand = ""
|
chromeProfilePath = "/home/*/.config/google-chrome/*/"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -24,35 +23,67 @@ var (
|
|||||||
}{
|
}{
|
||||||
"firefox": {
|
"firefox": {
|
||||||
ProfilePath: fireFoxProfilePath,
|
ProfilePath: fireFoxProfilePath,
|
||||||
Name: fireFoxCommand,
|
Name: firefoxName,
|
||||||
New: decryptFirefox,
|
New: decryptFirefox,
|
||||||
},
|
},
|
||||||
|
"chrome": {
|
||||||
|
ProfilePath: chromeProfilePath,
|
||||||
|
Name: chromeName,
|
||||||
|
New: decryptChromium,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *chromium) InitSecretKey() error {
|
func (c *chromium) InitSecretKey() error {
|
||||||
var (
|
//what is d-bus @https://dbus.freedesktop.org/
|
||||||
cmd *exec.Cmd
|
var chromeSecret []byte
|
||||||
stdout, stderr bytes.Buffer
|
conn, err := dbus.SessionBus()
|
||||||
)
|
|
||||||
//➜ security find-generic-password -wa 'Chrome'
|
|
||||||
cmd = exec.Command("security", "find-generic-password", "-wa", c.Name)
|
|
||||||
cmd.Stdout = &stdout
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if stderr.Len() > 0 {
|
svc, err := keyring.GetSecretService(conn)
|
||||||
err = errors.New(stderr.String())
|
if err != nil {
|
||||||
log.Error(err)
|
return err
|
||||||
|
}
|
||||||
|
session, err := svc.OpenSession()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err = session.Close(); err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
collections, err := svc.GetAllCollections()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, col := range collections {
|
||||||
|
items, err := col.GetAllItems()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, item := range items {
|
||||||
|
i, err := item.GetLabel()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i == "Chrome Safe Storage" {
|
||||||
|
se, err := item.GetSecret(session.Path())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
chromeSecret = se.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
temp := stdout.Bytes()
|
|
||||||
chromePass := temp[:len(temp)-1]
|
|
||||||
var chromeSalt = []byte("saltysalt")
|
var chromeSalt = []byte("saltysalt")
|
||||||
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_mac.mm;l=157
|
if chromeSecret == nil {
|
||||||
key := pbkdf2.Key(chromePass, chromeSalt, 1003, 16, sha1.New)
|
return ErrChromeSecretIsEmpty
|
||||||
|
}
|
||||||
|
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_linux.cc
|
||||||
|
key := pbkdf2.Key(chromeSecret, chromeSalt, 1, 16, sha1.New)
|
||||||
c.SecretKey = key
|
c.SecretKey = key
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-15
@@ -136,7 +136,6 @@ func (l *Logins) ChromeParse(key []byte) error {
|
|||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
err = loginDB.Ping()
|
|
||||||
rows, err := loginDB.Query(queryChromiumLogin)
|
rows, err := loginDB.Query(queryChromiumLogin)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := rows.Close(); err != nil {
|
if err := rows.Close(); err != nil {
|
||||||
@@ -206,7 +205,6 @@ func (h *History) ChromeParse(key []byte) error {
|
|||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
err = historyDB.Ping()
|
|
||||||
rows, err := historyDB.Query(queryChromiumHistory)
|
rows, err := historyDB.Query(queryChromiumHistory)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := rows.Close(); err != nil {
|
if err := rows.Close(); err != nil {
|
||||||
@@ -247,7 +245,6 @@ func (c *Cookies) ChromeParse(secretKey []byte) error {
|
|||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
err = cookieDB.Ping()
|
|
||||||
rows, err := cookieDB.Query(queryChromiumCookie)
|
rows, err := cookieDB.Query(queryChromiumCookie)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := rows.Close(); err != nil {
|
if err := rows.Close(); err != nil {
|
||||||
@@ -282,11 +279,7 @@ func (c *Cookies) ChromeParse(secretKey []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cookie.Value = string(value)
|
cookie.Value = string(value)
|
||||||
if _, ok := c.cookies[host]; ok {
|
c.cookies[host] = append(c.cookies[host], cookie)
|
||||||
c.cookies[host] = append(c.cookies[host], cookie)
|
|
||||||
} else {
|
|
||||||
c.cookies[host] = []cookies{cookie}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -412,7 +405,6 @@ func (c *Cookies) FirefoxParse() error {
|
|||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
err = cookieDB.Ping()
|
|
||||||
rows, err := cookieDB.Query(queryFirefoxCookie)
|
rows, err := cookieDB.Query(queryFirefoxCookie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@@ -441,11 +433,7 @@ func (c *Cookies) FirefoxParse() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cookie.Value = value
|
cookie.Value = value
|
||||||
if _, ok := c.cookies[host]; ok {
|
c.cookies[host] = append(c.cookies[host], cookie)
|
||||||
c.cookies[host] = append(c.cookies[host], cookie)
|
|
||||||
} else {
|
|
||||||
c.cookies[host] = []cookies{cookie}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -533,7 +521,6 @@ func getDecryptKey() (item1, item2, a11, a102 []byte, err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = keyDB.Ping()
|
|
||||||
pwdRows, err = keyDB.Query(queryMetaData)
|
pwdRows, err = keyDB.Query(queryMetaData)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := pwdRows.Close(); err != nil {
|
if err := pwdRows.Close(); err != nil {
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
|
errSecurityKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
|
||||||
errPasswordIsEmpty = errors.New("password is empty")
|
errPasswordIsEmpty = errors.New("password is empty")
|
||||||
errDecryptFailed = errors.New("decrypt failed, password is empty")
|
errDecryptFailed = errors.New("decrypt failed, password is empty")
|
||||||
|
errDbusSecretIsEmpty = errors.New("dbus secret key is empty")
|
||||||
)
|
)
|
||||||
|
|
||||||
func aes128CBCDecrypt(key, iv, encryptPass []byte) ([]byte, error) {
|
func aes128CBCDecrypt(key, iv, encryptPass []byte) ([]byte, error) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ var (
|
|||||||
func ChromePass(key, encryptPass []byte) ([]byte, error) {
|
func ChromePass(key, encryptPass []byte) ([]byte, error) {
|
||||||
if len(encryptPass) > 3 {
|
if len(encryptPass) > 3 {
|
||||||
if len(key) == 0 {
|
if len(key) == 0 {
|
||||||
return nil, errKeyIsEmpty
|
return nil, errSecurityKeyIsEmpty
|
||||||
}
|
}
|
||||||
m, err := aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
|
m, err := aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
|
||||||
return m, err
|
return m, err
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ var (
|
|||||||
func ChromePass(key, encryptPass []byte) ([]byte, error) {
|
func ChromePass(key, encryptPass []byte) ([]byte, error) {
|
||||||
if len(encryptPass) > 3 {
|
if len(encryptPass) > 3 {
|
||||||
if len(key) == 0 {
|
if len(key) == 0 {
|
||||||
return nil, errKeyIsEmpty
|
return nil, errSecurityKeyIsEmpty
|
||||||
}
|
}
|
||||||
m, err := aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
|
m, err := aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
|
||||||
return m, err
|
return m, err
|
||||||
@@ -151,18 +151,18 @@ func decryptMeta(globalSalt, masterPwd, entrySalt, encrypted []byte) ([]byte, er
|
|||||||
|
|
||||||
func decryptNss(globalSalt, masterPwd, nssIv, entrySalt, encrypted []byte, iter, keySize int) ([]byte, error) {
|
func decryptNss(globalSalt, masterPwd, nssIv, entrySalt, encrypted []byte, iter, keySize int) ([]byte, error) {
|
||||||
k := sha1.Sum(globalSalt)
|
k := sha1.Sum(globalSalt)
|
||||||
log.Println(hex.EncodeToString(k[:]))
|
log.Debug(hex.EncodeToString(k[:]))
|
||||||
key := pbkdf2.Key(k[:], entrySalt, iter, keySize, sha256.New)
|
key := pbkdf2.Key(k[:], entrySalt, iter, keySize, sha256.New)
|
||||||
log.Println(hex.EncodeToString(key))
|
log.Debug(hex.EncodeToString(key))
|
||||||
i, err := hex.DecodeString("040e")
|
i, err := hex.DecodeString("040e")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
// @https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49
|
// @https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49
|
||||||
iv := append(i, nssIv...)
|
iv := append(i, nssIv...)
|
||||||
dst, err := aes128CBCDecrypt(key, iv, encrypted)
|
dst, err := aes128CBCDecrypt(key, iv, encrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
return dst, err
|
return dst, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,18 +158,18 @@ func Nss(globalSalt, masterPwd []byte, pbe NssPBE) ([]byte, error) {
|
|||||||
|
|
||||||
func decryptMeta(globalSalt, masterPwd, nssIv, entrySalt, encrypted []byte, iter, keySize int) ([]byte, error) {
|
func decryptMeta(globalSalt, masterPwd, nssIv, entrySalt, encrypted []byte, iter, keySize int) ([]byte, error) {
|
||||||
k := sha1.Sum(globalSalt)
|
k := sha1.Sum(globalSalt)
|
||||||
log.Println(hex.EncodeToString(k[:]))
|
log.Debug(hex.EncodeToString(k[:]))
|
||||||
key := pbkdf2.Key(k[:], entrySalt, iter, keySize, sha256.New)
|
key := pbkdf2.Key(k[:], entrySalt, iter, keySize, sha256.New)
|
||||||
log.Println(hex.EncodeToString(key))
|
log.Debug(hex.EncodeToString(key))
|
||||||
i, err := hex.DecodeString("040e")
|
i, err := hex.DecodeString("040e")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
// @https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49
|
// @https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49
|
||||||
iv := append(i, nssIv...)
|
iv := append(i, nssIv...)
|
||||||
dst, err := aes128CBCDecrypt(key, iv, encrypted)
|
dst, err := aes128CBCDecrypt(key, iv, encrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
return dst, err
|
return dst, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ module hack-browser-data
|
|||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/godbus/dbus/v5 v5.0.3
|
||||||
github.com/jszwec/csvutil v1.3.0
|
github.com/jszwec/csvutil v1.3.0
|
||||||
github.com/mattn/go-sqlite3 v1.14.0
|
github.com/mattn/go-sqlite3 v1.14.0
|
||||||
|
github.com/ppacher/go-dbus-keyring v1.0.1
|
||||||
github.com/stretchr/testify v1.6.1 // indirect
|
github.com/stretchr/testify v1.6.1 // indirect
|
||||||
github.com/tidwall/gjson v1.6.0
|
github.com/tidwall/gjson v1.6.0
|
||||||
github.com/urfave/cli/v2 v2.2.0
|
github.com/urfave/cli/v2 v2.2.0
|
||||||
|
|||||||
@@ -6,12 +6,16 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSY
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
|
||||||
|
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/jszwec/csvutil v1.3.0 h1:d0zzXKQYvc22b4La5Wcp97CDgQ7JDLGJLm2NWqJGEYg=
|
github.com/jszwec/csvutil v1.3.0 h1:d0zzXKQYvc22b4La5Wcp97CDgQ7JDLGJLm2NWqJGEYg=
|
||||||
github.com/jszwec/csvutil v1.3.0/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
|
github.com/jszwec/csvutil v1.3.0/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
|
||||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/ppacher/go-dbus-keyring v1.0.1 h1:dM4dMfP5w9MxY+foFHCQiN7izEGpFdKr3tZeMGmvqD0=
|
||||||
|
github.com/ppacher/go-dbus-keyring v1.0.1/go.mod h1:JEmkRwBVPBFkOHedAsoZALWmhNJxR/R/ykkFpbEHtGE=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||||
|
|||||||
Reference in New Issue
Block a user