diff --git a/.env.example b/.env.example
deleted file mode 100644
index 775f70b..0000000
--- a/.env.example
+++ /dev/null
@@ -1 +0,0 @@
-DB_PASSWORD=password
\ No newline at end of file
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
deleted file mode 100644
index 2595b0b..0000000
--- a/.github/workflows/check.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
-# https://github.com/marketplace/actions/check-code-formatting-using-gofmt
-
-name: Go
-
-on: [push, pull_request]
-
-jobs:
- check-formatting:
- runs-on: ubuntu-latest
- steps:
-
- - uses: actions/checkout@v3
-
- - name: Check formatting
- uses: Jerome1337/gofmt-action@v1.0.5
- with:
- gofmt-path: '.'
- gofmt-flags: '-l -d'
-
- build-and-test:
- runs-on: ubuntu-latest
- steps:
-
- - uses: actions/checkout@v3
-
- - name: Set up Go
- uses: actions/setup-go@v3
- with:
- go-version: 1.19
-
- - name: Build
- run: go build -v ./...
-
- - name: Test
- run: go test -v ./...
-
- build-docker-images:
- runs-on: ubuntu-latest
- steps:
-
- - uses: actions/checkout@v3
-
- - name: Build the Docker image
- run: docker compose build
-
diff --git a/.gitignore b/.gitignore
index 69b774b..c6bb7a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,8 +6,6 @@
*.dylib
boltcard
createboltcard/createboltcard
-wipeboltcard/wipeboltcard
-cli/cli
# Test binary, built with `go test -c`
*.test
@@ -18,9 +16,9 @@ cli/cli
# Dependency directories (remove the comment below to include it)
# vendor/
-# possible secrets
+# secrets
tls.cert
*.macaroon*
+add_test_data.sql
Caddyfile
boltcard.service
-*.secret
diff --git a/Caddyfile_docker b/Caddyfile_docker
deleted file mode 100644
index e32ab53..0000000
--- a/Caddyfile_docker
+++ /dev/null
@@ -1,2 +0,0 @@
-https://card.yourdomain.com
-reverse_proxy boltcard_main:9000
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 90c6cc3..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,7 +0,0 @@
-FROM golang:1.19.0-bullseye
-
-WORKDIR /App
-ADD . /App
-RUN go build
-
-ENTRYPOINT ["/App/boltcard"]
diff --git a/README.md b/README.md
index b8e55c5..8d5c7fb 100644
--- a/README.md
+++ b/README.md
@@ -8,27 +8,18 @@ Each bolt card makes use of a service to receive the request from the merchant s
The 'bolt card service' software provided here can be used to host bolt cards for yourself and others.
-The simplest way to understand and set up your own system is to read the main document set below.
+The 'bolt card creation' instructions describe how to set up bolt cards for use with your bolt card service.
-## Main document set
+## Documents
| Document | Description |
| --- | --- |
-| [System](docs/SYSTEM.md) | Bolt card system overview |
| [Specification](docs/SPEC.md) | Bolt card specifications |
-| [Privacy](docs/CARD_PRIVACY.md) | Bolt card privacy |
-| [Docker Service Install](docs/DOCKER_INSTALL.md) | Bolt card service docker installation |
-| [Automatic Card Creation](docs/CARD_ANDROID.md) | Bolt card creation using the Bolt Card app|
-
-## Additional
-| Document | Description |
-| --- | --- |
+| [System](docs/SYSTEM.md) | Bolt card system overview |
| [Service Install](docs/INSTALL.md) | Bolt card service installation |
-| [Manual Card Creation](docs/CARD_MANUAL.md) | Bolt card creation using NXP TagXplorer software |
-| [LndHub Payments](docs/LNDHUB.md) | How to use LndHub |
+| [Automatic Card Creation](docs/CARD_ANDROID.md) | Bolt card creation using the Bolt Card app|
+| [Manual Card Creation](docs/CARD_MANUAL.md) | Bolt card creation using NXP TagXplorer software|
| [FAQ](docs/FAQ.md) | Frequently asked questions |
-| [Datasheet](docs/NT4H2421Gx.pdf) | NXP NTAG424DNA datasheet |
-| [Application Note](docs/NT4H2421Gx.pdf) | NXP NTAG424DNA features and hints |
## Telegram group
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index e44b628..0000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Security Policy
-
-Report issues you find by Telegram secret chat to `@peter_1337` .
-Please do not disclose any possible security vulnerabilities to third parties.
diff --git a/add_card_data.sql b/add_card_data.sql
new file mode 100644
index 0000000..c693091
--- /dev/null
+++ b/add_card_data.sql
@@ -0,0 +1,26 @@
+\c card_db
+
+INSERT INTO cards (
+ lock_key, /* this is key 0 on the card */
+ aes_cmac, /* this is key 2 on the card */
+ uid, /* this can be discovered from the service log */
+ last_counter_value, /* can start at zero and will be updated on first use (before issue) */
+ lnurlw_request_timeout_sec, /* 60 seconds by default */
+ enable_flag, /* useful for quickly switching card hosting on/off */
+ tx_limit_sats, /* set at a reasonable value for small test payments in 2022 */
+ day_limit_sats, /* set at a reasonable value for small test payments in 2022 */
+ card_description, /* to store a human readable card description (optional) */
+ one_time_code_used /* used to indicate if the one_time_code for card creation is live */
+)
+ VALUES (
+ '00000000000000000000000000000000',
+ '00000000000000000000000000000000',
+ '00000000000000',
+ 0,
+ 60,
+ 'Y',
+ 1000,
+ 10000,
+ 'bolt card',
+ 'Y'
+ );
diff --git a/boltcard.service b/boltcard.service
index 6ab02b1..42a2ef1 100644
--- a/boltcard.service
+++ b/boltcard.service
@@ -10,14 +10,41 @@ Restart=always
RestartSec=10
User=ubuntu
-# postgres database connection settings
+# boltcard service settings
+
+# LOG_LEVEL is DEBUG or PRODUCTION
+Environment="LOG_LEVEL=DEBUG"
+
+# AES_DECRYPT_KEY is the hex value of the server decrypt key for hosted bolt cards
+Environment="AES_DECRYPT_KEY=00000000000000000000000000000000"
+
+# DB_ values are for the postgres database connection
Environment="DB_HOST=localhost"
Environment="DB_PORT=5432"
Environment="DB_USER=cardapp"
Environment="DB_PASSWORD=database_password"
Environment="DB_NAME=card_db"
-ExecStart=/bin/bash /home/ubuntu/boltcard/script/s_launch
+# HOST_DOMAIN is the URL base prefix for the lnurlw calls
+Environment="HOST_DOMAIN=card.yourdomain.com"
+
+# MIN_WITHDRAW_SATS & MAX_WITHDRAW_SATS set the values for the lnurlw response
+Environment="MIN_WITHDRAW_SATS=1"
+Environment="MAX_WITHDRAW_SATS=1000000"
+
+# LN_ values are for the lightning server used for making payments
+Environment="LN_HOST=ln.host.io"
+Environment="LN_PORT=10009"
+Environment="LN_TLS_FILE=/home/ubuntu/boltcard/tls.cert"
+Environment="LN_MACAROON_FILE=/home/ubuntu/boltcard/SendPaymentV2.macaroon"
+
+# FEE_LIMIT_SAT is the maximum lightning network fee to be paid
+Environment="FEE_LIMIT_SAT=10"
+
+# LN_TESTNODE may be used in testing and will then only pay to the defined test node pubkey
+#Environment="LN_TESTNODE=000000000000000000000000000000000000000000000000000000000000000000"
+
+ExecStart=/bin/bash /home/ubuntu/boltcard/s_launch
[Install]
WantedBy=multi-user.target
diff --git a/cli/main.go b/cli/main.go
deleted file mode 100644
index b11bc1d..0000000
--- a/cli/main.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package main
-
-import (
- "bytes"
- "crypto/aes"
- "encoding/hex"
- "fmt"
- "github.com/aead/cmac"
- "github.com/boltcard/boltcard/crypto"
- "os"
-)
-
-// inspired by parse_request() in lnurlw_request.go
-
-func aes_cmac(key_sdm_file_read_mac []byte, sv2 []byte, ba_c []byte) (bool, error) {
-
- c2, err := aes.NewCipher(key_sdm_file_read_mac)
- if err != nil {
- return false, err
- }
-
- ks, err := cmac.Sum(sv2, c2, 16)
- if err != nil {
- return false, err
- }
-
- fmt.Println("ks = ", ks)
-
- c3, err := aes.NewCipher(ks)
- if err != nil {
- return false, err
- }
-
- cm, err := cmac.Sum([]byte{}, c3, 16)
- if err != nil {
- return false, err
- }
-
- fmt.Println("cm = ", cm)
-
- ct := make([]byte, 8)
- ct[0] = cm[1]
- ct[1] = cm[3]
- ct[2] = cm[5]
- ct[3] = cm[7]
- ct[4] = cm[9]
- ct[5] = cm[11]
- ct[6] = cm[13]
- ct[7] = cm[15]
-
- fmt.Println("ct = ", ct)
-
- res_cmac := bytes.Compare(ct, ba_c)
- if res_cmac != 0 {
- return false, nil
- }
-
- return true, nil
-}
-
-func check_cmac(uid []byte, ctr []byte, k2_cmac_key []byte, cmac []byte) (bool, error) {
-
- sv2 := make([]byte, 16)
- sv2[0] = 0x3c
- sv2[1] = 0xc3
- sv2[2] = 0x00
- sv2[3] = 0x01
- sv2[4] = 0x00
- sv2[5] = 0x80
- sv2[6] = uid[0]
- sv2[7] = uid[1]
- sv2[8] = uid[2]
- sv2[9] = uid[3]
- sv2[10] = uid[4]
- sv2[11] = uid[5]
- sv2[12] = uid[6]
- sv2[13] = ctr[2]
- sv2[14] = ctr[1]
- sv2[15] = ctr[0]
-
- fmt.Println("sv2 = ", sv2)
-
- cmac_verified, err := aes_cmac(k2_cmac_key, sv2, cmac)
-
- if err != nil {
- return false, err
- }
-
- return cmac_verified, nil
-}
-
-func main() {
-
- fmt.Println("-- bolt card crypto test vectors --")
- fmt.Println()
-
- args := os.Args[1:]
-
- if len(args) != 4 {
- fmt.Println("error: should have arguments for: p c aes_decrypt_key aes_cmac_key")
- os.Exit(1)
- }
-
- // get from args
- p_hex := args[0]
- c_hex := args[1]
- aes_decrypt_key_hex := args[2]
- aes_cmac_key_hex := args[3]
-
- fmt.Println("p = ", p_hex)
- fmt.Println("c = ", c_hex)
- fmt.Println("aes_decrypt_key = ", aes_decrypt_key_hex)
- fmt.Println("aes_cmac_key = ", aes_cmac_key_hex)
- fmt.Println()
-
- p, err := hex.DecodeString(p_hex)
-
- if err != nil {
- fmt.Println("ERROR: p not valid hex", err)
- os.Exit(1)
- }
-
- c, err := hex.DecodeString(c_hex)
-
- if err != nil {
- fmt.Println("ERROR: c not valid hex", err)
- os.Exit(1)
- }
-
- if len(p) != 16 {
- fmt.Println("ERROR: p length not valid")
- os.Exit(1)
- }
-
- if len(c) != 8 {
- fmt.Println("ERROR: c length not valid")
- os.Exit(1)
- }
-
- // decrypt p with aes_decrypt_key
-
- aes_decrypt_key, err := hex.DecodeString(aes_decrypt_key_hex)
-
- if err != nil {
- fmt.Println("ERROR: DecodeString() returned an error", err)
- os.Exit(1)
- }
-
- dec_p, err := crypto.Aes_decrypt(aes_decrypt_key, p)
-
- if err != nil {
- fmt.Println("ERROR: Aes_decrypt() returned an error", err)
- os.Exit(1)
- }
-
- if dec_p[0] != 0xC7 {
- fmt.Println("ERROR: decrypted data does not start with 0xC7 so is invalid")
- os.Exit(1)
- }
-
- uid := dec_p[1:8]
-
- ctr := make([]byte, 3)
- ctr[0] = dec_p[10]
- ctr[1] = dec_p[9]
- ctr[2] = dec_p[8]
-
- // set up uid & ctr for card record if needed
-
- uid_str := hex.EncodeToString(uid)
- ctr_str := hex.EncodeToString(ctr)
-
- fmt.Println("decrypted card data : uid", uid_str, ", ctr", ctr_str)
-
- // check cmac
-
- aes_cmac_key, err := hex.DecodeString(aes_cmac_key_hex)
-
- if err != nil {
- fmt.Println("ERROR: aes_cmac_key is not valid hex", err)
- os.Exit(1)
- }
-
- cmac_valid, err := check_cmac(uid, ctr, aes_cmac_key, c)
-
- if err != nil {
- fmt.Println("ERROR: check_cmac() returned an error", err)
- os.Exit(1)
- }
-
- if cmac_valid == false {
- fmt.Println("ERROR: cmac incorrect")
- os.Exit(1)
- }
-
- fmt.Println("cmac validates ok")
- os.Exit(0)
-}
diff --git a/create_db.sql b/create_db.sql
new file mode 100644
index 0000000..15e4c56
--- /dev/null
+++ b/create_db.sql
@@ -0,0 +1,42 @@
+DROP DATABASE IF EXISTS card_db;
+CREATE DATABASE card_db;
+
+CREATE USER cardapp WITH PASSWORD 'database_password';
+
+\c card_db;
+
+CREATE TABLE cards (
+ card_id INT GENERATED ALWAYS AS IDENTITY,
+ lock_key CHAR(32) NOT NULL,
+ aes_cmac CHAR(32) NOT NULL,
+ uid CHAR(14) NOT NULL,
+ last_counter_value INTEGER NOT NULL,
+ lnurlw_request_timeout_sec INT NOT NULL,
+ enable_flag CHAR(1) NOT NULL DEFAULT 'N',
+ tx_limit_sats INT NOT NULL,
+ day_limit_sats INT NOT NULL,
+ card_description VARCHAR(100) NOT NULL DEFAULT '',
+ one_time_code CHAR(32) NOT NULL DEFAULT '',
+ one_time_code_expiry TIMESTAMPTZ DEFAULT NOW() + INTERVAL '1 DAY',
+ one_time_code_used CHAR(1) NOT NULL DEFAULT 'Y',
+ PRIMARY KEY(card_id)
+);
+
+CREATE TABLE card_payments (
+ card_payment_id INT GENERATED ALWAYS AS IDENTITY,
+ card_id INT NOT NULL,
+ k1 CHAR(32) UNIQUE NOT NULL,
+ lnurlw_request_time TIMESTAMPTZ NOT NULL,
+ ln_invoice VARCHAR(1024) NOT NULL DEFAULT '',
+ amount_msats BIGINT CHECK (amount_msats > 0),
+ paid_flag CHAR(1) NOT NULL,
+ payment_time TIMESTAMPTZ,
+ payment_status VARCHAR(100) NOT NULL DEFAULT '',
+ failure_reason VARCHAR(100) NOT NULL DEFAULT '',
+ payment_status_time TIMESTAMPTZ,
+ PRIMARY KEY(card_payment_id),
+ CONSTRAINT fk_card FOREIGN KEY(card_id) REFERENCES cards(card_id)
+);
+
+GRANT ALL PRIVILEGES ON TABLE cards TO cardapp;
+GRANT ALL PRIVILEGES ON TABLE card_payments TO cardapp;
diff --git a/createboltcard/database.go b/createboltcard/database.go
new file mode 100644
index 0000000..9dce657
--- /dev/null
+++ b/createboltcard/database.go
@@ -0,0 +1,76 @@
+package main
+
+import (
+ "database/sql"
+ "errors"
+ "fmt"
+ _ "github.com/lib/pq"
+ "os"
+)
+
+func db_open() (*sql.DB, error) {
+
+ // get connection string from environment variables
+
+ conn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
+ os.Getenv("DB_HOST"),
+ os.Getenv("DB_PORT"),
+ os.Getenv("DB_USER"),
+ os.Getenv("DB_PASSWORD"),
+ os.Getenv("DB_NAME"))
+
+ db, err := sql.Open("postgres", conn)
+ if err != nil {
+ return db, err
+ }
+
+ return db, nil
+}
+
+func db_delete_expired() error {
+
+ db, err := db_open()
+ if err != nil {
+ return err
+ }
+ defer db.Close()
+
+ // delete expired one time code records
+
+ sqlStatement := `DELETE FROM cards WHERE one_time_code_expiry < NOW() AND one_time_code_used = 'N';`
+ _, err = db.Exec(sqlStatement)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func db_insert_card(one_time_code string, lock_key string, aes_cmac string) error {
+
+ db, err := db_open()
+ if err != nil {
+ return err
+ }
+ defer db.Close()
+
+ // insert a new record into cards
+
+ sqlStatement := `INSERT INTO cards` +
+ ` (one_time_code, lock_key, aes_cmac, uid, last_counter_value,` +
+ ` lnurlw_request_timeout_sec, tx_limit_sats, day_limit_sats, one_time_code_used)` +
+ ` VALUES ($1, $2, $3, '', 0, 60, 1000, 10000, 'N');`
+ res, err := db.Exec(sqlStatement, one_time_code, lock_key, aes_cmac)
+ if err != nil {
+ return err
+ }
+ count, err := res.RowsAffected()
+ if err != nil {
+ return err
+ }
+ if count != 1 {
+ return errors.New("not one card record inserted")
+ }
+
+ return nil
+}
diff --git a/createboltcard/main.go b/createboltcard/main.go
new file mode 100644
index 0000000..6768cd5
--- /dev/null
+++ b/createboltcard/main.go
@@ -0,0 +1,51 @@
+package main
+
+import (
+ "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ log "github.com/sirupsen/logrus"
+ qrcode "github.com/skip2/go-qrcode"
+ "os"
+)
+
+func random_hex() string {
+ b := make([]byte, 16)
+ _, err := rand.Read(b)
+ if err != nil {
+ log.Warn(err.Error())
+ return ""
+ }
+
+ return hex.EncodeToString(b)
+}
+
+func main() {
+ one_time_code := random_hex()
+ lock_key := random_hex()
+ aes_cmac := random_hex()
+
+ // create the new card record
+
+ err := db_insert_card(one_time_code, lock_key, aes_cmac)
+ if err != nil {
+ log.Warn(err.Error())
+ return
+ }
+
+ // remove any expired records
+
+ err = db_delete_expired()
+ if err != nil {
+ log.Warn(err.Error())
+ return
+ }
+
+ // show a QR code on the console for the URI + one_time_code
+
+ hostdomain := os.Getenv("HOST_DOMAIN")
+ url := "https://" + hostdomain + "/new?a=" + one_time_code
+ fmt.Println(url)
+ q, err := qrcode.New(url, qrcode.Medium)
+ fmt.Println(q.ToSmallString(false))
+}
diff --git a/crypto/crypto.go b/crypto.go
similarity index 83%
rename from crypto/crypto.go
rename to crypto.go
index 1555c00..23ed884 100644
--- a/crypto/crypto.go
+++ b/crypto.go
@@ -1,4 +1,4 @@
-package crypto
+package main
import (
"bytes"
@@ -9,7 +9,7 @@ import (
"github.com/aead/cmac"
)
-func Create_k1() (string, error) {
+func create_k1() (string, error) {
// 16 bytes = 128 bits
b := make([]byte, 16)
@@ -24,7 +24,7 @@ func Create_k1() (string, error) {
}
// decrypt p with aes_dec
-func Aes_decrypt(key_sdm_file_read []byte, ba_p []byte) ([]byte, error) {
+func crypto_aes_decrypt(key_sdm_file_read []byte, ba_p []byte) ([]byte, error) {
dec_p := make([]byte, 16)
iv := make([]byte, 16)
@@ -38,7 +38,7 @@ func Aes_decrypt(key_sdm_file_read []byte, ba_p []byte) ([]byte, error) {
return dec_p, nil
}
-func Aes_cmac(key_sdm_file_read_mac []byte, sv2 []byte, ba_c []byte) (bool, error) {
+func crypto_aes_cmac(key_sdm_file_read_mac []byte, sv2 []byte, ba_c []byte) (bool, error) {
c2, err := aes.NewCipher(key_sdm_file_read_mac)
if err != nil {
diff --git a/database.go b/database.go
new file mode 100644
index 0000000..e3244dd
--- /dev/null
+++ b/database.go
@@ -0,0 +1,343 @@
+package main
+
+import (
+ "database/sql"
+ "errors"
+ "fmt"
+ _ "github.com/lib/pq"
+ "os"
+)
+
+type card struct {
+ card_id int
+ card_guid string
+ aes_dec string
+ aes_cmac string
+ db_uid string
+ last_counter_value uint32
+ lnurlw_request_timeout_sec int
+ enable_flag string
+ tx_limit_sats int
+ day_limit_sats int
+ one_time_code string
+ lock_key string
+}
+
+type payment struct {
+ card_payment_id int
+ card_id int
+ k1 string
+ paid_flag string
+}
+
+func db_open() (*sql.DB, error) {
+
+ // get connection string from environment variables
+
+ conn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
+ os.Getenv("DB_HOST"),
+ os.Getenv("DB_PORT"),
+ os.Getenv("DB_USER"),
+ os.Getenv("DB_PASSWORD"),
+ os.Getenv("DB_NAME"))
+
+ db, err := sql.Open("postgres", conn)
+ if err != nil {
+ return db, err
+ }
+
+ return db, nil
+}
+
+func db_get_new_card(one_time_code string) (*card, error) {
+ c := card{}
+
+ db, err := db_open()
+ if err != nil {
+ return &c, err
+ }
+ defer db.Close()
+
+ sqlStatement := `SELECT lock_key, aes_cmac` +
+ ` FROM cards WHERE one_time_code=$1 AND` +
+ ` one_time_code_expiry > NOW() AND one_time_code_used = 'N';`
+ row := db.QueryRow(sqlStatement, one_time_code)
+ err = row.Scan(
+ &c.lock_key,
+ &c.aes_cmac)
+ if err != nil {
+ return &c, err
+ }
+
+ sqlStatement = `UPDATE cards SET one_time_code_used = 'Y' WHERE one_time_code = $1;`
+ _, err = db.Exec(sqlStatement, one_time_code)
+ if err != nil {
+ return &c, err
+ }
+
+ return &c, nil
+}
+
+func db_get_card_from_uid(card_uid string) (*card, error) {
+
+ c := card{}
+
+ db, err := db_open()
+ if err != nil {
+ return &c, err
+ }
+ defer db.Close()
+
+ sqlStatement := `SELECT card_id, aes_cmac, uid,` +
+ ` last_counter_value, lnurlw_request_timeout_sec,` +
+ ` enable_flag, tx_limit_sats, day_limit_sats` +
+ ` FROM cards WHERE uid=$1;`
+ row := db.QueryRow(sqlStatement, card_uid)
+ err = row.Scan(
+ &c.card_id,
+ &c.aes_cmac,
+ &c.db_uid,
+ &c.last_counter_value,
+ &c.lnurlw_request_timeout_sec,
+ &c.enable_flag,
+ &c.tx_limit_sats,
+ &c.day_limit_sats)
+ if err != nil {
+ return &c, err
+ }
+
+ return &c, nil
+}
+
+func db_get_card_from_card_id(card_id int) (*card, error) {
+
+ c := card{}
+
+ db, err := db_open()
+ if err != nil {
+ return &c, err
+ }
+ defer db.Close()
+
+ sqlStatement := `SELECT card_id, aes_cmac, uid,` +
+ ` last_counter_value, lnurlw_request_timeout_sec,` +
+ ` enable_flag, tx_limit_sats, day_limit_sats` +
+ ` FROM cards WHERE card_id=$1;`
+ row := db.QueryRow(sqlStatement, card_id)
+ err = row.Scan(
+ &c.card_id,
+ &c.aes_cmac,
+ &c.db_uid,
+ &c.last_counter_value,
+ &c.lnurlw_request_timeout_sec,
+ &c.enable_flag,
+ &c.tx_limit_sats,
+ &c.day_limit_sats)
+ if err != nil {
+ return &c, err
+ }
+
+ return &c, nil
+}
+
+func db_check_lnurlw_timeout(card_payment_id int) (bool, error) {
+
+ db, err := db_open()
+ if err != nil {
+ return true, err
+ }
+ defer db.Close()
+
+ lnurlw_timeout := true
+
+ sqlStatement := `SELECT NOW() > cp.lnurlw_request_time + c.lnurlw_request_timeout_sec * INTERVAL '1 SECOND'` +
+ ` FROM card_payments AS cp INNER JOIN cards AS c ON c.card_id = cp.card_id` +
+ ` WHERE cp.card_payment_id=$1;`
+ row := db.QueryRow(sqlStatement, card_payment_id)
+ err = row.Scan(&lnurlw_timeout)
+ if err != nil {
+ return true, err
+ }
+
+ return lnurlw_timeout, nil
+}
+
+func db_check_and_update_counter(card_id int, new_counter_value uint32) (bool, error) {
+
+ db, err := db_open()
+ if err != nil {
+ return false, err
+ }
+ defer db.Close()
+
+ sqlStatement := `UPDATE cards SET last_counter_value = $2 WHERE card_id = $1` +
+ ` AND last_counter_value < $2;`
+ res, err := db.Exec(sqlStatement, card_id, new_counter_value)
+ if err != nil {
+ return false, err
+ }
+ count, err := res.RowsAffected()
+ if err != nil {
+ return false, err
+ }
+ if count != 1 {
+ return false, nil
+ }
+
+ return true, nil
+}
+
+func db_insert_payment(card_id int, k1 string) error {
+
+ db, err := db_open()
+ if err != nil {
+ return err
+ }
+ defer db.Close()
+
+ // insert a new record into card_payments with card_id & k1 set
+
+ sqlStatement := `INSERT INTO card_payments` +
+ ` (card_id, k1, paid_flag, lnurlw_request_time)` +
+ ` VALUES ($1, $2, 'N', NOW());`
+ res, err := db.Exec(sqlStatement, card_id, k1)
+ if err != nil {
+ return err
+ }
+ count, err := res.RowsAffected()
+ if err != nil {
+ return err
+ }
+ if count != 1 {
+ return errors.New("not one card_payments record inserted")
+ }
+
+ return nil
+}
+
+func db_get_payment_k1(k1 string) (*payment, error) {
+ p := payment{}
+
+ db, err := db_open()
+ if err != nil {
+ return &p, err
+ }
+ defer db.Close()
+
+ sqlStatement := `SELECT card_payment_id, card_id, paid_flag` +
+ ` FROM card_payments WHERE k1=$1;`
+ row := db.QueryRow(sqlStatement, k1)
+ err = row.Scan(
+ &p.card_payment_id,
+ &p.card_id,
+ &p.paid_flag)
+ if err != nil {
+ return &p, err
+ }
+
+ return &p, nil
+}
+
+func db_update_payment_invoice(card_payment_id int, ln_invoice string, amount_msats int64) error {
+
+ db, err := db_open()
+ if err != nil {
+ return err
+ }
+ defer db.Close()
+
+ sqlStatement := `UPDATE card_payments SET ln_invoice = $2, amount_msats = $3 WHERE card_payment_id = $1;`
+ res, err := db.Exec(sqlStatement, card_payment_id, ln_invoice, amount_msats)
+ if err != nil {
+ return err
+ }
+ count, err := res.RowsAffected()
+ if err != nil {
+ return err
+ }
+ if count != 1 {
+ return errors.New("not one card_payment record updated")
+ }
+
+ return nil
+}
+
+func db_update_payment_paid(card_payment_id int) error {
+
+ db, err := db_open()
+ if err != nil {
+ return err
+ }
+ defer db.Close()
+
+ sqlStatement := `UPDATE card_payments SET paid_flag = 'Y', payment_time = NOW() WHERE card_payment_id = $1;`
+ res, err := db.Exec(sqlStatement, card_payment_id)
+ if err != nil {
+ return err
+ }
+ count, err := res.RowsAffected()
+ if err != nil {
+ return err
+ }
+ if count != 1 {
+ return errors.New("not one card_payment record updated")
+ }
+
+ return nil
+}
+
+func db_update_payment_status(card_payment_id int, payment_status string, failure_reason string) error {
+
+ db, err := db_open()
+
+ if err != nil {
+ return err
+ }
+
+ defer db.Close()
+
+ sqlStatement := `UPDATE card_payments SET payment_status = $2, failure_reason = $3, ` +
+ `payment_status_time = NOW() WHERE card_payment_id = $1;`
+
+ res, err := db.Exec(sqlStatement, card_payment_id, payment_status, failure_reason)
+
+ if err != nil {
+ return err
+ }
+
+ count, err := res.RowsAffected()
+
+ if err != nil {
+ return err
+ }
+
+ if count != 1 {
+ return errors.New("not one card_payment record updated")
+ }
+
+ return nil
+}
+
+func db_get_card_totals(card_id int) (int, error) {
+
+ db, err := db_open()
+ if err != nil {
+ return 0, err
+ }
+ defer db.Close()
+
+ day_total_msats := 0
+
+ sqlStatement := `SELECT COALESCE(SUM(amount_msats),0) FROM card_payments ` +
+ `WHERE card_id=$1 AND paid_flag='Y' ` +
+ `AND payment_time > NOW() - INTERVAL '1 DAY';`
+ row := db.QueryRow(sqlStatement, card_id)
+ err = row.Scan(&day_total_msats)
+ if err != nil {
+ return 0, err
+ }
+
+ day_total_sats := day_total_msats / 1000
+
+ return day_total_sats, nil
+}
diff --git a/db/db.go b/db/db.go
deleted file mode 100644
index f2fb515..0000000
--- a/db/db.go
+++ /dev/null
@@ -1,1072 +0,0 @@
-package db
-
-import (
- "database/sql"
- "errors"
- "fmt"
- _ "github.com/lib/pq"
- "os"
-)
-
-type Card struct {
- Card_id int
- Card_guid string
- K0_auth_key string
- K1_decrypt_key string
- K2_cmac_key string
- K3 string
- K4 string
- Db_uid string
- Last_counter_value uint32
- Lnurlw_request_timeout_sec int
- Lnurlw_enable string
- Tx_limit_sats int
- Day_limit_sats int
- Lnurlp_enable string
- Email_address string
- Email_enable string
- Uid_privacy string
- One_time_code string
- Card_name string
- Allow_negative_balance string
- Pin_enable string
- Pin_number string
- Pin_limit_sats int
-}
-
-type Payment struct {
- Card_payment_id int
- Card_id int
- Lnurlw_k1 string
- Paid_flag string
-}
-
-type Transaction struct {
- Card_id int
- Tx_id int
- Tx_type string
- Tx_amount_msats int
- Tx_time string
-}
-
-type Card_wipe_info struct {
- Id int
- K0 string
- K1 string
- K2 string
- K3 string
- K4 string
- Uid string
-}
-
-func open() (*sql.DB, error) {
-
- // get connection string from environment variables
-
- conn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
- os.Getenv("DB_HOST"),
- os.Getenv("DB_PORT"),
- os.Getenv("DB_USER"),
- os.Getenv("DB_PASSWORD"),
- os.Getenv("DB_NAME"))
-
- db, err := sql.Open("postgres", conn)
- if err != nil {
- return db, err
- }
-
- return db, nil
-}
-
-func Get_setting(setting_name string) string {
-
- setting_value := ""
-
- db, err := open()
- if err != nil {
- return ""
- }
- defer db.Close()
-
- sqlStatement := `select value from settings where name=$1;`
-
- row := db.QueryRow(sqlStatement, setting_name)
- err = row.Scan(&setting_value)
- if err != nil {
- return ""
- }
-
- return setting_value
-}
-
-func Get_new_card(one_time_code string) (*Card, error) {
-
- c := Card{}
-
- db, err := open()
- if err != nil {
- return &c, err
- }
- defer db.Close()
-
- sqlStatement := `SELECT k0_auth_key, k2_cmac_key, k3, k4, card_name, uid_privacy` +
- ` FROM cards WHERE one_time_code=$1 AND` +
- ` one_time_code_expiry > NOW() AND one_time_code_used = 'N' AND wiped = 'N';`
- row := db.QueryRow(sqlStatement, one_time_code)
- err = row.Scan(
- &c.K0_auth_key,
- &c.K2_cmac_key,
- &c.K3,
- &c.K4,
- &c.Card_name,
- &c.Uid_privacy)
- if err != nil {
- return &c, err
- }
-
- sqlStatement = `UPDATE cards SET one_time_code_used = 'Y' WHERE one_time_code = $1;`
- _, err = db.Exec(sqlStatement, one_time_code)
- if err != nil {
- return &c, err
- }
-
- return &c, nil
-}
-
-func Get_card_count_for_uid(uid string) (int, error) {
-
- card_count := 0
-
- db, err := open()
- if err != nil {
- return 0, err
- }
- defer db.Close()
-
- sqlStatement := `select count(card_id) from cards where uid=$1 AND wiped='N';`
-
- row := db.QueryRow(sqlStatement, uid)
- err = row.Scan(&card_count)
- if err != nil {
- return 0, err
- }
-
- return card_count, nil
-}
-
-func Get_card_count_for_name_lnurlp(name string) (int, error) {
-
- card_count := 0
-
- db, err := open()
- if err != nil {
- return 0, err
- }
- defer db.Close()
-
- sqlStatement := `select count(card_id) from cards where card_name=$1 and lnurlp_enable='Y';`
-
- row := db.QueryRow(sqlStatement, name)
- err = row.Scan(&card_count)
- if err != nil {
- return 0, err
- }
-
- return card_count, nil
-}
-
-// gets the last record
-func Get_card_id_for_name(name string) (int, error) {
-
- card_id := 0
-
- db, err := open()
- if err != nil {
- return 0, err
- }
- defer db.Close()
-
- sqlStatement := `select card_id from cards where card_name=$1 order by card_id desc limit 1;`
-
- row := db.QueryRow(sqlStatement, name)
- err = row.Scan(&card_id)
- if err != nil {
- return 0, err
- }
-
- return card_id, nil
-}
-
-func Get_card_id_for_card_payment_id(card_payment_id int) (int, error) {
- card_id := 0
-
- db, err := open()
- if err != nil {
- return 0, err
- }
- defer db.Close()
-
- sqlStatement := `SELECT card_id FROM card_payments WHERE card_payment_id=$1;`
-
- row := db.QueryRow(sqlStatement, card_payment_id)
- err = row.Scan(&card_id)
- if err != nil {
- return 0, err
- }
-
- return card_id, nil
-}
-
-func Get_card_id_for_r_hash(r_hash string) (int, error) {
- card_id := 0
-
- db, err := open()
- if err != nil {
- return 0, err
- }
- defer db.Close()
-
- sqlStatement := `SELECT card_id FROM card_receipts WHERE r_hash_hex=$1;`
-
- row := db.QueryRow(sqlStatement, r_hash)
- err = row.Scan(&card_id)
- if err != nil {
- return 0, err
- }
-
- return card_id, nil
-}
-
-func Get_cards_blank_uid() ([]Card, error) {
-
- // open the database
-
- db, err := open()
-
- if err != nil {
- return nil, err
- }
-
- defer db.Close()
-
- // query the database
-
- sqlStatement := `select card_id, k2_cmac_key from cards where uid='' and last_counter_value=0 and wiped='N';`
-
- rows, err := db.Query(sqlStatement)
-
- if err != nil {
- return nil, err
- }
-
- defer rows.Close()
-
- // prepare the results
-
- var cards []Card
-
- // Loop through rows, using Scan to assign column data to struct fields.
- for rows.Next() {
- var c Card
- err := rows.Scan(&c.Card_id, &c.K2_cmac_key)
-
- if err != nil {
- return cards, err
- }
- cards = append(cards, c)
- }
-
- err = rows.Err()
-
- if err != nil {
- return cards, err
- }
-
- return cards, nil
-}
-
-func Update_card_uid_ctr(card_id int, uid string, ctr uint32) error {
- db, err := open()
- if err != nil {
- return err
- }
- defer db.Close()
-
- sqlStatement := `UPDATE cards SET uid = $2, last_counter_value = $3 WHERE card_id = $1;`
- res, err := db.Exec(sqlStatement, card_id, uid, ctr)
- if err != nil {
- return err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if count != 1 {
- return nil
- }
-
- return nil
-}
-
-func Get_card_from_uid(card_uid string) (*Card, error) {
-
- c := Card{}
-
- db, err := open()
- if err != nil {
- return &c, err
- }
- defer db.Close()
-
- sqlStatement := `SELECT card_id, k2_cmac_key, uid,` +
- ` last_counter_value, lnurlw_request_timeout_sec,` +
- ` lnurlw_enable, tx_limit_sats, day_limit_sats` +
- ` FROM cards WHERE uid=$1 AND wiped='N';`
- row := db.QueryRow(sqlStatement, card_uid)
- err = row.Scan(
- &c.Card_id,
- &c.K2_cmac_key,
- &c.Db_uid,
- &c.Last_counter_value,
- &c.Lnurlw_request_timeout_sec,
- &c.Lnurlw_enable,
- &c.Tx_limit_sats,
- &c.Day_limit_sats)
- if err != nil {
- return &c, err
- }
-
- return &c, nil
-}
-
-func Get_card_from_card_id(card_id int) (*Card, error) {
-
- c := Card{}
-
- db, err := open()
- if err != nil {
- return &c, err
- }
- defer db.Close()
-
- sqlStatement := `SELECT card_id, k2_cmac_key, uid, ` +
- `last_counter_value, lnurlw_request_timeout_sec, ` +
- `lnurlw_enable, tx_limit_sats, day_limit_sats, ` +
- `email_enable, email_address, card_name, ` +
- `allow_negative_balance, pin_enable, pin_number, ` +
- `pin_limit_sats FROM cards WHERE card_id=$1;`
- row := db.QueryRow(sqlStatement, card_id)
- err = row.Scan(
- &c.Card_id,
- &c.K2_cmac_key,
- &c.Db_uid,
- &c.Last_counter_value,
- &c.Lnurlw_request_timeout_sec,
- &c.Lnurlw_enable,
- &c.Tx_limit_sats,
- &c.Day_limit_sats,
- &c.Email_enable,
- &c.Email_address,
- &c.Card_name,
- &c.Allow_negative_balance,
- &c.Pin_enable,
- &c.Pin_number,
- &c.Pin_limit_sats)
- if err != nil {
- return &c, err
- }
-
- return &c, nil
-}
-
-// non wiped cards only
-func Get_card_from_card_name(card_name string) (*Card, error) {
-
- c := Card{}
-
- db, err := open()
- if err != nil {
- return &c, err
- }
- defer db.Close()
-
- sqlStatement := `SELECT card_id, k2_cmac_key, uid,` +
- ` last_counter_value, lnurlw_request_timeout_sec,` +
- ` lnurlw_enable, tx_limit_sats, day_limit_sats, pin_enable, pin_limit_sats` +
- ` FROM cards WHERE card_name=$1 AND wiped = 'N';`
- row := db.QueryRow(sqlStatement, card_name)
- err = row.Scan(
- &c.Card_id,
- &c.K2_cmac_key,
- &c.Db_uid,
- &c.Last_counter_value,
- &c.Lnurlw_request_timeout_sec,
- &c.Lnurlw_enable,
- &c.Tx_limit_sats,
- &c.Day_limit_sats,
- &c.Pin_enable,
- &c.Pin_limit_sats)
- if err != nil {
- return &c, err
- }
-
- return &c, nil
-}
-
-func Check_lnurlw_timeout(card_payment_id int) (bool, error) {
-
- db, err := open()
- if err != nil {
- return true, err
- }
- defer db.Close()
-
- lnurlw_timeout := true
-
- sqlStatement := `SELECT NOW() > cp.lnurlw_request_time + c.lnurlw_request_timeout_sec * INTERVAL '1 SECOND'` +
- ` FROM card_payments AS cp INNER JOIN cards AS c ON c.card_id = cp.card_id` +
- ` WHERE cp.card_payment_id=$1;`
- row := db.QueryRow(sqlStatement, card_payment_id)
- err = row.Scan(&lnurlw_timeout)
- if err != nil {
- return true, err
- }
-
- return lnurlw_timeout, nil
-}
-
-func Check_and_update_counter(card_id int, new_counter_value uint32) (bool, error) {
-
- db, err := open()
- if err != nil {
- return false, err
- }
- defer db.Close()
-
- sqlStatement := `UPDATE cards SET last_counter_value = $2 WHERE card_id = $1` +
- ` AND last_counter_value < $2;`
- res, err := db.Exec(sqlStatement, card_id, new_counter_value)
- if err != nil {
- return false, err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return false, err
- }
- if count != 1 {
- return false, nil
- }
-
- return true, nil
-}
-
-func Insert_payment(card_id int, lnurlw_k1 string) error {
-
- db, err := open()
- if err != nil {
- return err
- }
- defer db.Close()
-
- // insert a new record into card_payments with card_id & lnurlw_k1 set
-
- sqlStatement := `INSERT INTO card_payments` +
- ` (card_id, lnurlw_k1, paid_flag, lnurlw_request_time, payment_status_time)` +
- ` VALUES ($1, $2, 'N', NOW(), NOW());`
- res, err := db.Exec(sqlStatement, card_id, lnurlw_k1)
- if err != nil {
- return err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if count != 1 {
- return errors.New("not one card_payments record inserted")
- }
-
- return nil
-}
-
-func Insert_receipt(
- card_id int,
- ln_invoice string,
- r_hash_hex string,
- amount_msat int64) error {
-
- db, err := open()
- if err != nil {
- return err
- }
- defer db.Close()
-
- // insert a new record into card_receipts
-
- sqlStatement := `INSERT INTO card_receipts` +
- ` (card_id, ln_invoice, r_hash_hex, amount_msats, receipt_status_time)` +
- ` VALUES ($1, $2, $3, $4, NOW());`
- res, err := db.Exec(sqlStatement, card_id, ln_invoice, r_hash_hex, amount_msat)
- if err != nil {
- return err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if count != 1 {
- return errors.New("not one card_receipts record inserted")
- }
-
- return nil
-}
-
-func Update_receipt_state(r_hash_hex string, invoice_state string) error {
- db, err := open()
- if err != nil {
- return err
- }
- defer db.Close()
-
- sqlStatement := `UPDATE card_receipts ` +
- `SET receipt_status = $2, receipt_status_time = NOW() ` +
- `WHERE r_hash_hex = $1;`
- res, err := db.Exec(sqlStatement, r_hash_hex, invoice_state)
- if err != nil {
- return err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if count != 1 {
- return errors.New("not one card_receipts record updated")
- }
-
- return nil
-}
-
-func Get_payment_k1(lnurlw_k1 string) (*Payment, error) {
- p := Payment{}
-
- db, err := open()
- if err != nil {
- return &p, err
- }
- defer db.Close()
-
- sqlStatement := `SELECT card_payment_id, card_id, paid_flag` +
- ` FROM card_payments WHERE lnurlw_k1=$1;`
- row := db.QueryRow(sqlStatement, lnurlw_k1)
- err = row.Scan(
- &p.Card_payment_id,
- &p.Card_id,
- &p.Paid_flag)
- if err != nil {
- return &p, err
- }
-
- return &p, nil
-}
-
-func Update_payment_invoice(card_payment_id int, ln_invoice string, amount_msats int64) error {
-
- db, err := open()
- if err != nil {
- return err
- }
- defer db.Close()
-
- sqlStatement := `UPDATE card_payments SET ln_invoice = $2, amount_msats = $3 WHERE card_payment_id = $1;`
- res, err := db.Exec(sqlStatement, card_payment_id, ln_invoice, amount_msats)
- if err != nil {
- return err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if count != 1 {
- return errors.New("not one card_payments record updated")
- }
-
- return nil
-}
-
-func Update_payment_paid(card_payment_id int) error {
-
- db, err := open()
- if err != nil {
- return err
- }
- defer db.Close()
-
- sqlStatement := `UPDATE card_payments SET paid_flag = 'Y', payment_time = NOW() WHERE card_payment_id = $1;`
- res, err := db.Exec(sqlStatement, card_payment_id)
- if err != nil {
- return err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if count != 1 {
- return errors.New("not one card_payment record updated")
- }
-
- return nil
-}
-
-func Update_payment_status(card_payment_id int, payment_status string, failure_reason string) error {
-
- db, err := open()
-
- if err != nil {
- return err
- }
-
- defer db.Close()
-
- sqlStatement := `UPDATE card_payments SET payment_status = $2, failure_reason = $3, ` +
- `payment_status_time = NOW() WHERE card_payment_id = $1;`
-
- res, err := db.Exec(sqlStatement, card_payment_id, payment_status, failure_reason)
-
- if err != nil {
- return err
- }
-
- count, err := res.RowsAffected()
-
- if err != nil {
- return err
- }
-
- if count != 1 {
- return errors.New("not one card_payment record updated")
- }
-
- return nil
-}
-
-func Get_card_totals(card_id int) (int, error) {
-
- db, err := open()
- if err != nil {
- return 0, err
- }
- defer db.Close()
-
- day_total_msats := 0
-
- sqlStatement := `SELECT COALESCE(SUM(amount_msats),0) FROM card_payments ` +
- `WHERE card_id=$1 AND paid_flag='Y' ` +
- `AND payment_time > NOW() - INTERVAL '1 DAY';`
- row := db.QueryRow(sqlStatement, card_id)
- err = row.Scan(&day_total_msats)
- if err != nil {
- return 0, err
- }
-
- day_total_sats := day_total_msats / 1000
-
- return day_total_sats, nil
-}
-
-func Get_card_txs(card_id int, max_txs int) ([]Transaction, error) {
- // open the database
-
- db, err := open()
-
- if err != nil {
- return nil, err
- }
-
- defer db.Close()
-
- // query the database
-
- sqlStatement := `SELECT card_id, ` +
- `card_payments.card_payment_id AS tx_id, 'payment' AS tx_type, ` +
- `amount_msats as tx_amount_msats, ` +
- `TO_CHAR(payment_status_time, 'DD/MM/YYYY HH:MI:SS') AS tx_time ` +
- `FROM card_payments WHERE card_id = $1 AND payment_status != 'FAILED' ` +
- `AND payment_status != '' ` +
- `AND amount_msats != 0 UNION SELECT card_id, card_receipts.card_receipt_id AS tx_id, ` +
- `'receipt' AS tx_type, amount_msats as tx_amount_msats, ` +
- `TO_CHAR(receipt_status_time, 'DD/MM/YYYY HH:MI:SS') AS tx_time ` +
- `FROM card_receipts WHERE card_id = $1 ` +
- `AND receipt_status = 'SETTLED' ORDER BY tx_time DESC LIMIT $2`
-
- rows, err := db.Query(sqlStatement, card_id, max_txs)
-
- if err != nil {
- return nil, err
- }
-
- defer rows.Close()
-
- // prepare the results
-
- var transactions []Transaction
-
- // Loop through rows, using Scan to assign column data to struct fields.
- for rows.Next() {
- var t Transaction
- err := rows.Scan(&t.Card_id, &t.Tx_id, &t.Tx_type, &t.Tx_amount_msats, &t.Tx_time)
-
- if err != nil {
- return transactions, err
- }
- transactions = append(transactions, t)
- }
-
- err = rows.Err()
-
- if err != nil {
- return transactions, err
- }
-
- return transactions, nil
-}
-
-func Get_card_total_sats(card_id int) (int, error) {
-
- db, err := open()
- if err != nil {
- return 0, err
- }
-
- card_total_msats := 0
-
- sqlStatement := `SELECT COALESCE(SUM(tx_amount_msats),0) FROM (SELECT card_id, ` +
- `card_payments.card_payment_id AS tx_id, 'payment' AS tx_type, ` +
- `-amount_msats as tx_amount_msats, payment_status_time AS tx_time ` +
- `FROM card_payments WHERE card_id = $1 AND payment_status != 'FAILED' ` +
- `AND payment_status != '' ` +
- `AND amount_msats != 0 UNION SELECT card_id, card_receipts.card_receipt_id AS tx_id, ` +
- `'receipt' AS tx_type, amount_msats as tx_amount_msats, ` +
- `receipt_status_time AS tx_time FROM card_receipts WHERE card_id = $1 ` +
- `AND receipt_status = 'SETTLED' ORDER BY tx_time) AS transactions;`
-
- row := db.QueryRow(sqlStatement, card_id)
- err = row.Scan(&card_total_msats)
- if err != nil {
- return 0, err
- }
-
- card_total_sats := card_total_msats / 1000
-
- return card_total_sats, nil
-}
-
-func Get_card_name_count(card_name string) (card_count int, err error) {
-
- card_count = 0
-
- db, err := open()
- if err != nil {
- return 0, err
- }
- defer db.Close()
-
- sqlStatement := `SELECT COUNT(card_id) FROM cards WHERE card_name = $1;`
-
- row := db.QueryRow(sqlStatement, card_name)
- err = row.Scan(&card_count)
- if err != nil {
- return 0, err
- }
-
- return card_count, nil
-}
-
-func Insert_card(one_time_code string, k0_auth_key string, k2_cmac_key string, k3 string, k4 string,
- tx_limit_sats int, day_limit_sats int, lnurlw_enable bool, card_name string, uid_privacy bool,
- allow_neg_bal_ptr bool) error {
-
- lnurlw_enable_yn := "N"
- if lnurlw_enable {
- lnurlw_enable_yn = "Y"
- }
-
- uid_privacy_yn := "N"
- if uid_privacy {
- uid_privacy_yn = "Y"
- }
-
- allow_neg_bal_yn := "N"
- if allow_neg_bal_ptr {
- allow_neg_bal_yn = "Y"
- }
-
- db, err := open()
- if err != nil {
- return err
- }
- defer db.Close()
-
- // ensure any cards with the same card_name are wiped
-
- sqlStatement := `UPDATE cards SET` +
- ` lnurlw_enable = 'N', lnurlp_enable = 'N', email_enable = 'N', wiped = 'Y'` +
- ` WHERE card_name = $1;`
- res, err := db.Exec(sqlStatement, card_name)
- if err != nil {
- return err
- }
-
- // insert a new record into cards
-
- sqlStatement = `INSERT INTO cards` +
- ` (one_time_code, k0_auth_key, k2_cmac_key, k3, k4, uid, last_counter_value,` +
- ` lnurlw_request_timeout_sec, tx_limit_sats, day_limit_sats, lnurlw_enable,` +
- ` one_time_code_used, card_name, uid_privacy, allow_negative_balance)` +
- ` VALUES ($1, $2, $3, $4, $5, '', 0, 60, $6, $7, $8, 'N', $9, $10, $11);`
- res, err = db.Exec(sqlStatement, one_time_code, k0_auth_key, k2_cmac_key, k3, k4,
- tx_limit_sats, day_limit_sats, lnurlw_enable_yn, card_name, uid_privacy_yn,
- allow_neg_bal_yn)
- if err != nil {
- return err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if count != 1 {
- return errors.New("not one card record inserted")
- }
-
- return nil
-}
-
-func Insert_card_with_pin(one_time_code string, k0_auth_key string, k2_cmac_key string, k3 string, k4 string,
- tx_limit_sats int, day_limit_sats int, lnurlw_enable bool, card_name string, uid_privacy bool,
- allow_neg_bal_ptr bool, pin_enable bool, pin_number string, pin_limit_sats int) error {
-
- lnurlw_enable_yn := "N"
- if lnurlw_enable {
- lnurlw_enable_yn = "Y"
- }
-
- uid_privacy_yn := "N"
- if uid_privacy {
- uid_privacy_yn = "Y"
- }
-
- allow_neg_bal_yn := "N"
- if allow_neg_bal_ptr {
- allow_neg_bal_yn = "Y"
- }
-
- pin_enable_yn := "N"
- if pin_enable {
- pin_enable_yn = "Y"
- }
-
- db, err := open()
- if err != nil {
- return err
- }
- defer db.Close()
-
- // ensure any cards with the same card_name are wiped
-
- sqlStatement := `UPDATE cards SET` +
- ` lnurlw_enable = 'N', lnurlp_enable = 'N', email_enable = 'N', wiped = 'Y'` +
- ` WHERE card_name = $1;`
- res, err := db.Exec(sqlStatement, card_name)
- if err != nil {
- return err
- }
-
- // insert a new record into cards
-
- sqlStatement = `INSERT INTO cards` +
- ` (one_time_code, k0_auth_key, k2_cmac_key, k3, k4, uid, last_counter_value,` +
- ` lnurlw_request_timeout_sec, tx_limit_sats, day_limit_sats, lnurlw_enable,` +
- ` one_time_code_used, card_name, uid_privacy, allow_negative_balance,` +
- ` pin_enable, pin_number, pin_limit_sats)` +
- ` VALUES ($1, $2, $3, $4, $5, '', 0, 60, $6, $7, $8, 'N', $9, $10, $11, $12, $13, $14);`
- res, err = db.Exec(sqlStatement, one_time_code, k0_auth_key, k2_cmac_key, k3, k4,
- tx_limit_sats, day_limit_sats, lnurlw_enable_yn, card_name, uid_privacy_yn,
- allow_neg_bal_yn, pin_enable_yn, pin_number, pin_limit_sats)
- if err != nil {
- return err
- }
- count, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if count != 1 {
- return errors.New("not one card record inserted")
- }
-
- return nil
-}
-
-func Wipe_card(card_name string) (*Card_wipe_info, error) {
-
- card_wipe_info := Card_wipe_info{}
-
- db, err := open()
- if err != nil {
- return &card_wipe_info, err
- }
- defer db.Close()
-
- // set card as wiped and disabled
-
- sqlStatement := `UPDATE cards SET` +
- ` lnurlw_enable = 'N', lnurlp_enable = 'N', email_enable = 'N', wiped = 'Y'` +
- ` WHERE card_name = $1;`
- _, err = db.Exec(sqlStatement, card_name)
- if err != nil {
- return &card_wipe_info, err
- }
-
- // get card keys for the last card wiped
-
- sqlStatement = `SELECT card_id, uid, k0_auth_key, k2_cmac_key, k3, k4` +
- ` FROM cards WHERE card_name = $1 ORDER BY card_id DESC LIMIT 1;`
- row := db.QueryRow(sqlStatement, card_name)
- err = row.Scan(
- &card_wipe_info.Id,
- &card_wipe_info.Uid,
- &card_wipe_info.K0,
- &card_wipe_info.K2,
- &card_wipe_info.K3,
- &card_wipe_info.K4)
- if err != nil {
- return &card_wipe_info, err
- }
-
- card_wipe_info.K1 = Get_setting("AES_DECRYPT_KEY")
-
- return &card_wipe_info, nil
-}
-
-func Update_card(card_name string, lnurlw_enable bool, tx_limit_sats int,
- day_limit_sats int) error {
-
- lnurlw_enable_yn := "N"
- if lnurlw_enable {
- lnurlw_enable_yn = "Y"
- }
-
- db, err := open()
-
- if err != nil {
- return err
- }
-
- defer db.Close()
-
- sqlStatement := `UPDATE cards SET lnurlw_enable = $2, tx_limit_sats = $3, day_limit_sats = $4 ` +
- `WHERE card_name = $1 AND wiped = 'N';`
-
- res, err := db.Exec(sqlStatement, card_name, lnurlw_enable_yn, tx_limit_sats, day_limit_sats)
-
- if err != nil {
- return err
- }
-
- count, err := res.RowsAffected()
-
- if err != nil {
- return err
- }
-
- if count != 1 {
- return errors.New("not one card record updated")
- }
-
- return nil
-}
-
-func Update_card_with_pin(card_name string, lnurlw_enable bool, tx_limit_sats int, day_limit_sats int,
- pin_enable bool, pin_number string, pin_limit_sats int) error {
-
- lnurlw_enable_yn := "N"
- if lnurlw_enable {
- lnurlw_enable_yn = "Y"
- }
-
- pin_enable_yn := "N"
- if pin_enable {
- pin_enable_yn = "Y"
- }
-
- db, err := open()
-
- if err != nil {
- return err
- }
-
- defer db.Close()
-
- sqlStatement := `UPDATE cards SET lnurlw_enable = $2, tx_limit_sats = $3, day_limit_sats = $4, ` +
- `pin_enable = $5, pin_number = $6, pin_limit_sats = $7 WHERE card_name = $1 AND wiped = 'N';`
-
- res, err := db.Exec(sqlStatement, card_name, lnurlw_enable_yn, tx_limit_sats, day_limit_sats,
- pin_enable_yn, pin_number, pin_limit_sats)
-
- if err != nil {
- return err
- }
-
- count, err := res.RowsAffected()
-
- if err != nil {
- return err
- }
-
- if count != 1 {
- return errors.New("not one card record updated")
- }
-
- return nil
-}
-
-func Update_card_with_part_pin(card_name string, lnurlw_enable bool, tx_limit_sats int, day_limit_sats int,
- pin_enable bool, pin_limit_sats int) error {
-
- lnurlw_enable_yn := "N"
- if lnurlw_enable {
- lnurlw_enable_yn = "Y"
- }
-
- pin_enable_yn := "N"
- if pin_enable {
- pin_enable_yn = "Y"
- }
-
- db, err := open()
-
- if err != nil {
- return err
- }
-
- defer db.Close()
-
- sqlStatement := `UPDATE cards SET lnurlw_enable = $2, tx_limit_sats = $3, day_limit_sats = $4, ` +
- `pin_enable = $5, pin_limit_sats = $6 WHERE card_name = $1 AND wiped = 'N';`
-
- res, err := db.Exec(sqlStatement, card_name, lnurlw_enable_yn, tx_limit_sats, day_limit_sats,
- pin_enable_yn, pin_limit_sats)
-
- if err != nil {
- return err
- }
-
- count, err := res.RowsAffected()
-
- if err != nil {
- return err
- }
-
- if count != 1 {
- return errors.New("not one card record updated")
- }
-
- return nil
-}
diff --git a/docker-compose-own-reverse-proxy.yml b/docker-compose-own-reverse-proxy.yml
deleted file mode 100644
index 3457930..0000000
--- a/docker-compose-own-reverse-proxy.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-version: '3'
-services:
- boltcard:
- build:
- context: ./
- dockerfile: Dockerfile
- container_name: boltcard_main
- depends_on:
- - db
- restart: unless-stopped
- environment:
- - LOG_LEVEL=DEBUG
- - DB_HOST=db
- - DB_USER=cardapp
- - DB_PASSWORD=${DB_PASSWORD}
- - DB_PORT=5432
- - DB_NAME=card_db
- expose:
- - "9000"
- ports:
- - "8080:9000"
- volumes:
- - ${PWD}/tls.cert:/boltcard/tls.cert
- - ${PWD}/admin.macaroon:/boltcard/admin.macaroon
- networks:
- - boltnet
- db:
- image: postgres
- container_name: boltcard_db
- restart: unless-stopped
- environment:
- - POSTGRES_USER=cardapp
- - POSTGRES_PASSWORD=${DB_PASSWORD}
- - POSTGRES_DB=card_db
- - PGDATA=/var/lib/postgresql/data/pgdata
- volumes:
- - db-data:/var/lib/postgresql/data
- - ./sql/select_db.sql:/docker-entrypoint-initdb.d/select_db.sql
- - ./sql/create_db.sql:/docker-entrypoint-initdb.d/create_db.sql
- - ./sql/settings.sql:/docker-entrypoint-initdb.d/settings.sql
- expose:
- - "5432"
- networks:
- - boltnet
-networks:
- boltnet:
-volumes:
- db-data:
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index f0474e5..0000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-version: '3'
-services:
- boltcard:
- build:
- context: ./
- dockerfile: Dockerfile
- container_name: boltcard_main
- depends_on:
- - db
- restart: unless-stopped
- environment:
- - LOG_LEVEL=DEBUG
- - DB_HOST=db
- - DB_USER=cardapp
- - DB_PASSWORD=${DB_PASSWORD}
- - DB_PORT=5432
- - DB_NAME=card_db
- expose:
- - "9000"
- volumes:
- - ${PWD}/tls.cert:/boltcard/tls.cert
- - ${PWD}/admin.macaroon:/boltcard/admin.macaroon
- networks:
- - boltnet
- db:
- image: postgres
- container_name: boltcard_db
- restart: unless-stopped
- environment:
- - POSTGRES_USER=cardapp
- - POSTGRES_PASSWORD=${DB_PASSWORD}
- - POSTGRES_DB=card_db
- - PGDATA=/var/lib/postgresql/data/pgdata
- volumes:
- - db-data:/var/lib/postgresql/data
- - ./sql/select_db.sql:/docker-entrypoint-initdb.d/select_db.sql
- - ./sql/create_db.sql:/docker-entrypoint-initdb.d/create_db.sql
- - ./sql/settings.sql:/docker-entrypoint-initdb.d/settings.sql
- expose:
- - "5432"
- networks:
- - boltnet
- webserver:
- image: caddy
- restart: unless-stopped
- ports:
- - "80:80"
- - "443:443"
- - "443:443/udp"
- volumes:
- - ${PWD}/Caddyfile_docker:/etc/caddy/Caddyfile
- - caddy_data:/data
- - caddy_config:/config
- networks:
- - boltnet
-networks:
- boltnet:
-volumes:
- db-data:
- caddy_data:
- external: true
- caddy_config:
\ No newline at end of file
diff --git a/docker_init.sh b/docker_init.sh
deleted file mode 100755
index 708070c..0000000
--- a/docker_init.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-echo Enter the domain name excluding the protocol
-read domainname
-
-echo Enter your LND node gRPC domain
-read lnd_host
-
-echo LND node gRPC port
-read lnd_port
-sed -i "1s/.*/https:\/\/$domainname/" Caddyfile_docker
-sed -i "s/[(]'HOST_DOMAIN'[^)]*[)]/(\'HOST_DOMAIN\', \'$domainname\')/" sql/settings.sql
-echo writing the domain name to $domainname ...
-
-PASSWORD=$(date +%s|sha256sum|base64|head -c 32)
-if [[ ! -e .env ]]; then
- cp .env.example .env
-fi
-sed -i "s/^DB_PASSWORD=.*$/DB_PASSWORD=$PASSWORD/g" .env
-decrypt_key=$(hexdump -vn16 -e'4/4 "%08x" 1 "\n"' /dev/random)
-echo $decrypt_key
-
-sed -i "s/[(]'LOG_LEVEL'[^)]*[)]/(\'LOG_LEVEL\', \'DEBUG\')/" sql/settings.sql
-sed -i "s/[(]'AES_DECRYPT_KEY'[^)]*[)]/(\'AES_DECRYPT_KEY\', \'$decrypt_key\')/" sql/settings.sql
-sed -i "s/[(]'MIN_WITHDRAW_SATS'[^)]*[)]/(\'MIN_WITHDRAW_SATS\', \'1\')/" sql/settings.sql
-sed -i "s/[(]'MAX_WITHDRAW_SATS'[^)]*[)]/(\'MAX_WITHDRAW_SATS\', \'1000000\')/" sql/settings.sql
-sed -i "s/[(]'LN_HOST'[^)]*[)]/(\'LN_HOST\', \'$lnd_host\')/" sql/settings.sql
-sed -i "s/[(]'LN_PORT'[^)]*[)]/(\'LN_PORT\', \'$lnd_port\')/" sql/settings.sql
-sed -i "s/[(]'LN_TLS_FILE'[^)]*[)]/(\'LN_TLS_FILE\', \'\/boltcard\/tls.cert\')/" sql/settings.sql
-sed -i "s/[(]'LN_MACAROON_FILE'[^)]*[)]/(\'LN_MACAROON_FILE\', \'\/boltcard\/admin.macaroon\')/" sql/settings.sql
-sed -i "s/[(]'FEE_LIMIT_SAT'[^)]*[)]/(\'FEE_LIMIT_SAT\', \'10\')/" sql/settings.sql
-sed -i "s/[(]'FEE_LIMIT_PERCENT'[^)]*[)]/(\'FEE_LIMIT_PERCENT\', \'0.5\')/" sql/settings.sql
-sed -i "s/[(]'FUNCTION_LNURLW'[^)]*[)]/(\'FUNCTION_LNURLW\', \'ENABLE\')/" sql/settings.sql
-sed -i "s/[(]'FUNCTION_LNURLP'[^)]*[)]/(\'FUNCTION_LNURLP\', \'DISABLE\')/" sql/settings.sql
-sed -i "s/[(]'FUNCTION_EMAIL'[^)]*[)]/(\'FUNCTION_EMAIL\', \'DISABLE\')/" sql/settings.sql
-sed -i "s/[(]'LN_INVOICE_EXPIRY_SEC'[^)]*[)]/(\'LN_INVOICE_EXPIRY_SEC\', \'3600\')/" sql/settings.sql
diff --git a/docs/AN12196.pdf b/docs/AN12196.pdf
deleted file mode 100644
index c1ecbc3..0000000
Binary files a/docs/AN12196.pdf and /dev/null differ
diff --git a/docs/CARD_ANDROID.md b/docs/CARD_ANDROID.md
index 5d18179..9003956 100644
--- a/docs/CARD_ANDROID.md
+++ b/docs/CARD_ANDROID.md
@@ -2,7 +2,7 @@
## Introduction
-Here we describe how to create your own bolt cards with the Bolt Card service and the Bolt Card Android app.
+Here we describe how to create your own bolt cards with the Bolt Card Android app and the Bolt Card service.
## Resources
@@ -16,50 +16,46 @@ Here we describe how to create your own bolt cards with the Bolt Card service an
### Install the app
-- install the app from
- - source
- - apk
- - Google Play Store [Boltcard NFC Card Creator](https://play.google.com/store/apps/details?id=com.lightningnfcapp)
+- install the app from source or apk
+
+### Write the URI template to the card
+on the app
+- select `Write NFC`
+- enter your domain and path in the text entry box given
+```
+card.yourdomain.com/ln
+```
+- bring the card to the device for programming the URI template
+- select `Read NFC`
+- check that the URI looks correct
+```
+lnurlw://card.yourdomain.com/ln?c=...&p=...
+```
+- note the UID value
### Write the key values to the card
on the bolt card server
-- ensure the environment variables for the database connection are set up (see `boltcard.service`)
-this can be achieved by writing these lines to the end of the `~/.bashrc` file
-```
-echo "writing database_login to env vars"
-
-export DB_HOST=localhost
-export DB_PORT=5432
-export DB_USER=cardapp
-export DB_PASSWORD=database_password
-export DB_NAME=card_db
-
-echo "writing host_domain to env vars"
-
-export HOST_DOMAIN=card.yourdomain.com
-```
-- use the internal API to create a card
-- `$ curl 'localhost:9001/createboltcard?card_name=card_5&enable=true&tx_max=1000&day_max=10000&uid_privacy=true&allow_neg_bal=true'`
-- this will give you a one-time link
+- ensure the environment variables for the database connection are set up (see `boltcard.service`)
+- enter the `createboltcard` directory
+- `$ go build`
+- `./createboltcard`
+- this will give you a one use link in text and QR code form
on the app
-- click `scan QR code`
+- select `Key Management`
+- click `scan QR code from console`
- scan the QR code
-- the app will prompt you to hold the card for programming
-- the app will test the card and show you the results
+- bring the card to the device for programming the keys
+
+### Update the card record on the server
+on the bolt card server
+- `$ psql card_db`
+- `card_db=# select card_id, one_time_code from cards order by card_id desc limit 1;`
+- check that this is the correct record (one_time_code matches from before)
+- `card_db=# update cards set uid = 'UID value from before without the 0x prefix' where card_id=card_id from before;`
+- `card_db=# update cards set enable_flag = 'Y' where card_id=card_id from before;`
### Make a payment
- monitor the bolt card service logs
- `$ journalctl -u boltcard.service -f`
- use a PoS setup to read the bolt card, e.g. [Breez wallet](https://breez.technology/)
-
-### Update the card settings
-
-- use the internal API to update settings for a card
-- `$ curl 'localhost:9001/updateboltcard?card_name=card_5&enable=true&tx_max=100&day_max=1000'`
-
-### Wipe a card
-
-- use the internal API to wipe a card
-- `$ curl 'localhost:9001/wipeboltcard?card_name=card_5'`
-- this will mark the card as wiped and return the keys for the app to wipe the card
diff --git a/docs/CARD_MANUAL.md b/docs/CARD_MANUAL.md
index 6688650..890bcbc 100644
--- a/docs/CARD_MANUAL.md
+++ b/docs/CARD_MANUAL.md
@@ -46,10 +46,8 @@ lnurlw://card.yourdomain.com/ln
```
lnurlw://card.yourdomain.com/ln?p=00000000000000000000000000000000&c=0000000000000000
```
-
-- click after `p=` and note the p_position (41 in this case)
-
-- click after `c=` and note the c_position (76 in this case)
+- click after `p=` and note the p_position (38 in this case)
+- click after `c=` and note the c_position (73 in this case)
- select `Write To Tag`

@@ -103,7 +101,7 @@ lnurlw://card.yourdomain.com/ln?p=00000000000000000000000000000000&c=00000000000
- set up the values in the order shown
-
+
- select `Change File Settings`
diff --git a/docs/CARD_PRIVACY.md b/docs/CARD_PRIVACY.md
deleted file mode 100644
index c164df4..0000000
--- a/docs/CARD_PRIVACY.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# Card Privacy
-
-## Payment tracking
-
-This document describes the different levels of privacy possible with bolt card implementations.
-
-## Card NDEF
-
-The URI that is programmed into the card and returned as the NDEF consists of three parts.
-1. The static part
-2. The encrypted part
-3. The authentication part
-
-```
-lnurlw://card.yourdomain.com/ln?p=A2EF40F6D46F1BB36E6EBF0114D4A464&c=F509EEA788E37E32 URI example
-
-lnurlw://card.yourdomain.com/ln?p= &c= static
-
- A2EF40F6D46F1BB36E6EBF0114D4A464 encrypted
-
- F509EEA788E37E32 authentication
-```
-
-| part | use |
-|------|-----|
-| static | specfying the protocol and service location as a URI |
-| encrypted | unique id and counter values encrypted by the card |
-| authentication | a value to authenticate that the entire URI is as generated by the card |
-
-## Card privacy levels
-
-In order for the system to work, the card must provide the point-of-sale with a URL for the backend server.
-For maximum privacy, it should not be possible for the point-of-sale to identify the card any further than this.
-
-Unfortunately, early implementations do not have this fully built out.
-
-You can check your card/s by reading the NDEF value (e.g. with the NXP TagInfo app) to check for a static identifier or a static UID value. This will enable you to find the level of privacy that has been implemented on creating the card.
-
-| Privacy level | Static id | UID plaintext|
-| ------------- | --------- | ------------ |
-| minimal | yes | yes |
-| good | no | yes |
-| best | no | no |
-
-### Minimal privacy (aka tracker)
-
-An identifier is included in the static part of the lnurlw.
-This is used on the server side to look up the decryption key and the authentication key per card.
-This is how early systems were implemented and allows the point-of-sale devices to track the use of the card.
-
-### Good privacy
-
-There is no identifier included in the static part of the lnurlw.
-This is made possible by holding the decryption key at database level.
-The authentication key is still recorded per card.
-
-This protects against leaking of point-of-sale databases and log files, however, a untrustworthy point-of-sale could still obtain the card UID using proprietary NXP commands.
-
-### Best privacy
-
-There is no identifier included in the static part of the lnurlw.
-In addition, the UID field is made inaccessible by NXP proprietary commands by using the Random ID feature.
-
-This protects against individual card tracking by trustworthy and untrustworthy point-of-sale systems.
diff --git a/docs/DEEPLINK.md b/docs/DEEPLINK.md
deleted file mode 100644
index 4ac2b1a..0000000
--- a/docs/DEEPLINK.md
+++ /dev/null
@@ -1,113 +0,0 @@
-## Abstract
-
-Boltcard NFC Programmer App is a native app on iOS and Android able to program or reset NTag424 into a Boltcard, the typical steps in the setup a Boltcard are:
-
-1. The `Boltcard Service` generates the keys, and format them into a QR Code
-2. The user opens the Boltcard NFC Programmer, go to `Create Bolt Card`, scans the QR code
-3. The user then taps the card
-
-The QR code contains all the keys necessary for the app to create the Boltcard.
-
-Here are the shortcomings of this process that we aim to address in this specification:
-
-1. If the QR code get displayed on the mobile device itself, it is difficult to scan it
-2. The `Boltcard Service`, not knowing the UID when the keys are requested, isn't able to assign a specific pair of keys for the NTag424 being setup (for example, the [deterministic key generation](./DETERMINISTIC.md) needs the UID before generating the keys)
-
-## Boltcard deeplinks
-
-The solution is for the `Boltcard Service` to generate deep links with the following format: `boltcard://[program|reset]?url=[keys-request-url]`.
-
-When clicked, `Boltcard NFC Programmer` would open and either allow the user to program their NTag424 or reset it after asking for the NTags keys to the `keys-request-url`.
-
-The `Boltcard NFC Programmer` should send an HTTP POST request with `Content-Type: application/json` in the following format:
-
-```json
-{
- "UID": "[UID]"
-}
-```
-
-Or
-
-```json
-{
- "LNURLW": "lnurlw://..."
-}
-```
-
-In `curl`:
-
-```bash
-curl -X POST "[keys-request-url]" -H "Content-Type: application/json" -d '{"UID": "[UID]"}'
-```
-
-* `UID` needs to be 7 bytes. (Program action)
-* `LNURLW` needs to be read from the Boltcard's NDEF and can be sent in place of `UID`. It must contains the `p=` and `c=` arguments of the Boltcard. (Reset action)
-
-The response will be similar to the format of the QR code:
-
-```json
-{
- "LNURLW": "lnurlw://...",
- "K0":"[Key0]",
- "K1":"[Key1]",
- "K2":"[Key2]",
- "K3":"[Key3]",
- "K4":"[Key4]"
-}
-```
-
-## The Program action
-
-If `program` is specified in the Boltcard link, the `Boltcard NFC Programmer` must:
-
-1. Check if the lnurlw `NDEF` can be read.
- * If the record can be read, then the card isn't blank, an error should be displayed to the user to first reset the Boltcard.
- * If the record can't be read, assume `K0` is `00000000000000000000000000000000` authenticate and call `GetUID` on the card again. (Since `GetUID` is called after authentication, the real `UID` will be returned even if `Random UID` has been activated)
-2. Send a request to the `keys-request-url` using the UID as explained above to get the NTag424 app keys
-3. Program the Boltcard with the app keys
-
-## The Reset action
-
-If `reset` is specified in the Boltcard link, the `Boltcard NFC Programmer` must:
-1. Check if the lnurlw `NDEF` can be read.
- * If the record can't be read, then the card is already reset, show an error message to the user.
- * If the record can be read, continue to step 2.
-2. Send a request to the `keys-request-url` using the lnurlw as explained above to get the NTag424 app keys
-3. Reset the Boltcard to factory state with the app keys
-
-## Handling setup/reset cycles for Boltcard Services
-
-When a NTag424 is reset, its counter is reset too.
-This means that if the user:
-
-* Setup a Boltcard
-* Make `5` payments
-* Reset the Boltcard
-* Setup the Boltcard on same `keys-request-url`
-
-With a naive implementation, the server will expect the next counter to be above `5`, but the next payment will have a counter of `0`.
-
-More precisely, the user will need to tap the card `5` times before being able to use the Boltcard for a payment successfully again.
-
-To avoid this issue the `Boltcard Service`, if using [Deterministic key generation](./DETERMINISTIC.md), should ensure it updates the key version during a `program` action.
-
-This can be done easily by the `Boltcard Service` by adding a parameter in the `keys-request-url` which specifies that the version need to be updated.
-
-When the `Boltcard NFC Programmer` queries the URL with the UID of the card, the `Boltcard Service` will detect this parameter, and update the version.
-
-## Test vectors
-
-Here is an example of two links for respectively program the Boltcard and Reset it.
-
-```html
-
-
- Setup Boltcard
-
- |
-
- Reset Boltcard
-
-
-```
diff --git a/docs/DETERMINISTIC.md b/docs/DETERMINISTIC.md
deleted file mode 100644
index eec8171..0000000
--- a/docs/DETERMINISTIC.md
+++ /dev/null
@@ -1,216 +0,0 @@
-## Abstract
-
-The NXP NTAG424DNA allows applications to configure five application keys, named `K0`, `K1`, `K2`, `K3`, and `K4`. In the BoltCard configuration:
-
-* `K0` is the `App Master Key`, it is the only key permitted to change the application keys.
-* `K1` serves as the `encryption key` for the `PICCData`, represented by the `p=` parameter.
-* `K2` is the `authentication key` used for calculating the SUN MAC of the `PICCData`, represented by the `c=` parameter.
-* `K3` and `K4` are not used but should be configured as recommended in the [NTag424 application notes](https://www.nxp.com/docs/en/application-note/AN12196.pdf).
-
-A simple approach to issuing BoltCards would involve randomly generating the five different keys and storing them in a database.
-
-When a validation request is made, the verifier would attempt to decrypt the `p=` parameter using all existing encryption keys until finding a match. Once decrypted, the `p=` parameter would reveal the card's uid, which can then be used to retrieve the remaining keys.
-
-The primary drawback of this method is its lack of scalability. If many cards have been issued, identifying the correct encryption key could become a computationally intensive task.
-
-In this document, we propose a solution to this issue.
-
-## Keys generation
-
-First, the `LNUrl Withdraw Service` generates a `IssuerKey` that it will use to generate the keys for every NTag424.
-
-Then, configure a BoltCard as follows:
-
-* `CardKey = PRF(IssuerKey, '2d003f75' || UID || Version)`
-* `K0 = PRF(CardKey, '2d003f76')`
-* `K1 = PRF(IssuerKey, '2d003f77')`
-* `K2 = PRF(CardKey, '2d003f78')`
-* `K3 = PRF(CardKey, '2d003f79')`
-* `K4 = PRF(CardKey, '2d003f7a')`
-* `ID = PRF(IssuerKey, '2d003f7b' || UID)`
-
-With the following parameters:
-* `IssuerKey`: This 16-bytes key is used by an `LNUrl Withdraw Service` to setup all its BoltCards.
-* `UID`: This is the 7-byte ID of the card. You can retrieve it from the NTag424 using the `GetCardUID` function after identification with K1, or by decrypting the `p=` parameter, also known as `PICCData`.
-* `Version`: A 4-bytes little endian version number. This must be incremented every time the user re-programs (reset/setup) the same BoltCard on the same `LNUrl Withdraw Service`.
-
-The Pseudo Random Function `PRF(key, message)` applied during the key generation is the CMAC algorithm described in NIST Special Publication 800-38B. [See implementation notes](#notes)
-
-## How to setup a new BoltCard
-
-1. Execute `ReadData` or `ISOReaDBinary` on the BoltCard to ensure the card is blank.
-2. Execute `AuthenticateEV2First` with the application key `00000000000000000000000000000000`
-3. Fetch the `UID` with `GetCardUID`.
-4. Calculate `ID`
-5. Fetch the `State` and `Version` of the BoltCard with the specified `ID` from the database.
-6. Ensure either:
- * If no BoltCard is found, insert an entry in the database with `Version=0` and its state set to `Configured`.
- * If a BoltCard is found and its state is `Reset` then increment `Version` by `1`, and change its state to `Configured`.
-7. Generate `CardKey` with `UID` and `Version`.
-8. Calculate `K0`, `K1`, `K2`, `K3`, `K4`.
-9. [Setup the BoltCard](./CARD_MANUAL.md).
-
-## How to implement a Reset feature
-
-If a `LNUrl Withdraw Service` offers a factory reset feature for a user's BoltCard, here is the recommended procedure:
-
-1. Read the NDEF lnurlw URL, extract `p=` and `c=`.
-2. Derive `Encryption Key (K1)`, decrypt `p=` to obtain the `PICCData`.
-3. Check `PICCData[0] == 0xc7`.
-4. Calculate `ID` with the `UID` from the `PICCData`.
-5. Fetch the BoltCard's `Version` with `ID` from the database.
-6. Ensure the BoltCard's state is `Configured`.
-7. Generate `CardKey` with `UID` and `Version`.
-8. Derive `K0`, `K2`, `K3`, `K4` with `CardKey` and the `UID`.
-9. Verify that the SUN MAC in `c=` matches the one calculated using `Authentication Key (K2)`.
-10. Execute `AuthenticateEV2First` with `K0`
-11. Erase the NDEF data file using `WriteData` or `ISOUpdateBinary`
-12. Restore the NDEF file settings to default values with `ChangeFileSettings`.
-13. Use `ChangeKey` with the recovered application keys to reset `K4` through `K0` to `00000000000000000000000000000000`.
-14. Update the BoltCard's state to `Reset` in the database.
-
-Rational: Attempting to call `AuthenticateEV2First` without validating the `p=` and `c=` parameters could render the NTag inoperable after a few attempts.
-
-## How to implement a verification
-
-If a `LNUrl Withdraw Service` needs to verify a payment request, follow these steps:
-
-1. Read the NDEF lnurlw URL, extract `p=` and `c=`.
-2. Derive `Encryption Key (K1)`, decrypts `p=` to get the `PICCData`.
-3. Check `PICCData[0] == 0xc7`.
-4. Calculate `ID` with the `UID` from the `PICCData`.
-5. Fetch the BoltCard's `Version` with `ID` from the database.
-6. Ensure the BoltCard's state in the database is not `Reset`.
-7. Generate `CardKey` with `UID` and `Version`.
-8. Derive `Authentication Key (K2)` with `CardKey` and the `UID`.
-9. Verify that the SUN MAC in `c=` matches the one calculated using `Authentication Key (K2)`.
-10. Confirm that the last-seen counter for `ID` is lower than what is stored in `counter=PICCData[8..11]`. (Little Endian)
-11. Update the last-seen counter.
-
-Rationale: The `ID` is calculated to prevent the exposure of the `UID` in the `LNUrl Withdraw Service` database. This approach provides both privacy and security. Specifically, because the `UID` is used to derive keys, it is preferable not to store it outside the NTag.
-
-## Multiple IssuerKeys
-
-A single `LNUrl Withdraw Service` can own multiple `IssuerKeys`. In such cases, it will need to attempt them all to decrypt `p=`, and pick the first one which satisfies `PICCData[0] == 0xc7` and verifies the `c=` checksum.
-
-Using multiple `IssuerKeys` can decrease the impact of a compromised `Encryption Key (K1)` at the cost of performance.
-
-## Security consideration
-
-### K1 security
-
-Since `K1` is shared among multiple BoltCards, the security of this scheme is based on the following assumptions:
-
-* `K1` cannot be extracted from a legitimate NTag424.
-* BoltCard setup occurs in a trusted environment.
-
-While NXP gives assurance keys can't be extracted, a non genuine NTag424 could potentially expose these keys.
-
-Furthermore, because blank NTag424 uses the well-known initial application keys `00000000000000000000000000000000`, communication between the PCD and the PICC could be intercepted. If the BoltCard setup does not occur in a trusted environment, `K1` could be exposed during the calls to `ChangeKey`.
-
-However, if `K1` is compromised, the attacker still cannot produce a valid checksum and can only recover the `UID` for tracking purposes.
-
-Note that verifying the signature returned by `Read_Sig` can only prove NXP issued a card with a specific `UID`. It cannot prove that the current communication channel is established with an authentic NTag424. This is because the signature returned by `Read_Sig` covers only the `UID` and can therefore be replayed by a non-genuine NTag424.
-
-### Issuer database security
-
-If the issuer's database is compromised, revealing both the IssuerKey and CardKeys, it would still be infeasible for an attacker to derive `K2` and thus to forge signatures for an arbitrary card.
-
-This is because the database only stores `ID` and not the `UID` itself.
-
-## Implementation notes {#notes}
-
-Here is a C# implementation of the CMAC algorithm described in NIST Special Publication 800-38B.
-
-```csharp
-public byte[] CMac(byte[] data)
-{
- var key = _bytes;
- // SubKey generation
- // step 1, AES-128 with key K is applied to an all-zero input block.
- byte[] L = AesEncrypt(key, new byte[16], new byte[16]);
-
- // step 2, K1 is derived through the following operation:
- byte[]
- FirstSubkey =
- RotateLeft(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit.
- if ((L[0] & 0x80) == 0x80)
- FirstSubkey[15] ^=
- 0x87; // Otherwise, K1 is the exclusive-OR of const_Rb and the left-shift of L by 1 bit.
-
- // step 3, K2 is derived through the following operation:
- byte[]
- SecondSubkey =
- RotateLeft(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit.
- if ((FirstSubkey[0] & 0x80) == 0x80)
- SecondSubkey[15] ^=
- 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit.
-
- // MAC computing
- if (((data.Length != 0) && (data.Length % 16 == 0)) == true)
- {
- // If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits),
- // the last block shall be exclusive-OR'ed with K1 before processing
- for (int j = 0; j < FirstSubkey.Length; j++)
- data[data.Length - 16 + j] ^= FirstSubkey[j];
- }
- else
- {
- // Otherwise, the last block shall be padded with 10^i
- byte[] padding = new byte[16 - data.Length % 16];
- padding[0] = 0x80;
-
- data = data.Concat(padding.AsEnumerable()).ToArray();
-
- // and exclusive-OR'ed with K2
- for (int j = 0; j < SecondSubkey.Length; j++)
- data[data.Length - 16 + j] ^= SecondSubkey[j];
- }
-
- // The result of the previous process will be the input of the last encryption.
- byte[] encResult = AesEncrypt(key, new byte[16], data);
-
- byte[] HashValue = new byte[16];
- Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);
-
- return HashValue;
-}
-static byte[] RotateLeft(byte[] b)
-{
- byte[] r = new byte[b.Length];
- byte carry = 0;
-
- for (int i = b.Length - 1; i >= 0; i--)
- {
- ushort u = (ushort)(b[i] << 1);
- r[i] = (byte)((u & 0xff) + carry);
- carry = (byte)((u & 0xff00) >> 8);
- }
-
- return r;
-}
-```
-
-## Implementation
-
-* [BTCPayServer.BoltCardTools](https://github.com/btcpayserver/BTCPayServer.BoltCardTools), a BoltCard/NTag424 library in C#.
-
-## Test vectors
-
-Input:
-```
-UID: 04a39493cc8680
-Issuer Key: 00000000000000000000000000000001
-Version: 1
-```
-
-Expected:
-```
-K0: a29119fcb48e737d1591d3489557e49b
-K1: 55da174c9608993dc27bb3f30a4a7314
-K2: f4b404be700ab285e333e32348fa3d3b
-K3: 73610ba4afe45b55319691cb9489142f
-K4: addd03e52964369be7f2967736b7bdb5
-ID: e07ce1279d980ecb892a81924b67bf18
-CardKey: ebff5a4e6da5ee14cbfe720ae06fbed9
-```
\ No newline at end of file
diff --git a/docs/DOCKER_INSTALL.md b/docs/DOCKER_INSTALL.md
deleted file mode 100644
index a2d87ed..0000000
--- a/docs/DOCKER_INSTALL.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Bolt card service installation using Docker
-
-### install Docker engine and Docker compose
-
-- [Docker engine download &
- install](https://docs.docker.com/engine/install/)
-
-### Set up the boltcard server
-- Run `./docker_init.sh` to set up the initial data
-- Put the `tls.cert` file and `admin.macaroon` files in the project root directory
-
-### https setup
-
-- set up the domain A record to point to the server
-- set up the server hosting firewall to allow open access to https (port 443) only
-
-### database setup
-
-- copy the `.env.example` file to `.env` and change the database password
-
-### service bring-up and running
-```
-$ sudo groupadd docker
-$ sudo usermod -aG docker ${USER}
-(log out & in again)
-$ docker volume create caddy_data
-// add -d option for detached mode
-$ docker compose up
-```
-
-### run boltcard server with own reverse proxy
-If you already have reverse proxy in your enviroment which controls/terminates TLS connections, Boltcard server wont be ready to use, because of existence of own reverse proxy (Caddy). Caddy wont be abble to obtain TLS certificate for your domain name. Run different docker-compose, that will start Boltcard server without Caddy and your reverse proxy will handle TLS.
-
-```
-// add -d option for detached mode
-$ docker-compose up -f docker-compose-own-reverse-proxy.yml
-```
-
-
-### stop docker
-```
-$ docker compose down
-```
-To delete the database and reset the docker volume, run `docker compose down --volumes`
-*NOTE: caddy_data volume won't be removed even if you run `docker compose down --volumes` because it's an external volume. **Make sure to wipe your programmed cards before wiping the database***
-
-### check container logs
-
-- [Docker Logs](https://docs.docker.com/engine/reference/commandline/logs/)
-
-```
-$ docker logs [OPTIONS] CONTAINER
-```
-
-Run `$ docker ps` to list containers and get container names/ids
-
-#### running internal API commands
-- `docker exec boltcard_main curl 'localhost:9001/createboltcard?card_name=card_5&enable=false&tx_max=1000&day_max=10000&uid_privacy=true&allow_neg_bal=true'`
-- `docker exec boltcard_main curl 'localhost:9001/updateboltcard?card_name=card_5&enable=true&tx_max=100&day_max=1000'`
-- `docker exec boltcard_main curl 'localhost:9001/wipeboltcard?card_name=card_5'`
-- `docker exec boltcard_main curl 'localhost:9001/getboltcard?card_name=card_5'`
\ No newline at end of file
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 350ef87..bf9d7c2 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -1,36 +1,26 @@
-# How do you bech32 encode a string on the card ?
+# FAQ
+
+> How do you bech32 encode a string on the card ?
The LNURLw that comes from the bolt card is not bech32 encoded.
It uses [LUD-17](https://github.com/fiatjaf/lnurl-rfc/blob/luds/17.md).
-# How do I generate a random key value ?
+> How do I generate a random key value ?
This will give you a new 128 bit random key as a 32 character hex value.
`$ hexdump -vn16 -e'4/4 "%08x" 1 "\n"' /dev/random`
-# Why do I get a payment failure with NO_ROUTE ?
+> Why do I get a payment failure with NO_ROUTE ?
This is due to your payment lightning node not finding a route to the merchant lightning node.
It may help to open well funded channels to other well connected nodes.
-It may also help to increase your maximum network fee in your service variables, **FEE_LIMIT_SAT** / **FEE_LIMIT_PERCENT** .
+It may also help to increase your maximum network fee in your service variables, **FEE_LIMIT_SAT** .
It can be useful to test paying invoices directly from your lightning node.
-# Why do my payments take so long ?
+> Why do my payments take so long ?
+
This is due to the time taken for your payment lightning node to find a route.
It can be improved by opening channels using clearnet rather than on the tor network.
It may also help to improve your lightning node hardware or software setup.
It can be useful to test paying invoices directly from your lightning node.
-
-# Can I use the same lightning node for the customer (bolt card) and the merchant (POS) ?
-
-When tested with LND in Nov 2022, the paying (customer, bolt card) lightning node must be a separate instance to the invoicing (merchant, POS) lightning node.
-
-# I get a 6982 error when trying to program a blank card
-
-A 6982 error is is known to happen after trying to use a 'blank' card which has been wiped with the CoinCorner customer app (July 2023) and happens because the card settings have not been cleared down correctly. It can also happen where a card is removed partway through programming (which can take a few seconds) or where the mobile device does not complete programming due to being in a low battery situation.
-The card settings can be fixed by using the 'Bolt Card NFC Card Creator' app. The card will then be blank and usable again.
-- Reset Keys
-- Enter all '0's in Key 0 until the field is full and copy to Keys 1-4
-- Reset Card Now
-- present the card
diff --git a/docs/INSTALL.md b/docs/INSTALL.md
index ea4bed2..24df150 100644
--- a/docs/INSTALL.md
+++ b/docs/INSTALL.md
@@ -43,17 +43,18 @@ $ xxd -r -p SendPaymentV2.macaroon.hex SendPaymentV2.macaroon
```
### setup the boltcard server
-edit `boltcard.service` to set up the database connection
-edit `insert_settings.sql` to set up [bolt card system settings](SETTINGS.md)
+edit `boltcard.service` in the section named `boltcard service settings`
edit `Caddyfile` to set the boltcard domain name
+edit `add_card_data.sql` to set up the individual bolt card records
### database creation
edit `create_db.sql` to set the cardapp password
`$ sudo -u postgres createuser -s ubuntu`
-`$ script/s_create_db`
+`$ ./s_create_db`
### boltcard service install
-`$ script/s_build`
+`$ sudo cp boltcard.service /etc/systemd/system/boltcard.service`
+`$ ./s_build`
`$ sudo systemctl enable boltcard`
`$ sudo systemctl status boltcard`
@@ -79,41 +80,11 @@ this should respond with 'bad request' and show up in the service log
navigate to the service URL from a browser, for example `https://card.yourdomain.com/ln?2`
this should respond with 'bad request' and show up in the service log
#### bolt card
-`Environment="FUNCTION_LNURLW=ENABLE"` in `boltcard.service`
[create a bolt card](CARD_ANDROID.md) with the URI pointing to this server
use a PoS setup to read the bolt card, e.g. [Breez wallet](https://breez.technology/)
monitor the service log to ensure decryption, authentication, payment rules and lightning payment work as expected
-#### lightning address (optional)
-add lightning address support to receive funds to cards
-create an updated macaroon with limited permissions to the lightning node
-```
-$ lncli \
---rpcserver=lightning-node.io:10009 \
---macaroonpath=admin.macaroon \
---tlscertpath="tls.cert" \
-bakemacaroon uri:/routerrpc.Router/SendPaymentV2 uri:/lnrpc.Lightning/AddInvoice \
-uri:/invoicesrpc.Invoices/SubscribeSingleInvoice > SendAddMonitor.macaroon.hex
-
-$ xxd -r -p SendAddMonitor.macaroon.hex SendAddMonitor.macaroon
-```
-`LN_MACAROON_FILE=...` (settings table) - update to point to new SendAddMonitor.macaroon
-`FUNCTION_LNURLP=ENABLE` (settings table)
-`cards.lnurlp_enable='Y'` (card record)
-
-the lightning address will be *{cards.card_name}@{HOST_DOMAIN}*
-#### email notifications (optional)
-add email notifications for payments and fund receipt
-`AWS_SES_ID=..."` (settings table)
-`AWS_SES_SECRET=..."` (settings table)
-`AWS_SES_EMAIL_FROM=..."` (settings table)
-`AWS_REGION=...` (settings table)
-`FUNCTION_EMAIL=ENABLE"` (settings table)
-`cards.email_address='card.notifications@yourdomain.com'`
-`cards.email_enable='Y'`
-
-the email address will be *{cards.email_address}@{HOST_DOMAIN}*
#### production use
-ensure that LOG_LEVEL is set to PRODUCTION (settings table)
+ensure that LOG_LEVEL is set to PRODUCTION
ensure that all secrets are minimally available
ensure that you have good operational security practices
monitor the system for unusual activity
diff --git a/docs/LNDHUB.md b/docs/LNDHUB.md
deleted file mode 100644
index 42a29c2..0000000
--- a/docs/LNDHUB.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## lndhub
-
-### in the `settings` table
-- set 'LNDHUB_URL' to 'lndhub.yourdomain.com'
-- set 'FUNCTION_LNDHUB' to 'ENABLE'
-
-### create card
-- set the card_name to the 'login:password' for the lndhub account
-e.g. '11111111111111111111:22222222222222222222'
-
-### limits
-- there are currently no payment rules in this code, only the lndhub account limit
-i.e. tx_limit_sats & day_limit_sats are not enforced
diff --git a/docs/NOTES.md b/docs/NOTES.md
deleted file mode 100644
index 7ddeec4..0000000
--- a/docs/NOTES.md
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-- `$ apidoc -i . -o apidoc` to generate API documentation
diff --git a/docs/NT4H2421Gx.pdf b/docs/NT4H2421Gx.pdf
deleted file mode 100644
index 6612e8b..0000000
Binary files a/docs/NT4H2421Gx.pdf and /dev/null differ
diff --git a/docs/SETTINGS.md b/docs/SETTINGS.md
deleted file mode 100644
index 1c52afa..0000000
--- a/docs/SETTINGS.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Settings
-
-The database connection settings are in the system environment variables.
-Other settings are in the database in a `settings` table.
-
-Here are the descriptions of values available to use in the `settings` table:
-
-| Name | Value | Description |
-| --- | --- | --- |
-| LOG_LEVEL | DEBUG | system logs are verbose to enable easier debug |
-| | PRODUCTION | system logs are minimal |
-| AES_DECRYPT_KEY | | hex encoded 128 bit AES key - see [FAQ](FAQ.md#how-do-i-generate-a-random-key-value-)|
-| HOST_DOMAIN | yourdomain.com | the domain for hosting lnurlw & lnurlp services |
-| MIN_WITHDRAW_SATS | 1 | minimum satoshis for lnurlw response |
-| MAX_WITHDRAW_SATS | 1000000 | maximum satoshis for lnurlw response |
-| LN_HOST | your_lnd_node.io | LND node gRPC domain |
-| LN_PORT | 9001 | LND node gRPC port |
-| LN_TLS_FILE | /home/ubuntu/boltcard/tls.cert | absolute path to your LND TLC certificate |
-| LN_MACAROON_FILE | /home/ubuntu/boltcard/boltcard.macaroon | absolute path to your LND macaroon |
-| FEE_LIMIT_SAT | 10 | the base fee limit amount for every invoice payment |
-| FEE_LIMIT_PERCENT | 0.5 | the percentage fee limit amount added to the base fee limit amount |
-| LN_TESTNODE | | lightning node pubkey for allowing only the defined test node |
-| FUNCTION_LNURLW | ENABLE | system level switch for LNURLw (bolt card) services |
-| FUNCTION_LNURLP | DISABLE | system level switch for LNURLp (lightning address) services |
-| FUNCTION_EMAIL | DISABLE | system level switch for email updates on credits & debits |
-| DEFAULT_DESCRIPTION | 'bolt card service' | default description of payment |
-| AWS_SES_ID | | Amazon Web Services - Simple Email Service - access id |
-| AWS_SES_SECRET | | Amazon Web Services - Simple Email Service - access secret |
-| AWS_SES_EMAIL_FROM | | Amazon Web Services - Simple Email Service - email from field |
-| AWS_REGION | us-east-1 | Amazon Web Services - Account region |
-| EMAIL_MAX_TXS | | maximum number of transactions to include in the email body |
-| FUNCTION_LNDHUB | DISABLE | system level switch for using LNDHUB in place of LND |
-| LNDHUB_URL | | URL for the LNDHUB service |
-| FUNCTION_INTERNAL_API | DISABLE | system level switch for activating the internal API |
-| SENDGRID_API_KEY | | User API Key from SendGrid.com |
-| SENDGRID_EMAIL_SENDER | | Single Sender email address verified by SendGrid |
-| LN_INVOICE_EXPIRY_SEC | 3600 | LN invoice's expiry time in seconds |
diff --git a/docs/SPEC.md b/docs/SPEC.md
index a5f9db4..34a3c76 100644
--- a/docs/SPEC.md
+++ b/docs/SPEC.md
@@ -1,26 +1,13 @@
# Bolt card specification
-The bolt card system is built on the technologies listed below.
+The bolt card system is built on the open standards listed below.
- [LUD-03: withdrawRequest base spec.](https://github.com/fiatjaf/lnurl-rfc/blob/luds/03.md)
- - with the exception of maxWithdrawable which must be returned as higher than the actual maximum amount
- [LUD-17: Protocol schemes and raw (non bech32-encoded) URLs.](https://github.com/fiatjaf/lnurl-rfc/blob/luds/17.md)
-- NFC Data Exchange Format (NDEF)
-- Replay protection
- - NXP Secure Unique NFC Message (SUN) technology as implemented in the NXP NTAG 424 DNA card
-
-Bolt card systems should implement the best possible privacy.
-
-- [Privacy levels](https://github.com/boltcard/boltcard/blob/main/docs/CARD_PRIVACY.md)
-
-Bolt card systems may optionally support these technogies.
-
-- [LUD-19: Pay link discoverable from withdraw link.](https://github.com/lnurl/luds/blob/luds/19.md)
-- [LUD-21: pinLimit for withdrawRequest](https://github.com/bitcoin-ring/luds/blob/withdraw-pin/21.md)
## Bolt card and POS interaction
-the point-of-sale (POS) will read a NDEF message from the card, which changes with each use, for example
+the point-of-sale (POS) will read an NDEF message from the card, for example
```
lnurlw://card.yourdomain.com?p=A2EF40F6D46F1BB36E6EBF0114D4A464&c=F509EEA788E37E32
```
@@ -28,9 +15,9 @@ the POS will then call your bolt card service here
```
https://card.yourdomain.com?p=A2EF40F6D46F1BB36E6EBF0114D4A464&c=F509EEA788E37E32
```
-your bolt card service should verify the payment request as below and continue the standard LNURLw protocol as defined in LUD-03
+your bolt card service should verify the payment request as below and continue the LNURLw protocol
-## Server side verification of the payment request
+## Server side verification
- for the `p` value and the `SDM Meta Read Access Key` value, decrypt the UID and counter with AES
- for the `c` value and the `SDM File Read Access Key` value, check with AES-CMAC
diff --git a/docs/TECHNOLOGY.md b/docs/TECHNOLOGY.md
deleted file mode 100644
index 9c1d248..0000000
--- a/docs/TECHNOLOGY.md
+++ /dev/null
@@ -1,12 +0,0 @@
-## Bolt Card technology
-
-| Document | Description |
-| --- | --- |
-| [System](SYSTEM.md) | Bolt card system overview |
-| [Specification](SPEC.md) | Bolt card specifications |
-| [Deterministic Keys (DRAFT FOR COMMENT)](DETERMINISTIC.md) | Consideration about key generation |
-| [Boltcard Setup via Deeplink](DEEPLINK.md) | Deeplink for Boltcard creator apps |
-| [Privacy](CARD_PRIVACY.md) | Bolt card privacy |
-| [NXP 424 Datasheet](NT4H2421Gx.pdf) | NXP NTAG424DNA datasheet |
-| [NXP 424 Application Note](NT4H2421Gx.pdf) | NXP NTAG424DNA features and hints |
-| [FAQ](FAQ.md) | Bolt card FAQ |
diff --git a/docs/TEST_VECTORS.md b/docs/TEST_VECTORS.md
deleted file mode 100644
index 646922a..0000000
--- a/docs/TEST_VECTORS.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# test vectors
-
-some test vectors to help with developing code to AES decode and validate lnurlw:// requests
-
-these have been created by using an actual card and with [a small command line utility](https://github.com/boltcard/boltcard/blob/main/cli/main.go)
-
-```
--- bolt card crypto test vectors --
-
-p = 4E2E289D945A66BB13377A728884E867
-c = E19CCB1FED8892CE
-aes_decrypt_key = 0c3b25d92b38ae443229dd59ad34b85d
-aes_cmac_key = b45775776cb224c75bcde7ca3704e933
-
-decrypted card data : uid 04996c6a926980 , ctr 000003
-sv2 = [60 195 0 1 0 128 4 153 108 106 146 105 128 3 0 0]
-ks = [242 92 75 92 230 171 63 244 5 242 135 175 172 78 77 26]
-cm = [118 225 233 156 238 203 64 31 163 237 110 136 112 146 124 206]
-ct = [225 156 203 31 237 136 146 206]
-cmac validates ok
-
-
-
--- bolt card crypto test vectors --
-
-p = 00F48C4F8E386DED06BCDC78FA92E2FE
-c = 66B4826EA4C155B4
-aes_decrypt_key = 0c3b25d92b38ae443229dd59ad34b85d
-aes_cmac_key = b45775776cb224c75bcde7ca3704e933
-
-decrypted card data : uid 04996c6a926980 , ctr 000005
-sv2 = [60 195 0 1 0 128 4 153 108 106 146 105 128 5 0 0]
-ks = [73 70 39 105 116 24 126 152 96 101 139 189 130 16 200 190]
-cm = [94 102 243 180 93 130 2 110 198 164 241 193 67 85 112 180]
-ct = [102 180 130 110 164 193 85 180]
-cmac validates ok
-
-
-
--- bolt card crypto test vectors --
-
-p = 0DBF3C59B59B0638D60B5842A997D4D1
-c = CC61660C020B4D96
-aes_decrypt_key = 0c3b25d92b38ae443229dd59ad34b85d
-aes_cmac_key = b45775776cb224c75bcde7ca3704e933
-
-decrypted card data : uid 04996c6a926980 , ctr 000007
-sv2 = [60 195 0 1 0 128 4 153 108 106 146 105 128 7 0 0]
-ks = [97 189 177 81 15 79 217 5 102 95 162 58 192 199 38 97]
-cm = [40 204 202 97 87 102 6 12 101 2 250 11 199 77 73 150]
-ct = [204 97 102 12 2 11 77 150]
-cmac validates ok
-
-```
diff --git a/docs/images/fs-add-2.webp b/docs/images/fs-add-2.webp
deleted file mode 100644
index d395a7b..0000000
Binary files a/docs/images/fs-add-2.webp and /dev/null differ
diff --git a/docs/images/fs-add.webp b/docs/images/fs-add.webp
index d395a7b..6d15cec 100644
Binary files a/docs/images/fs-add.webp and b/docs/images/fs-add.webp differ
diff --git a/docs/images/posn-p.webp b/docs/images/posn-p.webp
deleted file mode 100644
index 0f9810a..0000000
Binary files a/docs/images/posn-p.webp and /dev/null differ
diff --git a/docs/images/posn.webp b/docs/images/posn.webp
deleted file mode 100644
index d395a7b..0000000
Binary files a/docs/images/posn.webp and /dev/null differ
diff --git a/email/email.go b/email/email.go
deleted file mode 100644
index f0335c4..0000000
--- a/email/email.go
+++ /dev/null
@@ -1,179 +0,0 @@
-package email
-
-import (
- "strconv"
- "strings"
-
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/aws/awserr"
- "github.com/aws/aws-sdk-go/aws/credentials"
- "github.com/aws/aws-sdk-go/aws/session"
- "github.com/aws/aws-sdk-go/service/ses"
- "github.com/boltcard/boltcard/db"
- "github.com/sendgrid/sendgrid-go"
- "github.com/sendgrid/sendgrid-go/helpers/mail"
- log "github.com/sirupsen/logrus"
-)
-
-func Send_balance_email(recipient_email string, card_id int) {
-
- c, err := db.Get_card_from_card_id(card_id)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- card_total_sats, err := db.Get_card_total_sats(card_id)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- email_max_txs, err := strconv.Atoi(db.Get_setting("EMAIL_MAX_TXS"))
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- txs, err := db.Get_card_txs(card_id, email_max_txs+1)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- subject := c.Card_name + " balance = " + strconv.Itoa(card_total_sats) + " sats"
-
- // add transactions to the email body
-
- var html_body_sb strings.Builder
- var text_body_sb strings.Builder
-
- html_body_sb.WriteString("")
-
- html_body_sb.WriteString("transactions
| date | action | amount | ")
- text_body_sb.WriteString("transactions\n\n")
-
- for i, tx := range txs {
-
- if i < email_max_txs {
- html_body_sb.WriteString(
- "
|---|
" +
- "| " + tx.Tx_time + " | " +
- "" + tx.Tx_type + " | " +
- "" + strconv.Itoa(tx.Tx_amount_msats/1000) + " | " +
- "
")
- } else {
- html_body_sb.WriteString(
- "" +
- "| ... | " +
- " ... | " +
- " ... | " +
- "
")
- }
-
- text_body_sb.WriteString(tx.Tx_type +
- " " + strconv.Itoa(tx.Tx_amount_msats/1000))
- }
-
- html_body_sb.WriteString("
")
-
- html_body := html_body_sb.String()
- text_body := text_body_sb.String()
-
- Send_email(recipient_email,
- subject,
- html_body,
- text_body)
-}
-
-// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/ses-example-send-email.html
-// https://github.com/sendgrid/sendgrid-go
-
-func Send_email(recipient string, subject string, htmlBody string, textBody string) {
-
- send_grid_api_key := db.Get_setting("SENDGRID_API_KEY")
- send_grid_email_sender := db.Get_setting("SENDGRID_EMAIL_SENDER")
- if send_grid_api_key != "" && send_grid_email_sender != "" {
- from := mail.NewEmail("", send_grid_email_sender)
- subject := subject
- to := mail.NewEmail("", recipient)
- plainTextContent := textBody
- htmlContent := htmlBody
- message := mail.NewSingleEmail(from, subject, to, plainTextContent, htmlContent)
- client := sendgrid.NewSendClient(send_grid_api_key)
- response, err := client.Send(message)
- if err != nil {
- log.Warn(err.Error())
- } else {
- log.WithFields(log.Fields{"result": response}).Info("email sent")
- }
-
- } else {
-
- aws_ses_id := db.Get_setting("AWS_SES_ID")
- aws_ses_secret := db.Get_setting("AWS_SES_SECRET")
- sender := db.Get_setting("AWS_SES_EMAIL_FROM")
- region := db.Get_setting("AWS_REGION")
-
- sess, err := session.NewSession(&aws.Config{
- Region: aws.String(region),
- Credentials: credentials.NewStaticCredentials(aws_ses_id, aws_ses_secret, ""),
- })
-
- svc := ses.New(sess)
-
- charSet := "UTF-8"
-
- input := &ses.SendEmailInput{
- Destination: &ses.Destination{
- CcAddresses: []*string{},
- ToAddresses: []*string{
- aws.String(recipient),
- },
- },
- Message: &ses.Message{
- Body: &ses.Body{
- Html: &ses.Content{
- Charset: aws.String(charSet),
- Data: aws.String(htmlBody),
- },
- Text: &ses.Content{
- Charset: aws.String(charSet),
- Data: aws.String(textBody),
- },
- },
- Subject: &ses.Content{
- Charset: aws.String(charSet),
- Data: aws.String(subject),
- },
- },
- Source: aws.String(sender),
- //ConfigurationSetName: aws.String(ConfigurationSet),
- }
-
- result, err := svc.SendEmail(input)
-
- if err != nil {
- if aerr, ok := err.(awserr.Error); ok {
- switch aerr.Code() {
- case ses.ErrCodeMessageRejected:
- log.Warn(ses.ErrCodeMessageRejected, aerr.Error())
- case ses.ErrCodeMailFromDomainNotVerifiedException:
- log.Warn(ses.ErrCodeMailFromDomainNotVerifiedException, aerr.Error())
- case ses.ErrCodeConfigurationSetDoesNotExistException:
- log.Warn(ses.ErrCodeConfigurationSetDoesNotExistException, aerr.Error())
- default:
- log.Warn(aerr.Error())
- }
- } else {
- log.Warn(err.Error())
- }
-
- return
- }
-
- log.WithFields(log.Fields{"result": result}).Info("email sent")
- }
-}
diff --git a/go.mod b/go.mod
index 5223a0d..2dcfdd7 100644
--- a/go.mod
+++ b/go.mod
@@ -3,143 +3,43 @@ module github.com/boltcard/boltcard
go 1.18
require (
- github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1
- github.com/aws/aws-sdk-go v1.44.142
- github.com/fiatjaf/ln-decodepay v1.5.0
- github.com/gorilla/mux v1.8.0
- github.com/lib/pq v1.10.7
- github.com/lightningnetwork/lnd v0.15.5-beta.rc1
- github.com/sirupsen/logrus v1.9.0
- github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
- google.golang.org/grpc v1.51.0
- gopkg.in/macaroon.v2 v2.1.0
-)
-
-require (
- cloud.google.com/go/compute/metadata v0.2.3 // indirect
- github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
+ github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 // indirect
github.com/aead/siphash v1.0.1 // indirect
- github.com/benbjohnson/clock v1.3.0 // indirect
- github.com/beorn7/perks v1.0.1 // indirect
- github.com/btcsuite/btcd v0.23.4 // indirect
- github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
- github.com/btcsuite/btcd/btcutil v1.1.3 // indirect
- github.com/btcsuite/btcd/btcutil/psbt v1.1.6 // indirect
- github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
+ github.com/btcsuite/btcd v0.20.1-beta.0.20200515232429-9f0179fd2c46 // indirect
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect
- github.com/btcsuite/btcwallet v0.16.4 // indirect
- github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 // indirect
- github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 // indirect
- github.com/btcsuite/btcwallet/wallet/txsizes v1.2.3 // indirect
- github.com/btcsuite/btcwallet/walletdb v1.4.0 // indirect
- github.com/btcsuite/btcwallet/wtxmgr v1.5.0 // indirect
+ github.com/btcsuite/btcutil v1.0.2 // indirect
+ github.com/btcsuite/btcwallet v0.11.1-0.20200515224913-e0e62245ecbe // indirect
+ github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 // indirect
+ github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 // indirect
+ github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0 // indirect
+ github.com/btcsuite/btcwallet/walletdb v1.3.1 // indirect
+ github.com/btcsuite/btcwallet/wtxmgr v1.1.1-0.20200515224913-e0e62245ecbe // indirect
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect
- github.com/btcsuite/winsvc v1.0.0 // indirect
- github.com/cenkalti/backoff/v4 v4.2.0 // indirect
- github.com/cespare/xxhash/v2 v2.1.2 // indirect
- github.com/coreos/go-semver v0.3.0 // indirect
- github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
- github.com/decred/dcrd/lru v1.1.1 // indirect
- github.com/dustin/go-humanize v1.0.0 // indirect
- github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6 // indirect
- github.com/fergusstrange/embedded-postgres v1.19.0 // indirect
- github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
- github.com/go-errors/errors v1.4.2 // indirect
- github.com/go-logr/logr v1.2.3 // indirect
- github.com/go-logr/stdr v1.2.2 // indirect
- github.com/go-macaroon-bakery/macaroonpb v1.0.0 // indirect
- github.com/gogo/protobuf v1.3.2 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
- github.com/golang/snappy v0.0.4 // indirect
- github.com/google/btree v1.1.2 // indirect
- github.com/gorilla/websocket v1.5.0 // indirect
- github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
- github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.14.0 // indirect
- github.com/jackc/chunkreader/v2 v2.0.1 // indirect
- github.com/jackc/pgconn v1.13.0 // indirect
- github.com/jackc/pgio v1.0.0 // indirect
- github.com/jackc/pgpassfile v1.0.0 // indirect
- github.com/jackc/pgproto3/v2 v2.3.1 // indirect
- github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
- github.com/jackc/pgtype v1.12.0 // indirect
- github.com/jackc/pgx/v4 v4.17.2 // indirect
- github.com/jessevdk/go-flags v1.5.0 // indirect
- github.com/jmespath/go-jmespath v0.4.0 // indirect
- github.com/jonboulle/clockwork v0.3.0 // indirect
- github.com/jrick/logrotate v1.0.0 // indirect
- github.com/json-iterator/go v1.1.12 // indirect
- github.com/kkdai/bstream v1.0.0 // indirect
+ github.com/fiatjaf/ln-decodepay v1.4.0 // indirect
+ github.com/go-errors/errors v1.0.1 // indirect
+ github.com/golang/protobuf v1.3.3 // indirect
+ github.com/grpc-ecosystem/grpc-gateway v1.8.6 // indirect
+ github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect
+ github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec // indirect
+ github.com/lib/pq v1.10.6 // indirect
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // indirect
- github.com/lightninglabs/neutrino v0.14.2 // indirect
- github.com/lightningnetwork/lightning-onion v1.2.0 // indirect
- github.com/lightningnetwork/lnd/clock v1.1.0 // indirect
- github.com/lightningnetwork/lnd/healthcheck v1.2.2 // indirect
- github.com/lightningnetwork/lnd/kvdb v1.3.1 // indirect
- github.com/lightningnetwork/lnd/queue v1.1.0 // indirect
- github.com/lightningnetwork/lnd/ticker v1.1.0 // indirect
- github.com/lightningnetwork/lnd/tlv v1.0.3 // indirect
- github.com/lightningnetwork/lnd/tor v1.1.0 // indirect
- github.com/ltcsuite/ltcd v0.22.1-beta // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
- github.com/miekg/dns v1.1.50 // indirect
- github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
- github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/nbd-wtf/ln-decodepay v1.11.1 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_golang v1.14.0 // indirect
- github.com/prometheus/client_model v0.3.0 // indirect
- github.com/prometheus/common v0.37.0 // indirect
- github.com/prometheus/procfs v0.8.0 // indirect
+ github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200 // indirect
+ github.com/lightningnetwork/lnd v0.10.1-beta // indirect
+ github.com/lightningnetwork/lnd/queue v1.0.3 // indirect
+ github.com/lightningnetwork/lnd/ticker v1.0.0 // indirect
+ github.com/lncm/lnd-rpc v1.0.2 // indirect
+ github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8 // indirect
github.com/rogpeppe/fastuuid v1.2.0 // indirect
- github.com/sendgrid/rest v2.6.9+incompatible // indirect
- github.com/sendgrid/sendgrid-go v3.12.0+incompatible // indirect
- github.com/soheilhy/cmux v0.1.5 // indirect
- github.com/spf13/pflag v1.0.5 // indirect
- github.com/stretchr/objx v0.5.0 // indirect
- github.com/stretchr/testify v1.8.1 // indirect
- github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
- github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect
- github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
- github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
- go.etcd.io/bbolt v1.3.6 // indirect
- go.etcd.io/etcd/api/v3 v3.5.5 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.5 // indirect
- go.etcd.io/etcd/client/v2 v2.305.5 // indirect
- go.etcd.io/etcd/client/v3 v3.5.5 // indirect
- go.etcd.io/etcd/pkg/v3 v3.5.5 // indirect
- go.etcd.io/etcd/raft/v3 v3.5.5 // indirect
- go.etcd.io/etcd/server/v3 v3.5.5 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.4 // indirect
- go.opentelemetry.io/otel v1.11.1 // indirect
- go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 // indirect
- go.opentelemetry.io/otel/sdk v1.11.1 // indirect
- go.opentelemetry.io/otel/trace v1.11.1 // indirect
- go.opentelemetry.io/proto/otlp v0.19.0 // indirect
- go.uber.org/atomic v1.10.0 // indirect
- go.uber.org/multierr v1.8.0 // indirect
- go.uber.org/zap v1.23.0 // indirect
- golang.org/x/crypto v0.3.0 // indirect
- golang.org/x/mod v0.7.0 // indirect
- golang.org/x/net v0.7.0 // indirect
- golang.org/x/sys v0.5.0 // indirect
- golang.org/x/term v0.5.0 // indirect
- golang.org/x/text v0.7.0 // indirect
- golang.org/x/time v0.2.0 // indirect
- golang.org/x/tools v0.3.0 // indirect
- google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
- google.golang.org/protobuf v1.28.1 // indirect
+ github.com/sirupsen/logrus v1.8.1 // indirect
+ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect
+ golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
+ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 // indirect
+ golang.org/x/text v0.3.2 // indirect
+ google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce // indirect
+ google.golang.org/grpc v1.27.1 // indirect
gopkg.in/errgo.v1 v1.0.1 // indirect
- gopkg.in/macaroon-bakery.v2 v2.3.0 // indirect
- gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
- sigs.k8s.io/yaml v1.3.0 // indirect
+ gopkg.in/macaroon-bakery.v2 v2.0.1 // indirect
+ gopkg.in/macaroon.v2 v2.1.0 // indirect
)
diff --git a/go.sum b/go.sum
index b9afa5f..4a9d6ed 100644
--- a/go.sum
+++ b/go.sum
@@ -1,1215 +1,275 @@
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.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.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.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
-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/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0=
-cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
-cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
-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/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=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+git.schwanenlied.me/yawning/bsaes.git v0.0.0-20180720073208-c0276d75487e/go.mod h1:BWqTsj8PgcPriQJGl7el20J/7TuT1d/hSyFDXMEpoEo=
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/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
-github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ=
+github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82/go.mod h1:GbuBk21JqF+driLX3XtJYNZjGa45YDoa9IqCTzNSfEc=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
+github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 h1:+JkXLHME8vLJafGhOH4aoV2Iu8bR55nU6iKMVfYVLjY=
github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg=
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
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/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
-github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-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/aws/aws-sdk-go v1.44.142 h1:KZ1/FDwCSft1DuNllFaBtWpcG0CW2NgQjvOrE1TdlXE=
-github.com/aws/aws-sdk-go v1.44.142/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
-github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
-github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
-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/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
-github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
-github.com/btcsuite/btcd v0.22.0-beta.0.20220204213055-eaf0459ff879/go.mod h1:osu7EoKiL36UThEgzYPqdRaxeo0NU8VoXqgcnwpey0g=
-github.com/btcsuite/btcd v0.22.0-beta.0.20220207191057-4dc4ff7963b4/go.mod h1:7alexyj/lHlOtr2PJK7L/+HDJZpcGDn/pAU98r7DY08=
-github.com/btcsuite/btcd v0.22.0-beta.0.20220316175102-8d5c75c28923/go.mod h1:taIcYprAW2g6Z9S0gGUxyR+zDwimyDMK5ePOX+iJ2ds=
-github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
-github.com/btcsuite/btcd v0.23.1/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
-github.com/btcsuite/btcd v0.23.4 h1:IzV6qqkfwbItOS/sg/aDfPDsjPP8twrCOE2R93hxMlQ=
-github.com/btcsuite/btcd v0.23.4/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY=
-github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
-github.com/btcsuite/btcd/btcec/v2 v2.1.1/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
-github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
-github.com/btcsuite/btcd/btcec/v2 v2.2.2/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8=
-github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
-github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
-github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
-github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
-github.com/btcsuite/btcd/btcutil v1.1.1/go.mod h1:nbKlBMNm9FGsdvKvu0essceubPiAcI57pYBNnsLAa34=
-github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ=
-github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0=
-github.com/btcsuite/btcd/btcutil/psbt v1.1.4/go.mod h1:9AyU6EQVJ9Iw9zPyNT1lcdHd6cnEZdno5wLu5FY74os=
-github.com/btcsuite/btcd/btcutil/psbt v1.1.6 h1:T7ZsRJvLzEn8zPnBR7wNwS7MpunRMlUCd2vDmsP7t3U=
-github.com/btcsuite/btcd/btcutil/psbt v1.1.6/go.mod h1:kA6FLH/JfUx++j9pYU0pyu+Z8XGBQuuTmuKYUf6q7/U=
-github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
-github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
-github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
+github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
+github.com/btcsuite/btcd v0.20.1-beta.0.20200515232429-9f0179fd2c46 h1:QyTpiR5nQe94vza2qkvf7Ns8XX2Rjh/vdIhO3RzGj4o=
+github.com/btcsuite/btcd v0.20.1-beta.0.20200515232429-9f0179fd2c46/go.mod h1:Yktc19YNjh/Iz2//CX0vfRTS4IJKM/RKO5YZ9Fn+Pgo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
-github.com/btcsuite/btcwallet v0.16.4 h1:13Vro3kvLD6z1KfRB4GOyykqtlLsDbNRdzzX7nxAGfk=
-github.com/btcsuite/btcwallet v0.16.4/go.mod h1:mM19pFB3lGVxOL+kvHhHZAhdSWXKsZGiHvpJVvxL0D8=
-github.com/btcsuite/btcwallet/wallet/txauthor v1.2.3/go.mod h1:T2xSiKGpUkSLCh68aF+FMXmKK9mFqNdHl9VaqOr+JjU=
-github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2 h1:etuLgGEojecsDOYTII8rYiGHjGyV5xTqsXi+ZQ715UU=
-github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2/go.mod h1:Zpk/LOb2sKqwP2lmHjaZT9AdaKsHPSbNLm2Uql5IQ/0=
-github.com/btcsuite/btcwallet/wallet/txrules v1.2.0 h1:BtEN5Empw62/RVnZ0VcJaVtVlBijnLlJY+dwjAye2Bg=
-github.com/btcsuite/btcwallet/wallet/txrules v1.2.0/go.mod h1:AtkqiL7ccKWxuLYtZm8Bu8G6q82w4yIZdgq6riy60z0=
-github.com/btcsuite/btcwallet/wallet/txsizes v1.1.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
-github.com/btcsuite/btcwallet/wallet/txsizes v1.2.2/go.mod h1:q08Rms52VyWyXcp5zDc4tdFRKkFgNsMQrv3/LvE1448=
-github.com/btcsuite/btcwallet/wallet/txsizes v1.2.3 h1:PszOub7iXVYbtGybym5TGCp9Dv1h1iX4rIC3HICZGLg=
-github.com/btcsuite/btcwallet/wallet/txsizes v1.2.3/go.mod h1:q08Rms52VyWyXcp5zDc4tdFRKkFgNsMQrv3/LvE1448=
-github.com/btcsuite/btcwallet/walletdb v1.3.5/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
-github.com/btcsuite/btcwallet/walletdb v1.3.6-0.20210803004036-eebed51155ec/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
-github.com/btcsuite/btcwallet/walletdb v1.4.0 h1:/C5JRF+dTuE2CNMCO/or5N8epsrhmSM4710uBQoYPTQ=
-github.com/btcsuite/btcwallet/walletdb v1.4.0/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
-github.com/btcsuite/btcwallet/wtxmgr v1.5.0 h1:WO0KyN4l6H3JWnlFxfGR7r3gDnlGT7W2cL8vl6av4SU=
-github.com/btcsuite/btcwallet/wtxmgr v1.5.0/go.mod h1:TQVDhFxseiGtZwEPvLgtfyxuNUDsIdaJdshvWzR0HJ4=
+github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
+github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
+github.com/btcsuite/btcutil/psbt v1.0.2/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ=
+github.com/btcsuite/btcwallet v0.11.1-0.20200515224913-e0e62245ecbe h1:0m9uXDcnUc3Fv72635O/MfLbhbW+0hfSVgRiWezpkHU=
+github.com/btcsuite/btcwallet v0.11.1-0.20200515224913-e0e62245ecbe/go.mod h1:9+AH3V5mcTtNXTKe+fe63fDLKGOwQbZqmvOVUef+JFE=
+github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 h1:KGHMW5sd7yDdDMkCZ/JpP0KltolFsQcB973brBnfj4c=
+github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU=
+github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 h1:2VsfS0sBedcM5KmDzRMT3+b6xobqWveZGvjb+jFez5w=
+github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA=
+github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0 h1:6DxkcoMnCPY4E9cUDPB5tbuuf40SmmMkSQkoE8vCT+s=
+github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
+github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk=
+github.com/btcsuite/btcwallet/walletdb v1.2.0/go.mod h1:9cwc1Yyg4uvd4ZdfdoMnALji+V9gfWSMfxEdLdR5Vwc=
+github.com/btcsuite/btcwallet/walletdb v1.3.1 h1:lW1Ac3F1jJY4K11P+YQtRNcP5jFk27ASfrV7C6mvRU0=
+github.com/btcsuite/btcwallet/walletdb v1.3.1/go.mod h1:9cwc1Yyg4uvd4ZdfdoMnALji+V9gfWSMfxEdLdR5Vwc=
+github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY=
+github.com/btcsuite/btcwallet/wtxmgr v1.1.1-0.20200515224913-e0e62245ecbe h1:yQbJVYfsKbdqDQNLxd4hhiLSiMkIygefW5mSHMsdKpc=
+github.com/btcsuite/btcwallet/wtxmgr v1.1.1-0.20200515224913-e0e62245ecbe/go.mod h1:OwC0W0HhUszbWdvJvH6xvgabKSJ0lXl11YbmmqF9YXQ=
+github.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:QcFA8DZHtuIAdYKCq/BzELOaznRsCvwf4zTPmaYwaig=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
+github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
-github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
-github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
-github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
-github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/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 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
-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 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
-github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
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-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 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
-github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E=
-github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
-github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs=
-github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
-github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
-github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
-github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-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.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
-github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-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/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/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/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
-github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
-github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
-github.com/decred/dcrd/lru v1.1.1 h1:kWFDaW0OWx6AD6Ki342c+JPmHbiVdE6rK81pT3fuo/Y=
-github.com/decred/dcrd/lru v1.1.1/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
-github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
-github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6 h1:sE4tvxWw01v7K3MAHwKF2UF3xQbgy23PRURntuV1CkU=
-github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
-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.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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fergusstrange/embedded-postgres v1.10.0/go.mod h1:a008U8/Rws5FtIOTGYDYa7beVWsT3qVKyqExqYYjL+c=
-github.com/fergusstrange/embedded-postgres v1.19.0 h1:NqDufJHeA03U7biULlPHZ0pZ10/mDOMKPILEpT50Fyk=
-github.com/fergusstrange/embedded-postgres v1.19.0/go.mod h1:0B+3bPsMvcNgR9nN+bdM2x9YaNYDnf3ksUqYp1OAub0=
-github.com/fiatjaf/ln-decodepay v1.5.0 h1:2El572vj5XWIZCdJaLI8mgjVi0h0GKama/B2PWQGGg4=
-github.com/fiatjaf/ln-decodepay v1.5.0/go.mod h1:4Puy1RxCp4ETrLqxtWeoBFsrERF1aqM4g9uwXTIBGKk=
-github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
-github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
-github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/fiatjaf/ln-decodepay v1.4.0 h1:WDedFrzitQPQHfo7pktYXoZ1Rmy28RJnA/4w3cpzt40=
+github.com/fiatjaf/ln-decodepay v1.4.0/go.mod h1:zLf4G9EsRhryXtFO63072BZ0JQLWbr7uRm3wZFJafdo=
github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k=
-github.com/frankban/quicktest v1.1.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k=
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
-github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
-github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
-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/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
-github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
-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-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
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/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
-github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
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-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
-github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
-github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
-github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-macaroon-bakery/macaroonpb v1.0.0 h1:It9exBaRMZ9iix1iJ6gwzfwsDE6ExNuwtAJ9e09v6XE=
-github.com/go-macaroon-bakery/macaroonpb v1.0.0/go.mod h1:UzrGOcbiwTXISFP2XDLDPjfhMINZa+fX/7A2lMd31zc=
+github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
+github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
-github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/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.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
-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/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
-github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
-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/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
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/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 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
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 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
-github.com/golang/snappy v0.0.4/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/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
-github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
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.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-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-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/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
-github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
-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 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.14.0 h1:t7uX3JBHdVwAi3G7sSSdbsk8NfgA+LnUS88V/2EKaA0=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.14.0/go.mod h1:4OGVnY4qf2+gw+ssiHbW+pq4mo2yko94YxxMmXZ7jCA=
-github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/sdk v0.1.1/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-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-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.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/grpc-ecosystem/grpc-gateway v1.8.6 h1:XvND7+MPP7Jp+JpqSZ7naSl5nVZf6k0LbL1V3EKh0zc=
+github.com/grpc-ecosystem/grpc-gateway v1.8.6/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-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 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
-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.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
-github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
-github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
-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 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
-github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
-github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
-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.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
-github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
-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.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
-github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
-github.com/jackc/pgtype v1.12.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.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0=
-github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
-github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
-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.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
+github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
+github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
-github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
-github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
-github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
-github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
-github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-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/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg=
-github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
-github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-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/mgotest v1.0.1/go.mod h1:vTaDufYul+Ps8D7bgseHjq87X8eu0ivlKLp9mVc/Bfc=
-github.com/juju/postgrestest v1.1.0/go.mod h1:/n17Y2T6iFozzXwSCO0JYJ5gSiz2caEtSwAjh/uLXDM=
-github.com/juju/qthttptest v0.0.1/go.mod h1://LCf/Ls22/rPw2u1yWukUJvYtfPY4nYpWUl2uZhryo=
-github.com/juju/schema v1.0.0/go.mod h1:Y+ThzXpUJ0E7NYYocAbuvJ7vTivXfrof/IfRPq/0abI=
-github.com/juju/webbrowser v0.0.0-20160309143629-54b8c57083b4/go.mod h1:G6PCelgkM6cuvyD10iYJsjLBsSadVXtJ+nBxFAxE2BU=
+github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
+github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
+github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI=
+github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
+github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=
+github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
+github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=
+github.com/juju/version v0.0.0-20180108022336-b64dbd566305/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=
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/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/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec h1:n1NeQ3SgUHyISrjFFoO5dR748Is8dBL9qpaTNfphQrs=
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
-github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8=
-github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA=
-github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
-github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
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.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
-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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-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.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
-github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
+github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc=
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
-github.com/lightninglabs/neutrino v0.14.2 h1:yrnZUCYMZ5ECtXhgDrzqPq2oX8awoAN2D/cgCewJcCo=
-github.com/lightninglabs/neutrino v0.14.2/go.mod h1:OICUeTCn+4Tu27YRJIpWvvqySxx4oH4vgdP33Sw9RDc=
-github.com/lightningnetwork/lightning-onion v1.2.0 h1:nq7OxNMnhmOKKQefvgwDlZGT4rBMqxukM1kaH6JBOw4=
-github.com/lightningnetwork/lightning-onion v1.2.0/go.mod h1:7dDx73ApjEZA0kcknI799m2O5kkpfg4/gr7N092ojNo=
-github.com/lightningnetwork/lnd v0.15.5-beta.rc1 h1:7hhVFud2MlvXEezrnOGzkjjaBlo4xivbaJ6/qLXVB2k=
-github.com/lightningnetwork/lnd v0.15.5-beta.rc1/go.mod h1:+/dRmUl8tMN79xAU2EHEBI4n3pmnBBeC29kbXURGqzI=
-github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg=
-github.com/lightningnetwork/lnd/clock v1.1.0 h1:/yfVAwtPmdx45aQBoXQImeY7sOIEr7IXlImRMBOZ7GQ=
-github.com/lightningnetwork/lnd/clock v1.1.0/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg=
-github.com/lightningnetwork/lnd/healthcheck v1.0.0/go.mod h1:u92p1JGFJNMSkMvztKEwmt1P3TRnLeJBXZ3M85xkU1E=
-github.com/lightningnetwork/lnd/healthcheck v1.2.2 h1:im+qcpgSuteqRCGeorT9yqVXuLrS6A7/acYzGgarMS4=
-github.com/lightningnetwork/lnd/healthcheck v1.2.2/go.mod h1:IWY0GChlarRbXFkFDdE4WY5POYJabe/7/H1iCZt4ZKs=
-github.com/lightningnetwork/lnd/kvdb v1.3.1 h1:gEz3zudNNRrCLEvqRaktYoKwsUblyHX+MKjR0aI3QnM=
-github.com/lightningnetwork/lnd/kvdb v1.3.1/go.mod h1:x+IpsuDynubjokUofavLXroeGfS/WrqUXXTK6vN/gp4=
+github.com/lightninglabs/neutrino v0.11.0/go.mod h1:CuhF0iuzg9Sp2HO6ZgXgayviFTn1QHdSTJlMncK80wg=
+github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200 h1:j4iZ1XlUAPQmW6oSzMcJGILYsRHNs+4O3Gk+2Ms5Dww=
+github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200/go.mod h1:MlZmoKa7CJP3eR1s5yB7Rm5aSyadpKkxqAwLQmog7N0=
+github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI=
+github.com/lightningnetwork/lightning-onion v1.0.1/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
+github.com/lightningnetwork/lnd v0.10.1-beta h1:zA/rQoxC5FNHtayVuA2wRtSOEDnJbuzAzHKAf2PWj1Q=
+github.com/lightningnetwork/lnd v0.10.1-beta/go.mod h1:F9er1DrpOHdQVQBqYqyBqIFyl6q16xgBM8yTioHj2Cg=
+github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo=
github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms=
-github.com/lightningnetwork/lnd/queue v1.1.0 h1:YpCJjlIvVxN/R7ww2aNiY8ex7U2fucZDLJ67tI3HFx8=
-github.com/lightningnetwork/lnd/queue v1.1.0/go.mod h1:YTkTVZCxz8tAYreH27EO3s8572ODumWrNdYW2E/YKxg=
+github.com/lightningnetwork/lnd/queue v1.0.3 h1:5ufYVE7lh9GJnL1wOoeO3bZ3aAHWNnkNFHP7W1+NiJ8=
+github.com/lightningnetwork/lnd/queue v1.0.3/go.mod h1:YTkTVZCxz8tAYreH27EO3s8572ODumWrNdYW2E/YKxg=
+github.com/lightningnetwork/lnd/ticker v1.0.0 h1:S1b60TEGoTtCe2A0yeB+ecoj/kkS4qpwh6l+AkQEZwU=
github.com/lightningnetwork/lnd/ticker v1.0.0/go.mod h1:iaLXJiVgI1sPANIF2qYYUJXjoksPNvGNYowB8aRbpX0=
-github.com/lightningnetwork/lnd/ticker v1.1.0 h1:ShoBiRP3pIxZHaETndfQ5kEe+S4NdAY1hiX7YbZ4QE4=
-github.com/lightningnetwork/lnd/ticker v1.1.0/go.mod h1:ubqbSVCn6RlE0LazXuBr7/Zi6QT0uQo++OgIRBxQUrk=
-github.com/lightningnetwork/lnd/tlv v1.0.2/go.mod h1:fICAfsqk1IOsC1J7G9IdsWX1EqWRMqEDCNxZJSKr9C4=
-github.com/lightningnetwork/lnd/tlv v1.0.3 h1:0xBZcPuXagP6f7TY/RnLNR4igE21ov6qUdTr5NyvhhI=
-github.com/lightningnetwork/lnd/tlv v1.0.3/go.mod h1:dzR/aZetBri+ZY/fHbwV06fNn/3UID6htQzbHfREFdo=
-github.com/lightningnetwork/lnd/tor v1.0.0/go.mod h1:RDtaAdwfAm+ONuPYwUhNIH1RAvKPv+75lHPOegUcz64=
-github.com/lightningnetwork/lnd/tor v1.1.0 h1:iXO7fSzjxTI+p88KmtpbuyuRJeNfgtpl9QeaAliILXE=
-github.com/lightningnetwork/lnd/tor v1.1.0/go.mod h1:RDtaAdwfAm+ONuPYwUhNIH1RAvKPv+75lHPOegUcz64=
-github.com/ltcsuite/ltcd v0.22.1-beta h1:aXeIMuzwPss4VABDyc7Zbx+NMLYFaG3YkNTPNkKL9XA=
-github.com/ltcsuite/ltcd v0.22.1-beta/go.mod h1:O9R9U/mbZwRgr3So8TlNmW7CPc2ZQVhWyVlhXrqu/vo=
-github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-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.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-isatty v0.0.3/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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/lncm/lnd-rpc v1.0.2 h1:34F1+aNT5bbBrfA8aWg3m40yaEByJjQwCqVAyaV2Fog=
+github.com/lncm/lnd-rpc v1.0.2/go.mod h1:zw6oVgCpAYE+KYDfCa52xZag4m0+fOcuXxj6D+4NDtY=
+github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
+github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc=
-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/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
-github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-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/miekg/dns v0.0.0-20171125082028-79bfde677fa8 h1:PRMAcldsl4mXKJeRNB/KVNz6TlbS6hk2Rs42PqgU3Ws=
+github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-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/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/nbd-wtf/ln-decodepay v1.11.1 h1:MPiT4a4qZ2cKY27Aj0dI8sLFrLz5Ycu72Z3EG1HfPjk=
-github.com/nbd-wtf/ln-decodepay v1.11.1/go.mod h1:xzBXPaCj/7oRRaui+iYSIxy5LYUjoPfAyAGq2WCyNKk=
-github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
-github.com/nwaples/rardecode v1.1.2/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
-github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
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.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
-github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
-github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
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/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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
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.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
-github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/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.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
-github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-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/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
-github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/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.1.3/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/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
-github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
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/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/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/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/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0=
-github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
-github.com/sendgrid/sendgrid-go v3.12.0+incompatible h1:/N2vx18Fg1KmQOh6zESc5FJB8pYwt5QFBDflYPh1KVg=
-github.com/sendgrid/sendgrid-go v3.12.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
-github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
-github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
-github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-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.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 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
-github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
-github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
-github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/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/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.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
-github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
-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-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
-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/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
-github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
-github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-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.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
-go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
-go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
-go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
-go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
-go.etcd.io/etcd/api/v3 v3.5.5 h1:BX4JIbQ7hl7+jL+g+2j5UAr0o1bctCm6/Ct+ArBGkf0=
-go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8=
-go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
-go.etcd.io/etcd/client/pkg/v3 v3.5.5 h1:9S0JUVvmrVl7wCF39iTQthdaaNIiAaQbmK75ogO6GU8=
-go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ=
-go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
-go.etcd.io/etcd/client/v2 v2.305.5 h1:DktRP60//JJpnPC0VBymAN/7V71GHMdjDCBt4ZPXDjI=
-go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4=
-go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
-go.etcd.io/etcd/client/v3 v3.5.5 h1:q++2WTJbUgpQu4B6hCuT7VkdwaTP7Qz6Daak3WzbrlI=
-go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c=
-go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
-go.etcd.io/etcd/pkg/v3 v3.5.5 h1:Ablg7T7OkR+AeeeU32kdVhw/AGDsitkKPl7aW73ssjU=
-go.etcd.io/etcd/pkg/v3 v3.5.5/go.mod h1:6ksYFxttiUGzC2uxyqiyOEvhAiD0tuIqSZkX3TyPdaE=
-go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
-go.etcd.io/etcd/raft/v3 v3.5.5 h1:Ibz6XyZ60OYyRopu73lLM/P+qco3YtlZMOhnXNS051I=
-go.etcd.io/etcd/raft/v3 v3.5.5/go.mod h1:76TA48q03g1y1VpTue92jZLr9lIHKUNcYdZOOGyx8rI=
-go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
-go.etcd.io/etcd/server/v3 v3.5.5 h1:jNjYm/9s+f9A9r6+SC4RvNaz6AqixpOvhrFdT0PvIj0=
-go.etcd.io/etcd/server/v3 v3.5.5/go.mod h1:rZ95vDw/jrvsbj9XpTqPrTAB9/kzchVdhRirySPkUBc=
-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.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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.4 h1:PRXhsszxTt5bbPriTjmaweWUsAnJYeWBhUMLRetUgBU=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.4/go.mod h1:05eWWy6ZWzmpeImD3UowLTB3VjDMU1yxQ+ENuVWDM3c=
-go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
-go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
-go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4=
-go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE=
-go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 h1:X2GndnMCsUPh6CiY2a+frAbNsXaPLbB0soHRYhAZ5Ig=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 h1:MEQNafcNCB0uQIti/oHgU7CZpUMYQ7qigBwMVKycHvc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1/go.mod h1:19O5I2U5iys38SsmT2uDJja/300woyzE1KPIQxEUBUc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 h1:LYyG/f1W/jzAix16jbksJfMQFpOH/Ma6T639pVPMgfI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1/go.mod h1:QrRRQiY3kzAoYPNLP0W/Ikg0gR6V3LMc+ODSxr7yyvg=
-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 v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI=
-go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs=
-go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys=
-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/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
-go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ=
-go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
-go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
-go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
-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/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
-go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
-go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
-go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
-go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
-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/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
-go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
-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.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
-go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY=
+github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/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-20190211182817-74369b46fc67/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-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
-golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
-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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/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-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-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
-golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
+golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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/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-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
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-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.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
-golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/net v0.0.0-20150829230318-ea47fc708ee3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/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-20181106065722-10aee1819953/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-20190206173232-65e2d4e15006/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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
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-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-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-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 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
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-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-20200520004742-59133d7f0dd7/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-20200813134508-3edf25e44fcc/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-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
-golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
-golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-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-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.2.0 h1:GtQkldQ9m7yvzCL1V+LrYow3Khe0eJH0w7RbX/VbaIU=
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-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/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
-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-20190209173611-3b5209105503/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-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-20190624142023-c5567b49c5d0/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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/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 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
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 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/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-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-20200519105757-fe76b779f299/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-20200814200057-3d37ad5750ed/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/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-20210603081109-ebe580a85c40/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
-golang.org/x/sys v0.5.0/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/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
-golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
-golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
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.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-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-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE=
-golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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-20181008205924-a2b3f7f249e9/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-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-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-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-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-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-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-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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
-golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
-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=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-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.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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
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.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 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
-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-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 h1:1mbrb1tUU+Zmt5C94IGKADBTJZjZXAd+BubWi7r9EiI=
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-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c=
-google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.18.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.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/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 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
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.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.36.0/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.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
-google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
-google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
-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.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=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk=
gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso=
gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo=
-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/httprequest.v1 v1.2.0/go.mod h1:T61ZUaJLpMnzvoJDO03ZD8yRXD4nZzBeDoW5e9sffjg=
-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/juju/environschema.v1 v1.0.0/go.mod h1:WTgU3KXKCVoO9bMmG/4KHzoaRvLeoxfjArpgd1MGWFA=
-gopkg.in/macaroon-bakery.v2 v2.3.0 h1:b40knPgPTke1QLTE8BSYeH7+R/hiIozB1A8CTLYN0Ic=
-gopkg.in/macaroon-bakery.v2 v2.3.0/go.mod h1:/8YhtPARXeRzbpEPLmRB66+gQE8/pzBBkWwg7Vz/guc=
+gopkg.in/macaroon-bakery.v2 v2.0.1 h1:0N1TlEdfLP4HXNCg7MQUMp5XwvOoxk+oe9Owr2cpvsc=
+gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA=
+gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I=
gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI=
gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o=
-gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
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.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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
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=
-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.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
-sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
diff --git a/internalapi/createboltcard.go b/internalapi/createboltcard.go
deleted file mode 100644
index a8aa8f3..0000000
--- a/internalapi/createboltcard.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package internalapi
-
-import (
- "net/http"
- "strconv"
- "strings"
-
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
- log "github.com/sirupsen/logrus"
-)
-
-// random_hex() from Createboltcardwithpin used here
-
-func Createboltcard(w http.ResponseWriter, r *http.Request) {
- if db.Get_setting("FUNCTION_INTERNAL_API") != "ENABLE" {
- msg := "createboltcard: internal API function is not enabled"
- log.Debug(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- tx_max_str := r.URL.Query().Get("tx_max")
- tx_max, err := strconv.Atoi(tx_max_str)
- if err != nil {
- msg := "createboltcard: tx_max is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- day_max_str := r.URL.Query().Get("day_max")
- day_max, err := strconv.Atoi(day_max_str)
- if err != nil {
- msg := "createboltcard: day_max is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- enable_flag_str := r.URL.Query().Get("enable")
- enable_flag, err := strconv.ParseBool(enable_flag_str)
- if err != nil {
- msg := "createboltcard: enable is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- card_name := r.URL.Query().Get("card_name")
- if card_name == "" {
- msg := "createboltcard: the card name must be set"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- uid_privacy_flag_str := r.URL.Query().Get("uid_privacy")
- uid_privacy_flag, err := strconv.ParseBool(uid_privacy_flag_str)
- if err != nil {
- msg := "createboltcard: uid_privacy is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- allow_neg_bal_flag_str := r.URL.Query().Get("allow_neg_bal")
- allow_neg_bal_flag, err := strconv.ParseBool(allow_neg_bal_flag_str)
- if err != nil {
- msg := "createboltcard: allow_neg_bal is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- // log the request
-
- log.WithFields(log.Fields{
- "card_name": card_name, "tx_max": tx_max, "day_max": day_max,
- "enable": enable_flag, "uid_privacy": uid_privacy_flag,
- "allow_neg_bal": allow_neg_bal_flag}).Info("createboltcard API request")
-
- // create the keys
-
- one_time_code := random_hex()
- k0_auth_key := random_hex()
- k2_cmac_key := random_hex()
- k3 := random_hex()
- k4 := random_hex()
-
- // create the new card record
-
- err = db.Insert_card(one_time_code, k0_auth_key, k2_cmac_key, k3, k4,
- tx_max, day_max, enable_flag, card_name,
- uid_privacy_flag, allow_neg_bal_flag)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- // return the URI + one_time_code
-
- hostdomain := db.Get_setting("HOST_DOMAIN")
- hostdomainPort := db.Get_setting("HOST_DOMAIN_PORT")
- hostdomainsuffix := ""
- if hostdomainPort != "" {
- hostdomainsuffix = ":" + hostdomainPort
- }
- url := ""
- if strings.HasSuffix(hostdomain, ".onion") {
- url = "http://" + hostdomain + hostdomainsuffix + "/new?a=" + one_time_code
- } else {
- url = "https://" + hostdomain + hostdomainsuffix + "/new?a=" + one_time_code
- }
-
- // log the response
-
- log.WithFields(log.Fields{
- "card_name": card_name, "url": url}).Info("createboltcard API response")
-
- jsonData := []byte(`{"status":"OK",` +
- `"url":"` + url + `"}`)
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write(jsonData)
-}
diff --git a/internalapi/createboltcardwithpin.go b/internalapi/createboltcardwithpin.go
deleted file mode 100644
index a7e8cd8..0000000
--- a/internalapi/createboltcardwithpin.go
+++ /dev/null
@@ -1,159 +0,0 @@
-package internalapi
-
-import (
- "crypto/rand"
- "encoding/hex"
- "net/http"
- "strconv"
- "strings"
-
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
- log "github.com/sirupsen/logrus"
-)
-
-func random_hex() string {
- b := make([]byte, 16)
- _, err := rand.Read(b)
- if err != nil {
- log.Warn(err.Error())
- return ""
- }
-
- return hex.EncodeToString(b)
-}
-
-func Createboltcardwithpin(w http.ResponseWriter, r *http.Request) {
- if db.Get_setting("FUNCTION_INTERNAL_API") != "ENABLE" {
- msg := "createboltcardwithpin: internal API function is not enabled"
- log.Debug(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- tx_max_str := r.URL.Query().Get("tx_max")
- tx_max, err := strconv.Atoi(tx_max_str)
- if err != nil {
- msg := "createboltcardwithpin: tx_max is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- day_max_str := r.URL.Query().Get("day_max")
- day_max, err := strconv.Atoi(day_max_str)
- if err != nil {
- msg := "createboltcardwithpin: day_max is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- enable_flag_str := r.URL.Query().Get("enable")
- enable_flag, err := strconv.ParseBool(enable_flag_str)
- if err != nil {
- msg := "createboltcardwithpin: enable is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- card_name := r.URL.Query().Get("card_name")
- if card_name == "" {
- msg := "createboltcardwithpin: the card name must be set"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- uid_privacy_flag_str := r.URL.Query().Get("uid_privacy")
- uid_privacy_flag, err := strconv.ParseBool(uid_privacy_flag_str)
- if err != nil {
- msg := "createboltcardwithpin: uid_privacy is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- allow_neg_bal_flag_str := r.URL.Query().Get("allow_neg_bal")
- allow_neg_bal_flag, err := strconv.ParseBool(allow_neg_bal_flag_str)
- if err != nil {
- msg := "createboltcardwithpin: allow_neg_bal is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- pin_enable_flag_str := r.URL.Query().Get("enable_pin")
- pin_enable_flag, err := strconv.ParseBool(pin_enable_flag_str)
- if err != nil {
- msg := "createboltcardwithpin: enable_pin is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- pin_number := r.URL.Query().Get("pin_number")
-
- pin_limit_sats_str := r.URL.Query().Get("pin_limit_sats")
- pin_limit_sats, err := strconv.Atoi(pin_limit_sats_str)
- if err != nil {
- msg := "createboltcardwithpin: pin_limit_sats is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- // log the request
-
- log.WithFields(log.Fields{
- "card_name": card_name, "tx_max": tx_max, "day_max": day_max,
- "enable": enable_flag, "uid_privacy": uid_privacy_flag,
- "allow_neg_bal": allow_neg_bal_flag, "enable_pin": pin_enable_flag,
- "pin_number": pin_number, "pin_limit_sats": pin_limit_sats}).Info("createboltcardwithpin API request")
-
- // create the keys
-
- one_time_code := random_hex()
- k0_auth_key := random_hex()
- k2_cmac_key := random_hex()
- k3 := random_hex()
- k4 := random_hex()
-
- // create the new card record
-
- err = db.Insert_card_with_pin(one_time_code, k0_auth_key, k2_cmac_key, k3, k4,
- tx_max, day_max, enable_flag, card_name,
- uid_privacy_flag, allow_neg_bal_flag, pin_enable_flag, pin_number, pin_limit_sats)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- // return the URI + one_time_code
-
- hostdomain := db.Get_setting("HOST_DOMAIN")
- hostdomainPort := db.Get_setting("HOST_DOMAIN_PORT")
- hostdomainsuffix := ""
- if hostdomainPort != "" {
- hostdomainsuffix = ":" + hostdomainPort
- }
- url := ""
- if strings.HasSuffix(hostdomain, ".onion") {
- url = "http://" + hostdomain + hostdomainsuffix + "/new?a=" + one_time_code
- } else {
- url = "https://" + hostdomain + hostdomainsuffix + "/new?a=" + one_time_code
- }
-
- // log the response
-
- log.WithFields(log.Fields{
- "card_name": card_name, "url": url}).Info("createboltcard API response")
-
- jsonData := []byte(`{"status":"OK",` +
- `"url":"` + url + `"}`)
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write(jsonData)
-}
diff --git a/internalapi/getboltcard.go b/internalapi/getboltcard.go
deleted file mode 100644
index 0103752..0000000
--- a/internalapi/getboltcard.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package internalapi
-
-import (
- "net/http"
- "strconv"
-
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
- log "github.com/sirupsen/logrus"
-)
-
-func Getboltcard(w http.ResponseWriter, r *http.Request) {
- if db.Get_setting("FUNCTION_INTERNAL_API") != "ENABLE" {
- msg := "getboltcard: internal API function is not enabled"
- log.Debug(msg)
- resp_err.Write_message(w, msg)
- return
- }
- card_name := r.URL.Query().Get("card_name")
-
- // log the request
-
- log.WithFields(log.Fields{
- "card_name": card_name}).Info("getboltcard API request")
-
- // get the card record
-
- c, err := db.Get_card_from_card_name(card_name)
- if err != nil {
- msg := "getboltcard: a non-wiped card with the card_name does not exist in the database"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- jsonData := []byte(`{"status":"OK",` +
- `"uid": "` + c.Db_uid + `",` +
- `"lnurlw_enable": "` + c.Lnurlw_enable + `",` +
- `"tx_limit_sats": "` + strconv.Itoa(c.Tx_limit_sats) + `",` +
- `"day_limit_sats": "` + strconv.Itoa(c.Day_limit_sats) + `", ` +
- `"pin_enable": "` + c.Pin_enable + `", ` +
- `"pin_limit_sats": "` + strconv.Itoa(c.Pin_limit_sats) + `"}`)
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write(jsonData)
-}
diff --git a/internalapi/ping.go b/internalapi/ping.go
deleted file mode 100644
index 9a3d9d5..0000000
--- a/internalapi/ping.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package internalapi
-
-import (
- "net/http"
-)
-
-func Internal_ping(w http.ResponseWriter, req *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- jsonData := []byte(`{"status":"OK","pong":"internal API"}`)
- w.Write(jsonData)
-}
diff --git a/internalapi/updateboltcard.go b/internalapi/updateboltcard.go
deleted file mode 100644
index ae6ea20..0000000
--- a/internalapi/updateboltcard.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package internalapi
-
-import (
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
- log "github.com/sirupsen/logrus"
- "net/http"
- "strconv"
-)
-
-func Updateboltcard(w http.ResponseWriter, r *http.Request) {
- if db.Get_setting("FUNCTION_INTERNAL_API") != "ENABLE" {
- msg := "updateboltcard: internal API function is not enabled"
- log.Debug(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- enable_flag_str := r.URL.Query().Get("enable")
- enable_flag, err := strconv.ParseBool(enable_flag_str)
- if err != nil {
- msg := "updateboltcard: enable is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- tx_max_str := r.URL.Query().Get("tx_max")
- tx_max, err := strconv.Atoi(tx_max_str)
- if err != nil {
- msg := "updateboltcard: tx_max is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- day_max_str := r.URL.Query().Get("day_max")
- day_max, err := strconv.Atoi(day_max_str)
- if err != nil {
- msg := "updateboltcard: day_max is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- card_name := r.URL.Query().Get("card_name")
-
- // check if card_name exists
-
- card_count, err := db.Get_card_name_count(card_name)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- if card_count == 0 {
- msg := "updateboltcard: the card name does not exist in the database"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- // log the request
-
- log.WithFields(log.Fields{
- "card_name": card_name, "tx_max": tx_max, "day_max": day_max,
- "enable": enable_flag}).Info("updateboltcard API request")
-
- // update the card record
-
- err = db.Update_card(card_name, enable_flag, tx_max, day_max)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- // send a response
-
- jsonData := []byte(`{"status":"OK"}`)
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write(jsonData)
-}
diff --git a/internalapi/updateboltcardwithpin.go b/internalapi/updateboltcardwithpin.go
deleted file mode 100644
index 26ab45a..0000000
--- a/internalapi/updateboltcardwithpin.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package internalapi
-
-import (
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
- log "github.com/sirupsen/logrus"
- "net/http"
- "strconv"
-)
-
-func Updateboltcardwithpin(w http.ResponseWriter, r *http.Request) {
- if db.Get_setting("FUNCTION_INTERNAL_API") != "ENABLE" {
- msg := "updateboltcardwithpin: internal API function is not enabled"
- log.Debug(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- enable_flag_str := r.URL.Query().Get("enable")
- enable_flag, err := strconv.ParseBool(enable_flag_str)
- if err != nil {
- msg := "updateboltcardwithpin: enable is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- tx_max_str := r.URL.Query().Get("tx_max")
- tx_max, err := strconv.Atoi(tx_max_str)
- if err != nil {
- msg := "updateboltcardwithpin: tx_max is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- day_max_str := r.URL.Query().Get("day_max")
- day_max, err := strconv.Atoi(day_max_str)
- if err != nil {
- msg := "updateboltcardwithpin: day_max is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- pin_enable_flag_str := r.URL.Query().Get("enable_pin")
- pin_enable_flag, err := strconv.ParseBool(pin_enable_flag_str)
- if err != nil {
- msg := "updateboltcardwithpin: enable_pin is not a valid boolean"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- pin_number := r.URL.Query().Get("pin_number")
-
- pin_limit_sats_str := r.URL.Query().Get("pin_limit_sats")
- pin_limit_sats, err := strconv.Atoi(pin_limit_sats_str)
- if err != nil {
- msg := "updateboltcardwithpin: pin_limit_sats is not a valid integer"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- card_name := r.URL.Query().Get("card_name")
-
- // check if card_name exists
-
- card_count, err := db.Get_card_name_count(card_name)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- if card_count == 0 {
- msg := "updateboltcardwithpin: the card name does not exist in the database"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- // log the request
-
- log.WithFields(log.Fields{
- "card_name": card_name, "tx_max": tx_max, "day_max": day_max,
- "enable": enable_flag, "enable_pin": pin_enable_flag,
- "pin_number": pin_number, "pin_limit_sats": pin_limit_sats}).Info("updateboltcardwithpin API request")
-
- // update the card record
-
- if pin_number == "" {
- err = db.Update_card_with_part_pin(card_name, enable_flag, tx_max, day_max,
- pin_enable_flag, pin_limit_sats)
- if err != nil {
- log.Warn(err.Error())
- return
- }
- }
-
- if pin_number != "" {
- err = db.Update_card_with_pin(card_name, enable_flag, tx_max, day_max,
- pin_enable_flag, pin_number, pin_limit_sats)
- if err != nil {
- log.Warn(err.Error())
- return
- }
- }
-
- // send a response
-
- jsonData := []byte(`{"status":"OK"}`)
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write(jsonData)
-}
diff --git a/internalapi/wipeboltcard.go b/internalapi/wipeboltcard.go
deleted file mode 100644
index 10cfad5..0000000
--- a/internalapi/wipeboltcard.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package internalapi
-
-import (
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
- log "github.com/sirupsen/logrus"
- "net/http"
- "strconv"
-)
-
-func Wipeboltcard(w http.ResponseWriter, r *http.Request) {
- if db.Get_setting("FUNCTION_INTERNAL_API") != "ENABLE" {
- msg := "wipeboltcard: internal API function is not enabled"
- log.Debug(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- card_name := r.URL.Query().Get("card_name")
-
- // check if card_name has been given
-
- if card_name == "" {
- msg := "wipeboltcard: the card name must be set"
- log.Warn(msg)
- resp_err.Write_message(w, msg)
- return
- }
-
- // set the card as wiped and disabled, get the keys
-
- card_wipe_info_values, err := db.Wipe_card(card_name)
- if err != nil {
- log.Warn(err.Error())
- return
- }
-
- // log the request
-
- log.WithFields(log.Fields{
- "card_name": card_name}).Info("wipeboltcard API request")
-
- // generate a response
-
- jsonData := `{"status":"OK",` +
- `"action": "wipe",` +
- `"id": ` + strconv.Itoa(card_wipe_info_values.Id) + `,` +
- `"k0": "` + card_wipe_info_values.K0 + `",` +
- `"k1": "` + card_wipe_info_values.K1 + `",` +
- `"k2": "` + card_wipe_info_values.K2 + `",` +
- `"k3": "` + card_wipe_info_values.K3 + `",` +
- `"k4": "` + card_wipe_info_values.K4 + `",` +
- `"uid": "` + card_wipe_info_values.Uid + `",` +
- `"version": 1}`
-
- // log the response
-
- log.WithFields(log.Fields{
- "card_name": card_name, "response": jsonData}).Info("wipeboltcard API response")
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(jsonData))
-}
diff --git a/lightning.go b/lightning.go
new file mode 100644
index 0000000..ade078e
--- /dev/null
+++ b/lightning.go
@@ -0,0 +1,131 @@
+package main
+
+import (
+ "context"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "strconv"
+ "time"
+
+ lnrpc "github.com/lncm/lnd-rpc/v0.10.0/lnrpc"
+ routerrpc "github.com/lncm/lnd-rpc/v0.10.0/routerrpc"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials"
+
+ "gopkg.in/macaroon.v2"
+)
+
+type rpcCreds map[string]string
+
+func (m rpcCreds) RequireTransportSecurity() bool { return true }
+func (m rpcCreds) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
+ return m, nil
+}
+func newCreds(bytes []byte) rpcCreds {
+ creds := make(map[string]string)
+ creds["macaroon"] = hex.EncodeToString(bytes)
+ return creds
+}
+
+func getRouterClient(hostname string, port int, tlsFile, macaroonFile string) routerrpc.RouterClient {
+ macaroonBytes, err := ioutil.ReadFile(macaroonFile)
+ if err != nil {
+ log.Println("Cannot read macaroon file .. ", err)
+ panic(err)
+ }
+
+ mac := &macaroon.Macaroon{}
+ if err = mac.UnmarshalBinary(macaroonBytes); err != nil {
+ log.Println("Cannot unmarshal macaroon .. ", err)
+ panic(err)
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ transportCredentials, err := credentials.NewClientTLSFromFile(tlsFile, hostname)
+ if err != nil {
+ panic(err)
+ }
+
+ fullHostname := fmt.Sprintf("%s:%d", hostname, port)
+
+ connection, err := grpc.DialContext(ctx, fullHostname, []grpc.DialOption{
+ grpc.WithBlock(),
+ grpc.WithTransportCredentials(transportCredentials),
+ grpc.WithPerRPCCredentials(newCreds(macaroonBytes)),
+ }...)
+ if err != nil {
+ log.Printf("unable to connect to %s: %w", fullHostname, err)
+ panic(err)
+ }
+
+ return routerrpc.NewRouterClient(connection)
+}
+
+func pay_invoice(invoice string) (payment_status string, failure_reason string, return_err error) {
+
+ payment_status = ""
+ failure_reason = ""
+ return_err = nil
+
+ // SendPaymentV2
+
+ ctx2, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ // get node parameters from environment variables
+
+ ln_port, err := strconv.Atoi(os.Getenv("LN_PORT"))
+ if err != nil {
+ return_err = err
+ return
+ }
+
+ r_client := getRouterClient(
+ os.Getenv("LN_HOST"),
+ ln_port,
+ os.Getenv("LN_TLS_FILE"),
+ os.Getenv("LN_MACAROON_FILE"))
+
+ fee_limit_sat_str := os.Getenv("FEE_LIMIT_SAT")
+ fee_limit_sat, err := strconv.ParseInt(fee_limit_sat_str, 10, 64)
+ if err != nil {
+ return_err = err
+ return
+ }
+
+ stream, err := r_client.SendPaymentV2(ctx2, &routerrpc.SendPaymentRequest{
+ PaymentRequest: invoice,
+ NoInflightUpdates: true,
+ TimeoutSeconds: 30,
+ FeeLimitSat: fee_limit_sat})
+
+ if err != nil {
+ return_err = err
+ return
+ }
+
+ for {
+ update, err := stream.Recv()
+
+ if err == io.EOF {
+ break
+ }
+
+ if err != nil {
+ return_err = err
+ return
+ }
+
+ payment_status = lnrpc.Payment_PaymentStatus_name[int32(update.Status)]
+ failure_reason = lnrpc.PaymentFailureReason_name[int32(update.FailureReason)]
+ }
+
+ return
+}
diff --git a/lnd/lnd.go b/lnd/lnd.go
deleted file mode 100644
index f86548c..0000000
--- a/lnd/lnd.go
+++ /dev/null
@@ -1,310 +0,0 @@
-package lnd
-
-import (
- "context"
- "crypto/sha256"
- "encoding/hex"
- "fmt"
- log "github.com/sirupsen/logrus"
- "io"
- "io/ioutil"
- "strconv"
- "time"
-
- decodepay "github.com/fiatjaf/ln-decodepay"
- lnrpc "github.com/lightningnetwork/lnd/lnrpc"
- invoicesrpc "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
- routerrpc "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
-
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials"
-
- "gopkg.in/macaroon.v2"
-
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/email"
-)
-
-type rpcCreds map[string]string
-
-func (m rpcCreds) RequireTransportSecurity() bool { return true }
-func (m rpcCreds) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
- return m, nil
-}
-func newCreds(bytes []byte) rpcCreds {
- creds := make(map[string]string)
- creds["macaroon"] = hex.EncodeToString(bytes)
- return creds
-}
-
-func getGrpcConn(hostname string, port int, tlsFile, macaroonFile string) *grpc.ClientConn {
- macaroonBytes, err := ioutil.ReadFile(macaroonFile)
- if err != nil {
- log.Println("Cannot read macaroon file .. ", err)
- panic(err)
- }
-
- mac := &macaroon.Macaroon{}
- if err = mac.UnmarshalBinary(macaroonBytes); err != nil {
- log.Println("Cannot unmarshal macaroon .. ", err)
- panic(err)
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
-
- transportCredentials, err := credentials.NewClientTLSFromFile(tlsFile, hostname)
- if err != nil {
- panic(err)
- }
-
- fullHostname := fmt.Sprintf("%s:%d", hostname, port)
-
- connection, err := grpc.DialContext(ctx, fullHostname, []grpc.DialOption{
- grpc.WithBlock(),
- grpc.WithTransportCredentials(transportCredentials),
- grpc.WithPerRPCCredentials(newCreds(macaroonBytes)),
- }...)
- if err != nil {
- log.Printf("unable to connect to %s", fullHostname)
- panic(err)
- }
-
- return connection
-}
-
-// https://api.lightning.community/?shell#addinvoice
-
-func Add_invoice(amount_sat int64, metadata string) (payment_request string, r_hash []byte, return_err error) {
-
- ln_port, err := strconv.Atoi(db.Get_setting("LN_PORT"))
- if err != nil {
- return "", nil, err
- }
- ln_invoice_expiry, err := strconv.ParseInt(db.Get_setting("LN_INVOICE_EXPIRY_SEC"), 10, 64)
- if err != nil {
- return "", nil, err
- }
-
- dh := sha256.Sum256([]byte(metadata))
-
- connection := getGrpcConn(
- db.Get_setting("LN_HOST"),
- ln_port,
- db.Get_setting("LN_TLS_FILE"),
- db.Get_setting("LN_MACAROON_FILE"))
-
- l_client := lnrpc.NewLightningClient(connection)
-
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
-
- result, err := l_client.AddInvoice(ctx, &lnrpc.Invoice{
- Value: amount_sat,
- DescriptionHash: dh[:],
- Expiry: ln_invoice_expiry,
- })
-
- if err != nil {
- return "", nil, err
- }
-
- return result.PaymentRequest, result.RHash, nil
-}
-
-// https://api.lightning.community/?shell#subscribesingleinvoice
-
-func Monitor_invoice_state(r_hash []byte) {
-
- // SubscribeSingleInvoice
-
- // get node parameters from environment variables
-
- ln_port, err := strconv.Atoi(db.Get_setting("LN_PORT"))
- if err != nil {
- log.Warn(err)
- return
- }
- ln_invoice_expiry, err := strconv.Atoi(db.Get_setting("LN_INVOICE_EXPIRY_SEC"))
- if err != nil {
- log.Warn(err)
- return
- }
-
- connection := getGrpcConn(
- db.Get_setting("LN_HOST"),
- ln_port,
- db.Get_setting("LN_TLS_FILE"),
- db.Get_setting("LN_MACAROON_FILE"))
-
- i_client := invoicesrpc.NewInvoicesClient(connection)
-
- ctx, cancel := context.WithTimeout(context.Background(), time.Duration(ln_invoice_expiry)*time.Second)
- defer cancel()
-
- stream, err := i_client.SubscribeSingleInvoice(ctx, &invoicesrpc.SubscribeSingleInvoiceRequest{
- RHash: r_hash})
- if err != nil {
- log.WithFields(log.Fields{"r_hash": hex.EncodeToString(r_hash)}).Warn(err)
- return
- }
-
- for {
- update, err := stream.Recv()
-
- if err == io.EOF {
- break
- }
-
- if err != nil {
- log.WithFields(log.Fields{"r_hash": hex.EncodeToString(r_hash)}).Warn(err)
- return
- }
-
- invoice_state := lnrpc.Invoice_InvoiceState_name[int32(update.State)]
-
- log.WithFields(
- log.Fields{
- "r_hash": hex.EncodeToString(r_hash),
- "invoice_state": invoice_state,
- }).Info("invoice state updated")
-
- db.Update_receipt_state(hex.EncodeToString(r_hash), invoice_state)
- }
-
- connection.Close()
-
- // send email
-
- card_id, err := db.Get_card_id_for_r_hash(hex.EncodeToString(r_hash))
- if err != nil {
- log.WithFields(log.Fields{"r_hash": hex.EncodeToString(r_hash)}).Warn(err)
- return
- }
-
- log.WithFields(log.Fields{"r_hash": hex.EncodeToString(r_hash), "card_id": card_id}).Debug("card found")
-
- c, err := db.Get_card_from_card_id(card_id)
- if err != nil {
- log.WithFields(log.Fields{"r_hash": hex.EncodeToString(r_hash)}).Warn(err)
- return
- }
-
- if c.Email_enable != "Y" {
- log.Debug("email is not enabled for the card")
- return
- }
-
- go email.Send_balance_email(c.Email_address, card_id)
-
- return
-}
-
-// https://api.lightning.community/?shell#sendpaymentv2
-
-func PayInvoice(card_payment_id int, invoice string) {
-
- // SendPaymentV2
-
- // get node parameters from environment variables
-
- ln_port, err := strconv.Atoi(db.Get_setting("LN_PORT"))
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Warn(err)
- return
- }
-
- connection := getGrpcConn(
- db.Get_setting("LN_HOST"),
- ln_port,
- db.Get_setting("LN_TLS_FILE"),
- db.Get_setting("LN_MACAROON_FILE"))
-
- r_client := routerrpc.NewRouterClient(connection)
-
- fee_limit_sat_str := db.Get_setting("FEE_LIMIT_SAT")
- fee_limit_sat, err := strconv.ParseInt(fee_limit_sat_str, 10, 64)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Warn(err)
- return
- }
-
- fee_limit_percent_str := db.Get_setting("FEE_LIMIT_PERCENT")
- fee_limit_percent, err := strconv.ParseFloat(fee_limit_percent_str, 64)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Warn(err)
- return
- }
-
- bolt11, _ := decodepay.Decodepay(invoice)
- invoice_msats := bolt11.MSatoshi
- invoice_expiry := bolt11.Expiry
-
- fee_limit_product := int64((fee_limit_percent / 100) * (float64(invoice_msats) / 1000))
-
- ctx, cancel := context.WithTimeout(context.Background(), time.Duration(invoice_expiry)*time.Second)
- defer cancel()
-
- stream, err := r_client.SendPaymentV2(ctx, &routerrpc.SendPaymentRequest{
- PaymentRequest: invoice,
- NoInflightUpdates: true,
- TimeoutSeconds: 30,
- FeeLimitSat: fee_limit_sat + fee_limit_product})
-
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Warn(err)
- return
- }
-
- for {
- update, err := stream.Recv()
-
- if err == io.EOF {
- break
- }
-
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Warn(err)
- return
- }
-
- payment_status := lnrpc.Payment_PaymentStatus_name[int32(update.Status)]
- failure_reason := lnrpc.PaymentFailureReason_name[int32(update.FailureReason)]
-
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Info("payment failure reason : ", failure_reason)
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Info("payment status : ", payment_status)
-
- err = db.Update_payment_status(card_payment_id, payment_status, failure_reason)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Warn(err)
- return
- }
- }
-
- connection.Close()
-
- // send email
-
- card_id, err := db.Get_card_id_for_card_payment_id(card_payment_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Warn(err)
- return
- }
-
- log.WithFields(log.Fields{"card_payment_id": card_payment_id, "card_id": card_id}).Debug("card found")
-
- c, err := db.Get_card_from_card_id(card_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": card_payment_id}).Warn(err)
- return
- }
-
- if c.Email_enable != "Y" {
- log.Debug("email is not enabled for the card")
- return
- }
-
- go email.Send_balance_email(c.Email_address, card_id)
-
- return
-}
diff --git a/lndhub/lndhub.go b/lndhub/lndhub.go
deleted file mode 100644
index d21e609..0000000
--- a/lndhub/lndhub.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package lndhub
-
-import (
- "bytes"
- "encoding/json"
- "io"
- "net/http"
- "strconv"
-
- "github.com/boltcard/boltcard/db"
- log "github.com/sirupsen/logrus"
-)
-
-type LndhubPayInvoiceRequest struct {
- Invoice string `json:"invoice"`
- FreeAmount string `json:"freeamount"`
- LoginId string `json:"loginid"`
-}
-
-func PayInvoice(cardPaymentId int, invoice string, amountSats int, loginId string, accessToken string) {
-
- lndhub_url := db.Get_setting("LNDHUB_URL")
-
- client := &http.Client{}
-
- //lndhub.payinvoice API call
- var payInvoiceRequest LndhubPayInvoiceRequest
- payInvoiceRequest.Invoice = invoice
- payInvoiceRequest.FreeAmount = strconv.Itoa(amountSats)
- payInvoiceRequest.LoginId = loginId
-
- req_payinvoice, err := json.Marshal(payInvoiceRequest)
- log.Info(string(req_payinvoice))
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": cardPaymentId}).Warn(err)
- return
- }
-
- req, err := http.NewRequest("POST", lndhub_url+"/payinvoice", bytes.NewBuffer(req_payinvoice))
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": cardPaymentId}).Warn(err)
- return
- }
-
- req.Header.Add("Access-Control-Allow-Origin", "*")
- req.Header.Add("Content-Type", "application/json")
- req.Header.Add("Authorization", "Bearer "+accessToken)
-
- res2, err := client.Do(req)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": cardPaymentId}).Warn(err)
- return
- }
-
- defer res2.Body.Close()
-
- b2, err := io.ReadAll(res2.Body)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": cardPaymentId}).Warn(err)
- return
- }
-
- log.Info(string(b2))
-}
diff --git a/lnurlp/lnurlp_callback.go b/lnurlp/lnurlp_callback.go
deleted file mode 100644
index 7d02eaf..0000000
--- a/lnurlp/lnurlp_callback.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package lnurlp
-
-import (
- "encoding/hex"
- "net/http"
- "strconv"
-
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/lnd"
- "github.com/boltcard/boltcard/resp_err"
- "github.com/gorilla/mux"
- log "github.com/sirupsen/logrus"
-)
-
-func Callback(w http.ResponseWriter, r *http.Request) {
- if db.Get_setting("FUNCTION_LNURLP") != "ENABLE" {
- log.Debug("LNURLp function is not enabled")
- return
- }
-
- name := mux.Vars(r)["name"]
- amount := r.URL.Query().Get("amount")
-
- card_id, err := db.Get_card_id_for_name(name)
- if err != nil {
- log.Info("card name not found")
- resp_err.Write(w)
- return
- }
-
- log.WithFields(
- log.Fields{
- "url_path": r.URL.Path,
- "name": name,
- "card_id": card_id,
- "amount": amount,
- "req.Host": r.Host,
- }).Info("lnurlp_callback")
-
- domain := db.Get_setting("HOST_DOMAIN")
- hostdomainPort := db.Get_setting("HOST_DOMAIN_PORT")
- hostdomainsuffix := ""
- if hostdomainPort != "" {
- hostdomainsuffix = ":" + hostdomainPort
- }
- if r.Host != domain {
- log.Warn("wrong host domain")
- resp_err.Write(w)
- return
- }
-
- amount_msat, err := strconv.ParseInt(amount, 10, 64)
- if err != nil {
- log.Warn("amount is not a valid integer")
- resp_err.Write(w)
- return
- }
-
- amount_sat := amount_msat / 1000
-
- metadata := "[[\"text/identifier\",\"" + name + "@" + domain + hostdomainsuffix + "\"],[\"text/plain\",\"bolt card deposit\"]]"
- pr, r_hash, err := lnd.Add_invoice(amount_sat, metadata)
- if err != nil {
- log.Warn("could not add_invoice")
- resp_err.Write(w)
- return
- }
-
- err = db.Insert_receipt(card_id, pr, hex.EncodeToString(r_hash), amount_msat)
- if err != nil {
- log.Warn(err)
- resp_err.Write(w)
- return
- }
-
- go lnd.Monitor_invoice_state(r_hash)
-
- log.Debug("sending 'status OK' response")
-
- jsonData := []byte(`{` +
- `"status":"OK",` +
- `"routes":[],` +
- `"pr":"` + pr + `"` +
- `}`)
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write(jsonData)
-}
diff --git a/lnurlp/lnurlp_request.go b/lnurlp/lnurlp_request.go
deleted file mode 100644
index 853614d..0000000
--- a/lnurlp/lnurlp_request.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package lnurlp
-
-import (
- "net/http"
-
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
- "github.com/gorilla/mux"
- log "github.com/sirupsen/logrus"
-)
-
-func Response(w http.ResponseWriter, r *http.Request) {
- if db.Get_setting("FUNCTION_LNURLP") != "ENABLE" {
- log.Debug("LNURLp function is not enabled")
- return
- }
-
- name := mux.Vars(r)["name"]
-
- log.WithFields(
- log.Fields{
- "url_path": r.URL.Path,
- "name": name,
- "r.Host": r.Host,
- }).Info("lnurlp_response")
-
- // look up domain setting (HOST_DOMAIN)
-
- domain := db.Get_setting("HOST_DOMAIN")
- hostdomainPort := db.Get_setting("HOST_DOMAIN_PORT")
- hostdomainsuffix := ""
- if hostdomainPort != "" {
- hostdomainsuffix = ":" + hostdomainPort
- }
- if r.Host != domain {
- log.Warn("wrong host domain")
- resp_err.Write(w)
- return
- }
-
- // look up name in database (table cards, field card_name)
-
- card_count, err := db.Get_card_count_for_name_lnurlp(name)
- if err != nil {
- log.Warn("could not get card count for name")
- resp_err.Write(w)
- return
- }
-
- if card_count != 1 {
- log.Info("not one enabled card with that name")
- resp_err.Write(w)
- return
- }
-
- metadata := "[[\\\"text/identifier\\\",\\\"" + name + "@" + domain + hostdomainsuffix + "\\\"],[\\\"text/plain\\\",\\\"bolt card deposit\\\"]]"
-
- jsonData := []byte(`{"status":"OK",` +
- `"callback":"https://` + domain + hostdomainsuffix + `/lnurlp/` + name + `",` +
- `"tag":"payRequest",` +
- `"maxSendable":1000000000,` +
- `"minSendable":1000,` +
- `"metadata":"` + metadata + `",` +
- `"commentAllowed":0` +
- `}`)
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write(jsonData)
-}
diff --git a/lnurlw/lnurlw_callback.go b/lnurlw/lnurlw_callback.go
deleted file mode 100644
index de8c74f..0000000
--- a/lnurlw/lnurlw_callback.go
+++ /dev/null
@@ -1,320 +0,0 @@
-package lnurlw
-
-import (
- "bytes"
- "encoding/json"
- "io"
- "net/http"
- "strings"
-
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/lnd"
- "github.com/boltcard/boltcard/lndhub"
- "github.com/boltcard/boltcard/resp_err"
- decodepay "github.com/fiatjaf/ln-decodepay"
- log "github.com/sirupsen/logrus"
-)
-
-type LndhubAuthRequest struct {
- Login string `json:"login"`
- Password string `json:"password"`
-}
-
-type LndhubAuthResponse struct {
- RefreshToken string `json:"refresh_token"`
- AccessToken string `json:"access_token"`
-}
-
-func lndhub_payment(w http.ResponseWriter, p *db.Payment, bolt11 decodepay.Bolt11, param_pr string) {
-
- //get setting for LNDHUB_URL
- lndhub_url := db.Get_setting("LNDHUB_URL")
-
- //get lndhub login details from database
- c, err := db.Get_card_from_card_id(p.Card_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- // check amount limits
- invoice_sats := int(bolt11.MSatoshi / 1000)
-
- //check the tx limit
- if invoice_sats > c.Tx_limit_sats {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("invoice_sats: ", invoice_sats)
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("tx_limit_sats: ", c.Tx_limit_sats)
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("over tx_limit_sats!")
- resp_err.Write(w)
- return
- }
-
- //lndhub.auth API call
- //the login JSON is held in the Card_name field
- // as "login:password"
- card_name_parts := strings.Split(c.Card_name, ":")
-
- if len(card_name_parts) != 2 {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn("login:password not found")
- resp_err.Write(w)
- return
- }
-
- if len(card_name_parts[0]) != 20 || len(card_name_parts[1]) != 20 {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn("login:password badly formed")
- resp_err.Write(w)
- return
- }
-
- var lhAuthRequest LndhubAuthRequest
- lhAuthRequest.Login = card_name_parts[0]
- lhAuthRequest.Password = card_name_parts[1]
-
- authReq, err := json.Marshal(lhAuthRequest)
-
- req_auth, err := http.NewRequest("POST", lndhub_url+"/auth", bytes.NewBuffer(authReq))
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- req_auth.Header.Add("Access-Control-Allow-Origin", "*")
- req_auth.Header.Add("Content-Type", "application/json")
-
- client := &http.Client{}
- resp_auth, err := client.Do(req_auth)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- defer resp_auth.Body.Close()
-
- resp_auth_bytes, err := io.ReadAll(resp_auth.Body)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id,
- "resp_auth_bytes": string(resp_auth_bytes)}).Info("issue 62")
-
- var auth_keys LndhubAuthResponse
-
- err = json.Unmarshal([]byte(resp_auth_bytes), &auth_keys)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- // update paid_flag so we only attempt payment once
- err = db.Update_payment_paid(p.Card_payment_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- // https://github.com/fiatjaf/lnurl-rfc/blob/luds/03.md
- //
- // LN SERVICE sends a {"status": "OK"} or
- // {"status": "ERROR", "reason": "error details..."}
- // JSON response and then attempts to pay the invoices asynchronously.
-
- go lndhub.PayInvoice(p.Card_payment_id, param_pr, int(bolt11.MSatoshi/1000), card_name_parts[0], auth_keys.AccessToken)
-
- log.Debug("sending 'status OK' response")
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- jsonData := []byte(`{"status":"OK"}`)
- w.Write(jsonData)
-}
-
-func lnd_payment(w http.ResponseWriter, p *db.Payment, bolt11 decodepay.Bolt11, param_pr string) {
-
- // check amount limits
- invoice_sats := int(bolt11.MSatoshi / 1000)
-
- day_total_sats, err := db.Get_card_totals(p.Card_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- c, err := db.Get_card_from_card_id(p.Card_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- if invoice_sats > c.Tx_limit_sats {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("invoice_sats: ", invoice_sats)
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("tx_limit_sats: ", c.Tx_limit_sats)
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("over tx_limit_sats!")
- resp_err.Write(w)
- return
- }
-
- if day_total_sats+invoice_sats > c.Day_limit_sats {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("invoice_sats: ", invoice_sats)
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("day_total_sats: ", day_total_sats)
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("day_limit_sats: ", c.Day_limit_sats)
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("over day_limit_sats!")
- resp_err.Write(w)
- return
- }
-
- // check the card balance if marked as 'must stay above zero' (default)
- // i.e. cards.allow_negative_balance == 'N'
- if c.Allow_negative_balance != "Y" {
- card_total, err := db.Get_card_total_sats(p.Card_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- if card_total-invoice_sats < 0 {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn("not enough balance")
- resp_err.Write(w)
- return
- }
- }
-
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("paying invoice")
-
- // update paid_flag so we only attempt payment once
- err = db.Update_payment_paid(p.Card_payment_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- // https://github.com/fiatjaf/lnurl-rfc/blob/luds/03.md
- //
- // LN SERVICE sends a {"status": "OK"} or
- // {"status": "ERROR", "reason": "error details..."}
- // JSON response and then attempts to pay the invoices asynchronously.
-
- go lnd.PayInvoice(p.Card_payment_id, param_pr)
-
- log.Debug("sending 'status OK' response")
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- jsonData := []byte(`{"status":"OK"}`)
- w.Write(jsonData)
-}
-
-func Callback(w http.ResponseWriter, req *http.Request) {
-
- env_host_domain := db.Get_setting("HOST_DOMAIN")
- if req.Host != env_host_domain {
- log.Warn("wrong host domain")
- resp_err.Write(w)
- return
- }
-
- url := req.URL.RequestURI()
- log.WithFields(log.Fields{"url": url}).Debug("cb request")
-
- // get k1 value
- param_k1 := req.URL.Query().Get("k1")
-
- if param_k1 == "" {
- log.WithFields(log.Fields{"url": url}).Debug("k1 not found")
- resp_err.Write(w)
- return
- }
-
- p, err := db.Get_payment_k1(param_k1)
- if err != nil {
- log.WithFields(log.Fields{"url": url, "k1": param_k1}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- // check that payment has not been made
- if p.Paid_flag != "N" {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("payment already made")
- resp_err.Write(w)
- return
- }
-
- // check if lnurlw_request has timed out
- lnurlw_timeout, err := db.Check_lnurlw_timeout(p.Card_payment_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
- if lnurlw_timeout == true {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("lnurlw request has timed out")
- resp_err.Write(w)
- return
- }
-
- // get the payment request
- param_pr := req.URL.Query().Get("pr")
- if param_pr == "" {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn("pr field not found")
- resp_err.Write(w)
- return
- }
-
- bolt11, _ := decodepay.Decodepay(param_pr)
-
- // record the lightning invoice
- err = db.Update_payment_invoice(p.Card_payment_id, param_pr, bolt11.MSatoshi)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Debug("checking payment rules")
-
- // get the pin if it has been passed in
- param_pin := req.URL.Query().Get("pin")
-
- c, err := db.Get_card_from_card_id(p.Card_id)
- if err != nil {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- // check the pin if needed
- if c.Pin_enable == "Y" && int(bolt11.MSatoshi/1000) >= c.Pin_limit_sats && c.Pin_number != param_pin {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn("incorrect pin provided")
- resp_err.Write(w)
- return
- }
-
- // check if we are only sending funds to a defined test node
- testnode := db.Get_setting("LN_TESTNODE")
- if testnode != "" && bolt11.Payee != testnode {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("rejected as not the defined test node")
- resp_err.Write(w)
- return
- }
-
- //check if we are using LND or LNDHUB for payment
- lndhub := db.Get_setting("FUNCTION_LNDHUB")
- if lndhub == "ENABLE" {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("initiating lndhub payment")
- lndhub_payment(w, p, bolt11, param_pr)
- } else {
- log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("initiating lnd payment")
- lnd_payment(w, p, bolt11, param_pr)
- }
-}
diff --git a/lnurlw/lnurlw_request.go b/lnurlw/lnurlw_request.go
deleted file mode 100644
index ad392a9..0000000
--- a/lnurlw/lnurlw_request.go
+++ /dev/null
@@ -1,348 +0,0 @@
-package lnurlw
-
-import (
- "encoding/hex"
- "encoding/json"
- "errors"
- "net/http"
- "os"
- "strconv"
- "strings"
-
- "github.com/boltcard/boltcard/crypto"
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
- log "github.com/sirupsen/logrus"
-)
-
-func get_p_c(req *http.Request, p_name string, c_name string) (p string, c string) {
-
- params_p, ok := req.URL.Query()[p_name]
-
- if !ok || len(params_p[0]) < 1 {
- return "", ""
- }
-
- params_c, ok := req.URL.Query()[c_name]
-
- if !ok || len(params_c[0]) < 1 {
- return "", ""
- }
-
- p = params_p[0]
- c = params_c[0]
-
- return
-}
-
-func check_cmac(uid []byte, ctr []byte, k2_cmac_key []byte, cmac []byte) (bool, error) {
-
- sv2 := make([]byte, 16)
- sv2[0] = 0x3c
- sv2[1] = 0xc3
- sv2[2] = 0x00
- sv2[3] = 0x01
- sv2[4] = 0x00
- sv2[5] = 0x80
- sv2[6] = uid[0]
- sv2[7] = uid[1]
- sv2[8] = uid[2]
- sv2[9] = uid[3]
- sv2[10] = uid[4]
- sv2[11] = uid[5]
- sv2[12] = uid[6]
- sv2[13] = ctr[0]
- sv2[14] = ctr[1]
- sv2[15] = ctr[2]
-
- cmac_verified, err := crypto.Aes_cmac(k2_cmac_key, sv2, cmac)
-
- if err != nil {
- return false, err
- }
-
- return cmac_verified, nil
-}
-
-func setup_card_record(uid string, ctr uint32, uid_bin []byte, ctr_bin []byte, cmac []byte) error {
-
- // find the card record by matching the cmac
- // get possible card records from the database
-
- cards, err := db.Get_cards_blank_uid()
-
- if err != nil {
- return errors.New("db.Get_cards_blank_uid errored")
- }
-
- // check card records for a matching cmac
-
- for _, card := range cards {
-
- // check the cmac
-
- k2_cmac_key, err := hex.DecodeString(card.K2_cmac_key)
-
- if err != nil {
- log.WithFields(log.Fields{
- "card.card_id": card.Card_id,
- "card.k2_cmac_key": card.K2_cmac_key,
- }).Warn("card.k2_cmac_key decode failed - remove the invalid record")
- return err
- }
-
- cmac_valid, err := check_cmac(uid_bin, ctr_bin, k2_cmac_key, cmac)
-
- if err != nil {
- return err
- }
-
- if cmac_valid == true {
- log.WithFields(log.Fields{
- "card.card_id": card.Card_id,
- "card.k2_cmac_key": card.K2_cmac_key,
- }).Info("cmac match found")
-
- // store the uid and ctr in the card record
- err := db.Update_card_uid_ctr(card.Card_id, uid, ctr)
-
- if err != nil {
- return err
- }
-
- return nil
- }
- }
-
- log.Info("card record not found")
-
- return nil
-}
-
-func parse_request(req *http.Request) (int, error) {
-
- pid := os.Getpid()
- url := req.URL.RequestURI()
- log.WithFields(log.Fields{"pid": pid, "url": url}).Debug("ln request")
-
- param_p, param_c := get_p_c(req, "p", "c")
-
- ba_p, err := hex.DecodeString(param_p)
-
- if err != nil {
- return 0, errors.New("p parameter not valid hex")
- }
-
- ba_c, err := hex.DecodeString(param_c)
-
- if err != nil {
- return 0, errors.New("c parameter not valid hex")
- }
-
- if len(ba_p) != 16 {
- return 0, errors.New("p parameter length not valid")
- }
-
- if len(ba_c) != 8 {
- return 0, errors.New("c parameter length not valid")
- }
-
- // decrypt p with aes_decrypt_key
-
- aes_decrypt_key := db.Get_setting("AES_DECRYPT_KEY")
-
- key_sdm_file_read, err := hex.DecodeString(aes_decrypt_key)
-
- if err != nil {
- return 0, err
- }
-
- dec_p, err := crypto.Aes_decrypt(key_sdm_file_read, ba_p)
-
- if err != nil {
- return 0, err
- }
-
- if dec_p[0] != 0xC7 {
- return 0, errors.New("decrypted data not starting with 0xC7")
- }
-
- uid := dec_p[1:8]
- ctr := dec_p[8:11]
-
- ctr_int := uint32(ctr[2])<<16 | uint32(ctr[1])<<8 | uint32(ctr[0])
-
- // set up uid & ctr for card record if needed
-
- uid_str := hex.EncodeToString(uid)
-
- log.WithFields(log.Fields{"uid": uid_str, "ctr": ctr_int}).Info("decrypted card data")
-
- card_count, err := db.Get_card_count_for_uid(uid_str)
-
- if err != nil {
- return 0, errors.New("could not get card count for uid")
- }
-
- if card_count == 0 {
- log.Info("check CMACs and set UID")
- setup_card_record(uid_str, ctr_int, uid, ctr, ba_c)
- }
-
- if card_count > 1 {
- return 0, errors.New("more than one card found for uid")
- }
-
- // check card payment rules and make payment if appropriate
-
- // get card record from database for UID
-
- c, err := db.Get_card_from_uid(uid_str)
-
- if err != nil {
- return 0, errors.New("card not found for uid")
- }
-
- // check if card is enabled
-
- if c.Lnurlw_enable != "Y" {
- return 0, errors.New("card lnurlw enable is not set to Y")
- }
-
- // check cmac
-
- k2_cmac_key, err := hex.DecodeString(c.K2_cmac_key)
-
- if err != nil {
- return 0, err
- }
-
- cmac_valid, err := check_cmac(uid, ctr, k2_cmac_key, ba_c)
-
- if err != nil {
- return 0, err
- }
-
- if cmac_valid == false {
- return 0, errors.New("cmac incorrect")
- }
-
- // check and update last_counter_value
-
- counter_ok, err := db.Check_and_update_counter(c.Card_id, ctr_int)
-
- if err != nil {
- return 0, err
- }
-
- if counter_ok == false {
- return 0, errors.New("counter not increasing")
- }
-
- log.WithFields(log.Fields{"card_id": c.Card_id, "counter": ctr_int}).Info("validated")
-
- return c.Card_id, nil
-}
-
-func Response(w http.ResponseWriter, req *http.Request) {
-
- env_host_domain := db.Get_setting("HOST_DOMAIN")
- hostdomainPort := db.Get_setting("HOST_DOMAIN_PORT")
- hostdomainsuffix := ""
- if hostdomainPort != "" {
- hostdomainsuffix = ":" + hostdomainPort
- }
-
- if req.Host != env_host_domain {
- log.Warn("wrong host domain")
- resp_err.Write(w)
- return
- }
-
- card_id, err := parse_request(req)
-
- if err != nil {
- log.Debug(err.Error())
- resp_err.Write(w)
- return
- }
-
- lnurlw_k1, err := crypto.Create_k1()
-
- if err != nil {
- log.Warn(err.Error())
- resp_err.Write(w)
- return
- }
-
- // store k1 in database and include in response
-
- err = db.Insert_payment(card_id, lnurlw_k1)
-
- if err != nil {
- log.Warn(err.Error())
- resp_err.Write(w)
- return
- }
-
- lnurlw_cb_url := ""
- if strings.HasSuffix(env_host_domain, ".onion") {
- lnurlw_cb_url = "http://" + env_host_domain + hostdomainsuffix + "/cb"
- } else {
- lnurlw_cb_url = "https://" + env_host_domain + hostdomainsuffix + "/cb"
- }
-
- min_withdraw_sats_str := db.Get_setting("MIN_WITHDRAW_SATS")
- min_withdraw_sats, err := strconv.Atoi(min_withdraw_sats_str)
-
- if err != nil {
- log.Warn(err.Error())
- resp_err.Write(w)
- return
- }
-
- max_withdraw_sats_str := db.Get_setting("MAX_WITHDRAW_SATS")
- max_withdraw_sats, err := strconv.Atoi(max_withdraw_sats_str)
-
- if err != nil {
- log.Warn(err.Error())
- resp_err.Write(w)
- return
- }
-
- // get pin_enable & pin_limit_sats
-
- c, err := db.Get_card_from_card_id(card_id)
- if err != nil {
- log.WithFields(log.Fields{"card_id": card_id}).Warn(err)
- resp_err.Write(w)
- return
- }
-
- default_description := db.Get_setting("DEFAULT_DESCRIPTION")
-
- response := make(map[string]interface{})
-
- response["tag"] = "withdrawRequest"
- response["callback"] = lnurlw_cb_url
- response["k1"] = lnurlw_k1
- response["defaultDescription"] = default_description
- response["minWithdrawable"] = min_withdraw_sats * 1000 // milliSats
- response["maxWithdrawable"] = max_withdraw_sats * 1000 // milliSats
-
- if c.Pin_enable == "Y" {
- response["pinLimit"] = c.Pin_limit_sats * 1000 // milliSats
- }
-
- jsonData, err := json.Marshal(response)
-
- if err != nil {
- log.Warn(err)
- resp_err.Write(w)
- return
- }
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- w.Write(jsonData)
-}
diff --git a/lnurlw_callback.go b/lnurlw_callback.go
new file mode 100644
index 0000000..0fc43d2
--- /dev/null
+++ b/lnurlw_callback.go
@@ -0,0 +1,142 @@
+package main
+
+import (
+ decodepay "github.com/fiatjaf/ln-decodepay"
+ log "github.com/sirupsen/logrus"
+ "net/http"
+ "os"
+)
+
+func lnurlw_callback(w http.ResponseWriter, req *http.Request) {
+
+ url := req.URL.RequestURI()
+ log.WithFields(log.Fields{"url": url}).Debug("cb request")
+
+ // check k1 value
+ params_k1, ok := req.URL.Query()["k1"]
+
+ if !ok || len(params_k1[0]) < 1 {
+ log.WithFields(log.Fields{"url": url}).Debug("k1 not found")
+ return
+ }
+
+ param_k1 := params_k1[0]
+
+ p, err := db_get_payment_k1(param_k1)
+ if err != nil {
+ log.WithFields(log.Fields{"url": url, "k1": param_k1}).Warn(err)
+ return
+ }
+
+ // check that payment has not been made
+ if p.paid_flag != "N" {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("payment already made")
+ return
+ }
+
+ // check if lnurlw_request has timed out
+ lnurlw_timeout, err := db_check_lnurlw_timeout(p.card_payment_id)
+ if err != nil {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn(err)
+ return
+ }
+ if lnurlw_timeout == true {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("lnurlw request has timed out")
+ return
+ }
+
+ params_pr, ok := req.URL.Query()["pr"]
+ if !ok || len(params_pr[0]) < 1 {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn("pr field not found")
+ return
+ }
+
+ param_pr := params_pr[0]
+ bolt11, _ := decodepay.Decodepay(param_pr)
+
+ // record the lightning invoice
+ err = db_update_payment_invoice(p.card_payment_id, param_pr, bolt11.MSatoshi)
+ if err != nil {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn(err)
+ return
+ }
+
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Debug("checking payment rules")
+
+ // check if we are only sending funds to a defined test node
+ testnode := os.Getenv("LN_TESTNODE")
+ if testnode != "" && bolt11.Payee != testnode {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("rejected as not the defined test node")
+ return
+ }
+
+ // check amount limits
+
+ invoice_sats := int(bolt11.MSatoshi / 1000)
+
+ day_total_sats, err := db_get_card_totals(p.card_id)
+ if err != nil {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn(err)
+ return
+ }
+
+ c, err := db_get_card_from_card_id(p.card_id)
+ if err != nil {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn(err)
+ return
+ }
+
+ if invoice_sats > c.tx_limit_sats {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("invoice_sats: ", invoice_sats)
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("tx_limit_sats: ", c.tx_limit_sats)
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("over tx_limit_sats!")
+ return
+ }
+
+ if day_total_sats+invoice_sats > c.day_limit_sats {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("invoice_sats: ", invoice_sats)
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("day_total_sats: ", day_total_sats)
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("day_limit_sats: ", c.day_limit_sats)
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("over day_limit_sats!")
+ return
+ }
+
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("paying invoice")
+
+ // update paid_flag so we only attempt payment once
+ err = db_update_payment_paid(p.card_payment_id)
+ if err != nil {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn(err)
+ return
+ }
+
+ // https://github.com/fiatjaf/lnurl-rfc/blob/luds/03.md
+ //
+ // LN SERVICE sends a {"status": "OK"} or
+ // {"status": "ERROR", "reason": "error details..."}
+ // JSON response and then attempts to pay the invoices asynchronously.
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ jsonData := []byte(`{"status":"OK"}`)
+ w.Write(jsonData)
+
+ payment_status, failure_reason, err := pay_invoice(param_pr)
+ if err != nil {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn(err)
+ return
+ }
+
+ if failure_reason != "FAILURE_REASON_NONE" {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("payment failure reason : ", failure_reason)
+ }
+
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("payment status : ", payment_status)
+
+ // store result in database
+ err = db_update_payment_status(p.card_payment_id, payment_status, failure_reason)
+ if err != nil {
+ log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn(err)
+ return
+ }
+}
diff --git a/lnurlw_request.go b/lnurlw_request.go
new file mode 100644
index 0000000..2a2283d
--- /dev/null
+++ b/lnurlw_request.go
@@ -0,0 +1,216 @@
+package main
+
+import (
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+ log "github.com/sirupsen/logrus"
+ "net/http"
+ "os"
+ "strconv"
+)
+
+type Response struct {
+ Tag string `json:"tag"`
+ Callback string `json:"callback"`
+ K1 string `json:"k1"`
+ DefaultDescription string `json:"defaultDescription"`
+ MinWithdrawable int `json:"minWithdrawable"`
+ MaxWithdrawable int `json:"maxWithdrawable"`
+}
+
+func get_p_c(req *http.Request, p_name string, c_name string) (p string, c string) {
+
+ params_p, ok := req.URL.Query()[p_name]
+ if !ok || len(params_p[0]) < 1 {
+ return "", ""
+ }
+
+ params_c, ok := req.URL.Query()[c_name]
+ if !ok || len(params_c[0]) < 1 {
+ return "", ""
+ }
+
+ p = params_p[0]
+ c = params_c[0]
+ return
+}
+
+func parse_request(req *http.Request) (int, error) {
+
+ url := req.URL.RequestURI()
+ log.Debug("ln url: ", url)
+
+ param_p, param_c := get_p_c(req, "p", "c")
+
+ ba_p, err := hex.DecodeString(param_p)
+ if err != nil {
+ return 0, errors.New("p parameter not valid hex")
+ }
+
+ ba_c, err := hex.DecodeString(param_c)
+ if err != nil {
+ return 0, errors.New("c parameter not valid hex")
+ }
+
+ if len(ba_p) != 16 {
+ return 0, errors.New("p parameter length not valid")
+ }
+
+ if len(ba_c) != 8 {
+ return 0, errors.New("c parameter length not valid")
+ }
+
+ // decrypt p with aes_decrypt_key
+
+ aes_decrypt_key := os.Getenv("AES_DECRYPT_KEY")
+
+ key_sdm_file_read, err := hex.DecodeString(aes_decrypt_key)
+ if err != nil {
+ return 0, err
+ }
+
+ dec_p, err := crypto_aes_decrypt(key_sdm_file_read, ba_p)
+ if err != nil {
+ return 0, err
+ }
+
+ if dec_p[0] != 0xC7 {
+ return 0, errors.New("decrypted data not starting with 0xC7")
+ }
+
+ uid := dec_p[1:8]
+ ctr := dec_p[8:11]
+
+ ctr_int := uint32(ctr[2])<<16 | uint32(ctr[1])<<8 | uint32(ctr[0])
+
+ // get card record from database for UID
+
+ uid_str := hex.EncodeToString(uid)
+ log.Debug("card UID: ", uid_str)
+
+ c, err := db_get_card_from_uid(uid_str)
+
+ if err != nil {
+ return 0, errors.New("card not found for UID")
+ }
+
+ // check if card is enabled
+
+ if c.enable_flag != "Y" {
+ return 0, errors.New("card enable is not set to Y")
+ }
+
+ // check cmac
+
+ sv2 := make([]byte, 16)
+ sv2[0] = 0x3c
+ sv2[1] = 0xc3
+ sv2[2] = 0x00
+ sv2[3] = 0x01
+ sv2[4] = 0x00
+ sv2[5] = 0x80
+ sv2[6] = uid[0]
+ sv2[7] = uid[1]
+ sv2[8] = uid[2]
+ sv2[9] = uid[3]
+ sv2[10] = uid[4]
+ sv2[11] = uid[5]
+ sv2[12] = uid[6]
+ sv2[13] = ctr[0]
+ sv2[14] = ctr[1]
+ sv2[15] = ctr[2]
+
+ key_sdm_file_read_mac, err := hex.DecodeString(c.aes_cmac)
+ if err != nil {
+ return 0, err
+ }
+
+ cmac_verified, err := crypto_aes_cmac(key_sdm_file_read_mac, sv2, ba_c)
+ if err != nil {
+ return 0, err
+ }
+
+ if cmac_verified == false {
+ return 0, errors.New("CMAC incorrect")
+ }
+
+ // check and update last_counter_value
+
+ counter_ok, err := db_check_and_update_counter(c.card_id, ctr_int)
+ if err != nil {
+ return 0, err
+ }
+ if counter_ok == false {
+ return 0, errors.New("counter not increasing")
+ }
+
+ log.WithFields(log.Fields{"card_id": c.card_id, "counter": ctr_int}).Info("validated")
+
+ return c.card_id, nil
+}
+
+func lnurlw_response(w http.ResponseWriter, req *http.Request) {
+
+ card_id, err := parse_request(req)
+
+ if err != nil {
+ log.Debug(err.Error())
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ jsonData := []byte(`{"status":"ERROR","reason":"bad request"}`)
+ w.Write(jsonData)
+
+ return
+ }
+
+ k1, err := create_k1()
+ if err != nil {
+ log.Warn(err.Error())
+ return
+ }
+
+ // store k1 in database and include in response
+
+ err = db_insert_payment(card_id, k1)
+ if err != nil {
+ log.Warn(err.Error())
+ return
+ }
+
+ host_domain := os.Getenv("HOST_DOMAIN")
+ lnurlw_cb_url := "https://" + host_domain + "/cb"
+
+ min_withdraw_sats_str := os.Getenv("MIN_WITHDRAW_SATS")
+ min_withdraw_sats, err := strconv.Atoi(min_withdraw_sats_str)
+ if err != nil {
+ log.Warn(err.Error())
+ return
+ }
+
+ max_withdraw_sats_str := os.Getenv("MAX_WITHDRAW_SATS")
+ max_withdraw_sats, err := strconv.Atoi(max_withdraw_sats_str)
+ if err != nil {
+ log.Warn(err.Error())
+ return
+ }
+
+ response := Response{}
+ response.Tag = "withdrawRequest"
+ response.Callback = lnurlw_cb_url
+ response.K1 = k1
+ response.DefaultDescription = "WWT withdrawal"
+ response.MinWithdrawable = min_withdraw_sats * 1000 // milliSats
+ response.MaxWithdrawable = max_withdraw_sats * 1000 // milliSats
+
+ jsonData, err := json.Marshal(response)
+ if err != nil {
+ log.Warn(err)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ w.Write(jsonData)
+}
diff --git a/main.go b/main.go
index d4e7148..87852a4 100644
--- a/main.go
+++ b/main.go
@@ -1,85 +1,28 @@
package main
import (
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/internalapi"
- "github.com/boltcard/boltcard/lnurlp"
- "github.com/boltcard/boltcard/lnurlw"
- "github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
"net/http"
- "time"
+ "os"
)
-var router = mux.NewRouter()
-
func main() {
- log_level := db.Get_setting("LOG_LEVEL")
+ log_level := os.Getenv("LOG_LEVEL")
- switch log_level {
- case "DEBUG":
+ if log_level == "DEBUG" {
log.SetLevel(log.DebugLevel)
- log.Info("bolt card service started - debug log level")
- case "PRODUCTION":
- log.Info("bolt card service started - production log level")
- default:
- // log.Fatal calls os.Exit(1) after logging the error
- log.Fatal("error getting a valid LOG_LEVEL setting from the database")
}
log.SetFormatter(&log.JSONFormatter{
DisableHTMLEscape: true,
})
- var external_router = mux.NewRouter()
- var internal_router = mux.NewRouter()
+ mux := http.NewServeMux()
- // external API
+ mux.HandleFunc("/new", new_card_request)
+ mux.HandleFunc("/ln", lnurlw_response)
+ mux.HandleFunc("/cb", lnurlw_callback)
- // ping
- external_router.Path("/ping").Methods("GET").HandlerFunc(external_ping)
- // createboltcard
- external_router.Path("/new").Methods("GET").HandlerFunc(new_card_request)
- // lnurlw for pos
- external_router.Path("/ln").Methods("GET").HandlerFunc(lnurlw.Response)
- external_router.Path("/cb").Methods("GET").HandlerFunc(lnurlw.Callback)
- // lnurlp for lightning address
- external_router.Path("/.well-known/lnurlp/{name}").Methods("GET").HandlerFunc(lnurlp.Response)
- external_router.Path("/lnurlp/{name}").Methods("GET").HandlerFunc(lnurlp.Callback)
-
- // internal API
- // this has no authentication and is not to be exposed publicly
- // it exists for use on a private virtual network within a docker container
-
- internal_router.Path("/ping").Methods("GET").HandlerFunc(internalapi.Internal_ping)
- internal_router.Path("/createboltcard").Methods("GET").HandlerFunc(internalapi.Createboltcard)
- internal_router.Path("/createboltcardwithpin").Methods("GET").HandlerFunc(internalapi.Createboltcardwithpin)
- internal_router.Path("/updateboltcard").Methods("GET").HandlerFunc(internalapi.Updateboltcard)
- internal_router.Path("/updateboltcardwithpin").Methods("GET").HandlerFunc(internalapi.Updateboltcardwithpin)
- internal_router.Path("/wipeboltcard").Methods("GET").HandlerFunc(internalapi.Wipeboltcard)
- internal_router.Path("/getboltcard").Methods("GET").HandlerFunc(internalapi.Getboltcard)
-
- port := db.Get_setting("HOST_PORT")
- if port == "" {
- port = "9000"
- }
-
- external_server := &http.Server{
- Handler: external_router,
- Addr: ":" + port, // consider adding host
- WriteTimeout: 30 * time.Second,
- ReadTimeout: 30 * time.Second,
- }
-
- internal_server := &http.Server{
- Handler: internal_router,
- Addr: ":9001",
- WriteTimeout: 5 * time.Second,
- ReadTimeout: 5 * time.Second,
- }
-
- go external_server.ListenAndServe()
- go internal_server.ListenAndServe()
-
- select {}
+ err := http.ListenAndServe(":9000", mux)
+ log.Fatal(err)
}
diff --git a/new_card_request.go b/new_card_request.go
index 1512e4f..3190714 100644
--- a/new_card_request.go
+++ b/new_card_request.go
@@ -1,45 +1,16 @@
package main
import (
- "database/sql"
"encoding/json"
- "net/http"
-
- "github.com/boltcard/boltcard/db"
- "github.com/boltcard/boltcard/resp_err"
log "github.com/sirupsen/logrus"
+ "net/http"
+ "os"
)
-/**
- * @api {get} /new/:a Request information to create a new bolt card
- * @apiName NewBoltCard
- * @apiGroup BoltCardService
- *
- * @apiParam {String} a one time authentication code
- *
- * @apiSuccess {String} protocol_name name of the protocol message
- * @apiSuccess {Int} protocol_version version of the protocol message
- * @apiSuccess {String} card_name user friendly card name
- * @apiSuccess {String} lnurlw_base base for creating the lnurlw on the card
- * @apiSuccess {String} k0 Key 0 - authorisation key
- * @apiSuccess {String} k1 Key 1 - decryption key
- * @apiSuccess {String} k2 Key 2 - authentication key
- * @apiSuccess {String} k3 Key 3 - NXP documents say this must be set
- * @apiSuccess {String} k4 Key 4 - NXP documents say this must be set
- * @apiSuccess {String} uid_privacy - set up the card for the UID to be private
- */
-
type NewCardResponse struct {
- PROTOCOL_NAME string `json:"protocol_name"`
- PROTOCOL_VERSION int `json:"protocol_version"`
- CARD_NAME string `json:"card_name"`
- LNURLW_BASE string `json:"lnurlw_base"`
- K0 string `json:"k0"`
- K1 string `json:"k1"`
- K2 string `json:"k2"`
- K3 string `json:"k3"`
- K4 string `json:"k4"`
- UID_PRIVACY string `json:"uid_privacy"`
+ K0 string `json:"k0"`
+ K1 string `json:"k1"`
+ K2 string `json:"k2"`
}
func new_card_request(w http.ResponseWriter, req *http.Request) {
@@ -50,54 +21,47 @@ func new_card_request(w http.ResponseWriter, req *http.Request) {
params_a, ok := req.URL.Query()["a"]
if !ok || len(params_a[0]) < 1 {
log.Debug("a not found")
- resp_err.Write(w)
return
}
a := params_a[0]
- hostdomainPort := db.Get_setting("HOST_DOMAIN_PORT")
- hostdomainsuffix := ""
- if hostdomainPort != "" {
- hostdomainsuffix = ":" + hostdomainPort
- }
- lnurlw_base := "lnurlw://" + db.Get_setting("HOST_DOMAIN") + hostdomainsuffix + "/ln"
+ if a == "00000000000000000000000000000000" {
+ response := NewCardResponse{}
+ response.K0 = "11111111111111111111111111111111"
+ response.K1 = "22222222222222222222222222222222"
+ response.K2 = "33333333333333333333333333333333"
+ log.Debug("special a = 0...0")
- c, err := db.Get_new_card(a)
+ jsonData, err := json.Marshal(response)
+ if err != nil {
+ log.Warn(err)
+ return
+ }
- if err == sql.ErrNoRows {
- log.Debug(err)
- resp_err.Write_message(w, "one time code was used or card was wiped or card does not exist")
- return
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ w.Write(jsonData)
+
+ return;
}
+ c, err := db_get_new_card(a)
if err != nil {
log.Warn(err)
- resp_err.Write(w)
return
}
- k1_decrypt_key := db.Get_setting("AES_DECRYPT_KEY")
+ aes_decrypt_key := os.Getenv("AES_DECRYPT_KEY")
response := NewCardResponse{}
- response.PROTOCOL_NAME = "create_bolt_card_response"
- response.PROTOCOL_VERSION = 2
- response.CARD_NAME = c.Card_name
- response.LNURLW_BASE = lnurlw_base
- response.K0 = c.K0_auth_key
- response.K1 = k1_decrypt_key
- response.K2 = c.K2_cmac_key
- response.K3 = c.K3
- response.K4 = c.K4
- response.UID_PRIVACY = c.Uid_privacy
+ response.K0 = c.lock_key
+ response.K1 = aes_decrypt_key
+ response.K2 = c.aes_cmac
- log.SetFormatter(&log.JSONFormatter{
- DisableHTMLEscape: true,
- })
jsonData, err := json.Marshal(response)
if err != nil {
log.Warn(err)
- resp_err.Write(w)
return
}
diff --git a/ping.go b/ping.go
deleted file mode 100644
index 0119b7a..0000000
--- a/ping.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package main
-
-import (
- "net/http"
-)
-
-func external_ping(w http.ResponseWriter, req *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- jsonData := []byte(`{"status":"OK","pong":"external API"}`)
- w.Write(jsonData)
-}
diff --git a/resp_err/resp_err.go b/resp_err/resp_err.go
deleted file mode 100644
index 951dab7..0000000
--- a/resp_err/resp_err.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package resp_err
-
-import (
- "net/http"
-)
-
-func Write(w http.ResponseWriter) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- jsonData := []byte(`{"status":"ERROR","reason":"bad request"}`)
- w.Write(jsonData)
-}
-
-func Write_message(w http.ResponseWriter, message string) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- jsonData := []byte(`{"status":"ERROR","reason":"` + message + `"}`)
- w.Write(jsonData)
-}
diff --git a/script/s_build b/s_build
similarity index 61%
rename from script/s_build
rename to s_build
index 48e26fe..c814186 100755
--- a/script/s_build
+++ b/s_build
@@ -1,5 +1,4 @@
go build
-sudo cp boltcard.service /etc/systemd/system/boltcard.service
sudo systemctl daemon-reload
sudo systemctl stop boltcard
sudo systemctl start boltcard
diff --git a/script/s_setup_test_data b/s_create_db
similarity index 60%
rename from script/s_setup_test_data
rename to s_create_db
index 7426df8..fadfa94 100755
--- a/script/s_setup_test_data
+++ b/s_create_db
@@ -2,5 +2,5 @@
sudo systemctl stop postgresql
sudo systemctl start postgresql
-psql postgres -f sql/data.test.sql
-echo Test data added
+psql postgres -f create_db.sql
+psql postgres -f add_card_data.sql
diff --git a/script/s_launch b/s_launch
similarity index 100%
rename from script/s_launch
rename to s_launch
diff --git a/script/s_restart b/s_restart
similarity index 100%
rename from script/s_restart
rename to s_restart
diff --git a/script/s_create_db b/script/s_create_db
deleted file mode 100755
index aecb7b6..0000000
--- a/script/s_create_db
+++ /dev/null
@@ -1,23 +0,0 @@
-# to close any database connections
-sudo systemctl stop postgresql
-sudo systemctl start postgresql
-
-echo If you have previously created the database
-echo then this will delete it and recreate it.
-echo
-echo Key values for cards may be in the database data.
-echo
-echo Continue? "(y or n)"
-
-read x
-
-if [ "$x" = "y" ]; then
- psql postgres -f sql/create_db_init.sql
- psql postgres -f sql/create_db.sql
- psql postgres -f sql/create_db_user.sql
- psql postgres -f sql/settings.sql.secret
- echo Database created
-else
- echo No action
-fi
-
diff --git a/sql/create_db.sql b/sql/create_db.sql
deleted file mode 100644
index 9cd6135..0000000
--- a/sql/create_db.sql
+++ /dev/null
@@ -1,71 +0,0 @@
-\c card_db;
-
-CREATE TABLE settings (
- setting_id INT GENERATED ALWAYS AS IDENTITY,
- name VARCHAR(30) UNIQUE NOT NULL DEFAULT '',
- value VARCHAR(128) NOT NULL DEFAULT '',
- PRIMARY KEY(setting_id)
-);
-
-CREATE TABLE cards (
- card_id INT GENERATED ALWAYS AS IDENTITY,
- k0_auth_key CHAR(32) NOT NULL,
- k2_cmac_key CHAR(32) NOT NULL,
- k3 CHAR(32) NOT NULL,
- k4 CHAR(32) NOT NULL,
- uid VARCHAR(14) NOT NULL DEFAULT '',
- last_counter_value INTEGER NOT NULL,
- lnurlw_request_timeout_sec INT NOT NULL,
- lnurlw_enable CHAR(1) NOT NULL DEFAULT 'N',
- tx_limit_sats INT NOT NULL,
- day_limit_sats INT NOT NULL,
- lnurlp_enable CHAR(1) NOT NULL DEFAULT 'N',
- card_name VARCHAR(100) NOT NULL,
- email_address VARCHAR(100) DEFAULT '',
- email_enable CHAR(1) NOT NULL DEFAULT 'N',
- uid_privacy CHAR(1) NOT NULL DEFAULT 'N',
- one_time_code CHAR(32) NOT NULL DEFAULT '',
- one_time_code_expiry TIMESTAMPTZ DEFAULT NOW() + INTERVAL '1 DAY',
- one_time_code_used CHAR(1) NOT NULL DEFAULT 'Y',
- allow_negative_balance CHAR(1) NOT NULL DEFAULT 'N',
- pin_enable CHAR(1) NOT NULL DEFAULT 'N',
- pin_number CHAR(4) NOT NULL DEFAULT '0000',
- pin_limit_sats INT NOT NULL DEFAULT 0,
- wiped CHAR(1) NOT NULL DEFAULT 'N',
- PRIMARY KEY(card_id)
-);
-
-CREATE TABLE card_payments (
- card_payment_id INT GENERATED ALWAYS AS IDENTITY,
- card_id INT NOT NULL,
- lnurlw_k1 CHAR(32) UNIQUE NOT NULL,
- lnurlw_request_time TIMESTAMPTZ NOT NULL,
- ln_invoice VARCHAR(1024) NOT NULL DEFAULT '',
- amount_msats BIGINT CHECK (amount_msats > 0),
- paid_flag CHAR(1) NOT NULL,
- payment_time TIMESTAMPTZ,
- payment_status VARCHAR(100) NOT NULL DEFAULT '',
- failure_reason VARCHAR(100) NOT NULL DEFAULT '',
- payment_status_time TIMESTAMPTZ,
- PRIMARY KEY(card_payment_id),
- CONSTRAINT fk_card FOREIGN KEY(card_id) REFERENCES cards(card_id)
-);
-
-CREATE TABLE card_receipts (
- card_receipt_id INT GENERATED ALWAYS AS IDENTITY,
- card_id INT NOT NULL,
- ln_invoice VARCHAR(1024) NOT NULL DEFAULT '',
- r_hash_hex CHAR(64) UNIQUE NOT NULL DEFAULT '',
- amount_msats BIGINT CHECK (amount_msats > 0),
- receipt_status VARCHAR(100) NOT NULL DEFAULT '',
- receipt_status_time TIMESTAMPTZ,
- PRIMARY KEY(card_receipt_id),
- CONSTRAINT fk_card FOREIGN KEY(card_id) REFERENCES cards(card_id)
-);
-
-
-GRANT ALL PRIVILEGES ON TABLE settings TO cardapp;
-GRANT ALL PRIVILEGES ON TABLE cards TO cardapp;
-GRANT ALL PRIVILEGES ON TABLE card_payments TO cardapp;
-GRANT ALL PRIVILEGES ON TABLE card_receipts TO cardapp;
-
diff --git a/sql/create_db_init.sql b/sql/create_db_init.sql
deleted file mode 100644
index 2a65afb..0000000
--- a/sql/create_db_init.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-DROP DATABASE IF EXISTS card_db;
-CREATE DATABASE card_db;
diff --git a/sql/create_db_user.sql b/sql/create_db_user.sql
deleted file mode 100644
index 678c8b1..0000000
--- a/sql/create_db_user.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-DROP USER cardapp;
-CREATE USER cardapp WITH PASSWORD 'database_password';
\ No newline at end of file
diff --git a/sql/data.test.sql b/sql/data.test.sql
deleted file mode 100644
index cae568a..0000000
--- a/sql/data.test.sql
+++ /dev/null
@@ -1,24 +0,0 @@
--- connect to card_db
-\c card_db;
-
--- clear out table data
-DELETE FROM settings;
-DELETE FROM card_payments;
-DELETE FROM card_receipts;
-DELETE FROM cards;
-
--- set up test data
-INSERT INTO settings (name, value) VALUES ('LOG_LEVEL', 'DEBUG');
-INSERT INTO settings (name, value) VALUES ('AES_DECRYPT_KEY', '994de7f8156609a0effafbdb049337b1');
-INSERT INTO settings (name, value) VALUES ('HOST_DOMAIN', 'localhost:9000');
-INSERT INTO settings (name, value) VALUES ('FUNCTION_INTERNAL_API', 'ENABLE');
-INSERT INTO settings (name, value) VALUES ('MIN_WITHDRAW_SATS', '1');
-INSERT INTO settings (name, value) VALUES ('MAX_WITHDRAW_SATS', '1000');
-
-
-INSERT INTO cards
- (k0_auth_key, k2_cmac_key, k3, k4, lnurlw_enable, last_counter_value, lnurlw_request_timeout_sec,
- tx_limit_sats, day_limit_sats, card_name, pin_enable, pin_number, pin_limit_sats)
- VALUES
- ('', 'd3dffa1e12d2477e443a6ee9fcfeab18', '', '', 'Y', 0, 10,
- 0, 0, 'test_card', 'Y', '1234', 1000);
diff --git a/sql/select_db.sql b/sql/select_db.sql
deleted file mode 100644
index 340c842..0000000
--- a/sql/select_db.sql
+++ /dev/null
@@ -1 +0,0 @@
-SELECT 'CREATE DATABASE card_db' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'card_db');
\ No newline at end of file
diff --git a/sql/settings.sql b/sql/settings.sql
deleted file mode 100644
index 810a2bb..0000000
--- a/sql/settings.sql
+++ /dev/null
@@ -1,34 +0,0 @@
-\c card_db;
-
-DELETE FROM settings;
-
--- an explanation for each of the bolt card server settings can be found here
--- https://github.com/boltcard/boltcard/blob/main/docs/SETTINGS.md
-
-INSERT INTO settings (name, value) VALUES ('LOG_LEVEL', '');
-INSERT INTO settings (name, value) VALUES ('AES_DECRYPT_KEY', '');
-INSERT INTO settings (name, value) VALUES ('HOST_DOMAIN', '');
-INSERT INTO settings (name, value) VALUES ('MIN_WITHDRAW_SATS', '');
-INSERT INTO settings (name, value) VALUES ('MAX_WITHDRAW_SATS', '');
-INSERT INTO settings (name, value) VALUES ('LN_HOST', '');
-INSERT INTO settings (name, value) VALUES ('LN_PORT', '');
-INSERT INTO settings (name, value) VALUES ('LN_TLS_FILE', '');
-INSERT INTO settings (name, value) VALUES ('LN_MACAROON_FILE', '');
-INSERT INTO settings (name, value) VALUES ('FEE_LIMIT_SAT', '');
-INSERT INTO settings (name, value) VALUES ('FEE_LIMIT_PERCENT', '');
-INSERT INTO settings (name, value) VALUES ('LN_TESTNODE', '');
-INSERT INTO settings (name, value) VALUES ('FUNCTION_LNURLW', '');
-INSERT INTO settings (name, value) VALUES ('FUNCTION_LNURLP', '');
-INSERT INTO settings (name, value) VALUES ('FUNCTION_EMAIL', '');
-INSERT INTO settings (name, value) VALUES ('DEFAULT_DESCRIPTION', 'bolt card service');
-INSERT INTO settings (name, value) VALUES ('AWS_SES_ID', '');
-INSERT INTO settings (name, value) VALUES ('AWS_SES_SECRET', '');
-INSERT INTO settings (name, value) VALUES ('AWS_SES_EMAIL_FROM', '');
-INSERT INTO settings (name, value) VALUES ('AWS_REGION', 'us-east-1');
-INSERT INTO settings (name, value) VALUES ('EMAIL_MAX_TXS', '');
-INSERT INTO settings (name, value) VALUES ('FUNCTION_LNDHUB', '');
-INSERT INTO settings (name, value) VALUES ('LNDHUB_URL', '');
-INSERT INTO settings (name, value) VALUES ('FUNCTION_INTERNAL_API', '');
-INSERT INTO settings (name, value) VALUES ('SENDGRID_API_KEY', '');
-INSERT INTO settings (name, value) VALUES ('SENDGRID_EMAIL_SENDER', '');
-INSERT INTO settings (name, value) VALUES ('LN_INVOICE_EXPIRY_SEC', '3600');