create db/lnd/email packages

This commit is contained in:
Peter Rounce 2023-02-18 14:14:57 +00:00
parent 6153edd0c3
commit 9545e5bd4e
12 changed files with 255 additions and 736 deletions

View file

@ -1,4 +1,4 @@
package main
package db
import (
"database/sql"
@ -8,45 +8,45 @@ import (
"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
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
}
type payment struct {
card_payment_id int
card_id int
lnurlw_k1 string
paid_flag string
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 Transaction struct {
Card_id int
Tx_id int
Tx_type string
Tx_amount_msats int
Tx_time string
}
func db_open() (*sql.DB, error) {
func open() (*sql.DB, error) {
// get connection string from environment variables
@ -65,11 +65,11 @@ func db_open() (*sql.DB, error) {
return db, nil
}
func db_get_setting(setting_name string) string {
func Get_setting(setting_name string) string {
setting_value := ""
db, err := db_open()
db, err := open()
if err != nil {
return ""
}
@ -86,11 +86,11 @@ func db_get_setting(setting_name string) string {
return setting_value
}
func db_get_new_card(one_time_code string) (*card, error) {
func Get_new_card(one_time_code string) (*Card, error) {
c := card{}
c := Card{}
db, err := db_open()
db, err := open()
if err != nil {
return &c, err
}
@ -101,12 +101,12 @@ func db_get_new_card(one_time_code string) (*card, error) {
` 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)
&c.K0_auth_key,
&c.K2_cmac_key,
&c.K3,
&c.K4,
&c.Card_name,
&c.Uid_privacy)
if err != nil {
return &c, err
}
@ -120,11 +120,11 @@ func db_get_new_card(one_time_code string) (*card, error) {
return &c, nil
}
func db_get_card_count_for_uid(uid string) (int, error) {
func Get_card_count_for_uid(uid string) (int, error) {
card_count := 0
db, err := db_open()
db, err := open()
if err != nil {
return 0, err
}
@ -141,11 +141,11 @@ func db_get_card_count_for_uid(uid string) (int, error) {
return card_count, nil
}
func db_get_card_count_for_name_lnurlp(name string) (int, error) {
func Get_card_count_for_name_lnurlp(name string) (int, error) {
card_count := 0
db, err := db_open()
db, err := open()
if err != nil {
return 0, err
}
@ -162,11 +162,11 @@ func db_get_card_count_for_name_lnurlp(name string) (int, error) {
return card_count, nil
}
func db_get_card_id_for_name(name string) (int, error) {
func Get_card_id_for_name(name string) (int, error) {
card_id := 0
db, err := db_open()
db, err := open()
if err != nil {
return 0, err
}
@ -183,10 +183,10 @@ func db_get_card_id_for_name(name string) (int, error) {
return card_id, nil
}
func db_get_card_id_for_card_payment_id(card_payment_id int) (int, error) {
func Get_card_id_for_card_payment_id(card_payment_id int) (int, error) {
card_id := 0
db, err := db_open()
db, err := open()
if err != nil {
return 0, err
}
@ -203,10 +203,10 @@ func db_get_card_id_for_card_payment_id(card_payment_id int) (int, error) {
return card_id, nil
}
func db_get_card_id_for_r_hash(r_hash string) (int, error) {
func Get_card_id_for_r_hash(r_hash string) (int, error) {
card_id := 0
db, err := db_open()
db, err := open()
if err != nil {
return 0, err
}
@ -223,11 +223,11 @@ func db_get_card_id_for_r_hash(r_hash string) (int, error) {
return card_id, nil
}
func db_get_cards_blank_uid() ([]card, error) {
func Get_cards_blank_uid() ([]Card, error) {
// open the database
db, err := db_open()
db, err := open()
if err != nil {
return nil, err
@ -249,12 +249,12 @@ func db_get_cards_blank_uid() ([]card, error) {
// prepare the results
var cards []card
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)
var c Card
err := rows.Scan(&c.Card_id, &c.K2_cmac_key)
if err != nil {
return cards, err
@ -271,8 +271,8 @@ func db_get_cards_blank_uid() ([]card, error) {
return cards, nil
}
func db_update_card_uid_ctr(card_id int, uid string, ctr uint32) error {
db, err := db_open()
func Update_card_uid_ctr(card_id int, uid string, ctr uint32) error {
db, err := open()
if err != nil {
return err
}
@ -294,11 +294,11 @@ func db_update_card_uid_ctr(card_id int, uid string, ctr uint32) error {
return nil
}
func db_get_card_from_uid(card_uid string) (*card, error) {
func Get_card_from_uid(card_uid string) (*Card, error) {
c := card{}
c := Card{}
db, err := db_open()
db, err := open()
if err != nil {
return &c, err
}
@ -310,14 +310,14 @@ func db_get_card_from_uid(card_uid string) (*card, error) {
` 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)
&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
}
@ -325,11 +325,11 @@ func db_get_card_from_uid(card_uid string) (*card, error) {
return &c, nil
}
func db_get_card_from_card_id(card_id int) (*card, error) {
func Get_card_from_card_id(card_id int) (*Card, error) {
c := card{}
c := Card{}
db, err := db_open()
db, err := open()
if err != nil {
return &c, err
}
@ -342,18 +342,18 @@ func db_get_card_from_card_id(card_id int) (*card, error) {
`allow_negative_balance 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.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)
if err != nil {
return &c, err
}
@ -361,9 +361,9 @@ func db_get_card_from_card_id(card_id int) (*card, error) {
return &c, nil
}
func db_check_lnurlw_timeout(card_payment_id int) (bool, error) {
func Check_lnurlw_timeout(card_payment_id int) (bool, error) {
db, err := db_open()
db, err := open()
if err != nil {
return true, err
}
@ -383,9 +383,9 @@ func db_check_lnurlw_timeout(card_payment_id int) (bool, error) {
return lnurlw_timeout, nil
}
func db_check_and_update_counter(card_id int, new_counter_value uint32) (bool, error) {
func Check_and_update_counter(card_id int, new_counter_value uint32) (bool, error) {
db, err := db_open()
db, err := open()
if err != nil {
return false, err
}
@ -408,9 +408,9 @@ func db_check_and_update_counter(card_id int, new_counter_value uint32) (bool, e
return true, nil
}
func db_insert_payment(card_id int, lnurlw_k1 string) error {
func Insert_payment(card_id int, lnurlw_k1 string) error {
db, err := db_open()
db, err := open()
if err != nil {
return err
}
@ -436,13 +436,13 @@ func db_insert_payment(card_id int, lnurlw_k1 string) error {
return nil
}
func db_insert_receipt(
func Insert_receipt(
card_id int,
ln_invoice string,
r_hash_hex string,
amount_msat int64) error {
db, err := db_open()
db, err := open()
if err != nil {
return err
}
@ -468,8 +468,8 @@ func db_insert_receipt(
return nil
}
func db_update_receipt_state(r_hash_hex string, invoice_state string) error {
db, err := db_open()
func Update_receipt_state(r_hash_hex string, invoice_state string) error {
db, err := open()
if err != nil {
return err
}
@ -493,10 +493,10 @@ func db_update_receipt_state(r_hash_hex string, invoice_state string) error {
return nil
}
func db_get_payment_k1(lnurlw_k1 string) (*payment, error) {
p := payment{}
func Get_payment_k1(lnurlw_k1 string) (*Payment, error) {
p := Payment{}
db, err := db_open()
db, err := open()
if err != nil {
return &p, err
}
@ -506,9 +506,9 @@ func db_get_payment_k1(lnurlw_k1 string) (*payment, error) {
` 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)
&p.Card_payment_id,
&p.Card_id,
&p.Paid_flag)
if err != nil {
return &p, err
}
@ -516,9 +516,9 @@ func db_get_payment_k1(lnurlw_k1 string) (*payment, error) {
return &p, nil
}
func db_update_payment_invoice(card_payment_id int, ln_invoice string, amount_msats int64) error {
func Update_payment_invoice(card_payment_id int, ln_invoice string, amount_msats int64) error {
db, err := db_open()
db, err := open()
if err != nil {
return err
}
@ -540,9 +540,9 @@ func db_update_payment_invoice(card_payment_id int, ln_invoice string, amount_ms
return nil
}
func db_update_payment_paid(card_payment_id int) error {
func Update_payment_paid(card_payment_id int) error {
db, err := db_open()
db, err := open()
if err != nil {
return err
}
@ -564,9 +564,9 @@ func db_update_payment_paid(card_payment_id int) error {
return nil
}
func db_update_payment_status(card_payment_id int, payment_status string, failure_reason string) error {
func Update_payment_status(card_payment_id int, payment_status string, failure_reason string) error {
db, err := db_open()
db, err := open()
if err != nil {
return err
@ -596,9 +596,9 @@ func db_update_payment_status(card_payment_id int, payment_status string, failur
return nil
}
func db_get_card_totals(card_id int) (int, error) {
func Get_card_totals(card_id int) (int, error) {
db, err := db_open()
db, err := open()
if err != nil {
return 0, err
}
@ -620,10 +620,10 @@ func db_get_card_totals(card_id int) (int, error) {
return day_total_sats, nil
}
func db_get_card_txs(card_id int, max_txs int) ([]transaction, error) {
func Get_card_txs(card_id int, max_txs int) ([]Transaction, error) {
// open the database
db, err := db_open()
db, err := open()
if err != nil {
return nil, err
@ -655,12 +655,12 @@ func db_get_card_txs(card_id int, max_txs int) ([]transaction, error) {
// prepare the results
var transactions []transaction
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)
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
@ -677,9 +677,9 @@ func db_get_card_txs(card_id int, max_txs int) ([]transaction, error) {
return transactions, nil
}
func db_get_card_total_sats(card_id int) (int, error) {
func Get_card_total_sats(card_id int) (int, error) {
db, err := db_open()
db, err := open()
if err != nil {
return 0, err
}

View file

@ -1,4 +1,4 @@
package main
package email
import (
"github.com/aws/aws-sdk-go/aws"
@ -9,35 +9,36 @@ import (
log "github.com/sirupsen/logrus"
"strconv"
"strings"
"github.com/boltcard/boltcard/db"
)
func send_balance_email(recipient_email string, card_id int) {
func Send_balance_email(recipient_email string, card_id int) {
c, err := db_get_card_from_card_id(card_id)
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)
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"))
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)
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"
subject := c.Card_name + " balance = " + strconv.Itoa(card_total_sats) + " sats"
// add transactions to the email body
@ -56,9 +57,9 @@ func send_balance_email(recipient_email string, card_id int) {
if i < email_max_txs {
html_body_sb.WriteString(
"<tr>" +
"<td>" + tx.tx_time + "</td>" +
"<td>" + tx.tx_type + "</td>" +
"<td style='text-align:right'>" + strconv.Itoa(tx.tx_amount_msats/1000) + "</td>" +
"<td>" + tx.Tx_time + "</td>" +
"<td>" + tx.Tx_type + "</td>" +
"<td style='text-align:right'>" + strconv.Itoa(tx.Tx_amount_msats/1000) + "</td>" +
"</tr>")
} else {
html_body_sb.WriteString(
@ -69,8 +70,8 @@ func send_balance_email(recipient_email string, card_id int) {
"</tr>")
}
text_body_sb.WriteString(tx.tx_type +
" " + strconv.Itoa(tx.tx_amount_msats/1000))
text_body_sb.WriteString(tx.Tx_type +
" " + strconv.Itoa(tx.Tx_amount_msats/1000))
}
html_body_sb.WriteString("</table></body></html>")
@ -78,7 +79,7 @@ func send_balance_email(recipient_email string, card_id int) {
html_body := html_body_sb.String()
text_body := text_body_sb.String()
send_email(recipient_email,
Send_email(recipient_email,
subject,
html_body,
text_body)
@ -86,11 +87,11 @@ func send_balance_email(recipient_email string, card_id int) {
// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/ses-example-send-email.html
func send_email(recipient string, subject string, htmlBody string, textBody string) {
func Send_email(recipient string, subject string, htmlBody string, textBody string) {
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")
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")
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-east-1"),

20
go.mod
View file

@ -16,9 +16,10 @@ require (
)
require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/aead/siphash v1.0.1 // indirect
github.com/andybalholm/brotli v1.0.4 // 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
@ -26,7 +27,6 @@ require (
github.com/btcsuite/btcd/btcutil/psbt v1.1.6 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect
github.com/btcsuite/btcutil v1.0.2 // 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
@ -44,7 +44,6 @@ require (
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/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // 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
@ -75,10 +74,7 @@ require (
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/juju/loggo v1.0.0 // indirect
github.com/kkdai/bstream v1.0.0 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/pgzip v1.2.5 // 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
@ -89,15 +85,11 @@ require (
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/lncm/lnd-rpc v1.0.2 // indirect
github.com/ltcsuite/ltcd v0.22.1-beta // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mholt/archiver/v3 v3.5.1 // 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/nwaples/rardecode v1.1.3 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // 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
@ -110,7 +102,6 @@ require (
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/ulikunitz/xz v0.5.10 // 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
@ -121,18 +112,12 @@ require (
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 v1.9.0 // 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 v0.20.0 // 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/internal/metric v0.27.0 // indirect
go.opentelemetry.io/otel/metric v0.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.11.1 // indirect
go.opentelemetry.io/otel/sdk/export/metric v0.28.0 // indirect
go.opentelemetry.io/otel/sdk/metric v0.33.0 // 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
@ -146,7 +131,6 @@ require (
golang.org/x/text v0.4.0 // indirect
golang.org/x/time v0.2.0 // indirect
golang.org/x/tools v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/errgo.v1 v1.0.1 // indirect

487
go.sum

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
package main
package lnd
import (
"context"
@ -20,6 +20,9 @@ import (
"google.golang.org/grpc/credentials"
"gopkg.in/macaroon.v2"
"github.com/boltcard/boltcard/db"
"github.com/boltcard/boltcard/email"
)
type rpcCreds map[string]string
@ -72,9 +75,9 @@ func getGrpcConn(hostname string, port int, tlsFile, macaroonFile string) *grpc.
// https://api.lightning.community/?shell#addinvoice
func add_invoice(amount_sat int64, metadata string) (payment_request string, r_hash []byte, return_err error) {
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"))
ln_port, err := strconv.Atoi(db.Get_setting("LN_PORT"))
if err != nil {
return "", nil, err
}
@ -82,10 +85,10 @@ func add_invoice(amount_sat int64, metadata string) (payment_request string, r_h
dh := sha256.Sum256([]byte(metadata))
connection := getGrpcConn(
db_get_setting("LN_HOST"),
db.Get_setting("LN_HOST"),
ln_port,
db_get_setting("LN_TLS_FILE"),
db_get_setting("LN_MACAROON_FILE"))
db.Get_setting("LN_TLS_FILE"),
db.Get_setting("LN_MACAROON_FILE"))
l_client := lnrpc.NewLightningClient(connection)
@ -106,23 +109,23 @@ func add_invoice(amount_sat int64, metadata string) (payment_request string, r_h
// https://api.lightning.community/?shell#subscribesingleinvoice
func monitor_invoice_state(r_hash []byte) {
func Monitor_invoice_state(r_hash []byte) {
// SubscribeSingleInvoice
// get node parameters from environment variables
ln_port, err := strconv.Atoi(db_get_setting("LN_PORT"))
ln_port, err := strconv.Atoi(db.Get_setting("LN_PORT"))
if err != nil {
log.Warn(err)
return
}
connection := getGrpcConn(
db_get_setting("LN_HOST"),
db.Get_setting("LN_HOST"),
ln_port,
db_get_setting("LN_TLS_FILE"),
db_get_setting("LN_MACAROON_FILE"))
db.Get_setting("LN_TLS_FILE"),
db.Get_setting("LN_MACAROON_FILE"))
i_client := invoicesrpc.NewInvoicesClient(connection)
@ -156,14 +159,14 @@ func monitor_invoice_state(r_hash []byte) {
"invoice_state": invoice_state,
}).Info("invoice state updated")
db_update_receipt_state(hex.EncodeToString(r_hash), invoice_state)
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))
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
@ -171,52 +174,52 @@ func monitor_invoice_state(r_hash []byte) {
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)
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" {
if c.Email_enable != "Y" {
log.Debug("email is not enabled for the card")
return
}
go send_balance_email(c.email_address, card_id)
go email.Send_balance_email(c.Email_address, card_id)
return
}
// https://api.lightning.community/?shell#sendpaymentv2
func pay_invoice(card_payment_id int, invoice string) {
func Pay_invoice(card_payment_id int, invoice string) {
// SendPaymentV2
// get node parameters from environment variables
ln_port, err := strconv.Atoi(db_get_setting("LN_PORT"))
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"),
db.Get_setting("LN_HOST"),
ln_port,
db_get_setting("LN_TLS_FILE"),
db_get_setting("LN_MACAROON_FILE"))
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_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_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)
@ -260,7 +263,7 @@ func pay_invoice(card_payment_id int, invoice string) {
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)
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
@ -271,7 +274,7 @@ func pay_invoice(card_payment_id int, invoice string) {
// send email
card_id, err := db_get_card_id_for_card_payment_id(card_payment_id)
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
@ -279,18 +282,18 @@ func pay_invoice(card_payment_id int, invoice string) {
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)
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" {
if c.Email_enable != "Y" {
log.Debug("email is not enabled for the card")
return
}
go send_balance_email(c.email_address, card_id)
go email.Send_balance_email(c.Email_address, card_id)
return
}

View file

@ -6,10 +6,12 @@ import (
log "github.com/sirupsen/logrus"
"net/http"
"strconv"
"github.com/boltcard/boltcard/lnd"
"github.com/boltcard/boltcard/db"
)
func lnurlp_callback(w http.ResponseWriter, r *http.Request) {
if db_get_setting("FUNCTION_LNURLP") != "ENABLE" {
if db.Get_setting("FUNCTION_LNURLP") != "ENABLE" {
log.Debug("LNURLp function is not enabled")
return
}
@ -17,7 +19,7 @@ func lnurlp_callback(w http.ResponseWriter, r *http.Request) {
name := mux.Vars(r)["name"]
amount := r.URL.Query().Get("amount")
card_id, err := db_get_card_id_for_name(name)
card_id, err := db.Get_card_id_for_name(name)
if err != nil {
log.Info("card name not found")
write_error(w)
@ -33,7 +35,7 @@ func lnurlp_callback(w http.ResponseWriter, r *http.Request) {
"req.Host": r.Host,
}).Info("lnurlp_callback")
domain := db_get_setting("HOST_DOMAIN")
domain := db.Get_setting("HOST_DOMAIN")
if r.Host != domain {
log.Warn("wrong host domain")
write_error(w)
@ -50,21 +52,21 @@ func lnurlp_callback(w http.ResponseWriter, r *http.Request) {
amount_sat := amount_msat / 1000
metadata := "[[\"text/identifier\",\"" + name + "@" + domain + "\"],[\"text/plain\",\"bolt card deposit\"]]"
pr, r_hash, err := add_invoice(amount_sat, metadata)
pr, r_hash, err := lnd.Add_invoice(amount_sat, metadata)
if err != nil {
log.Warn("could not add_invoice")
write_error(w)
return
}
err = db_insert_receipt(card_id, pr, hex.EncodeToString(r_hash), amount_msat)
err = db.Insert_receipt(card_id, pr, hex.EncodeToString(r_hash), amount_msat)
if err != nil {
log.Warn(err)
write_error(w)
return
}
go monitor_invoice_state(r_hash)
go lnd.Monitor_invoice_state(r_hash)
log.Debug("sending 'status OK' response")

View file

@ -4,10 +4,11 @@ import (
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
"net/http"
"github.com/boltcard/boltcard/db"
)
func lnurlp_response(w http.ResponseWriter, r *http.Request) {
if db_get_setting("FUNCTION_LNURLP") != "ENABLE" {
if db.Get_setting("FUNCTION_LNURLP") != "ENABLE" {
log.Debug("LNURLp function is not enabled")
return
}
@ -23,7 +24,7 @@ func lnurlp_response(w http.ResponseWriter, r *http.Request) {
// look up domain setting (HOST_DOMAIN)
domain := db_get_setting("HOST_DOMAIN")
domain := db.Get_setting("HOST_DOMAIN")
if r.Host != domain {
log.Warn("wrong host domain")
write_error(w)
@ -32,7 +33,7 @@ func lnurlp_response(w http.ResponseWriter, r *http.Request) {
// look up name in database (table cards, field card_name)
card_count, err := db_get_card_count_for_name_lnurlp(name)
card_count, err := db.Get_card_count_for_name_lnurlp(name)
if err != nil {
log.Warn("could not get card count for name")
write_error(w)

View file

@ -4,11 +4,13 @@ import (
decodepay "github.com/fiatjaf/ln-decodepay"
log "github.com/sirupsen/logrus"
"net/http"
"github.com/boltcard/boltcard/db"
"github.com/boltcard/boltcard/lnd"
)
func lnurlw_callback(w http.ResponseWriter, req *http.Request) {
env_host_domain := db_get_setting("HOST_DOMAIN")
env_host_domain := db.Get_setting("HOST_DOMAIN")
if req.Host != env_host_domain {
log.Warn("wrong host domain")
write_error(w)
@ -29,7 +31,7 @@ func lnurlw_callback(w http.ResponseWriter, req *http.Request) {
param_k1 := params_k1[0]
p, err := db_get_payment_k1(param_k1)
p, err := db.Get_payment_k1(param_k1)
if err != nil {
log.WithFields(log.Fields{"url": url, "k1": param_k1}).Warn(err)
write_error(w)
@ -37,28 +39,28 @@ func lnurlw_callback(w http.ResponseWriter, req *http.Request) {
}
// 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")
if p.Paid_flag != "N" {
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("payment already made")
write_error(w)
return
}
// check if lnurlw_request has timed out
lnurlw_timeout, err := db_check_lnurlw_timeout(p.card_payment_id)
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)
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
write_error(w)
return
}
if lnurlw_timeout == true {
log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("lnurlw request has timed out")
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("lnurlw request has timed out")
write_error(w)
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")
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn("pr field not found")
write_error(w)
return
}
@ -67,19 +69,19 @@ func lnurlw_callback(w http.ResponseWriter, req *http.Request) {
bolt11, _ := decodepay.Decodepay(param_pr)
// record the lightning invoice
err = db_update_payment_invoice(p.card_payment_id, param_pr, bolt11.MSatoshi)
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)
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
write_error(w)
return
}
log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Debug("checking payment rules")
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 := db_get_setting("LN_TESTNODE")
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")
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Info("rejected as not the defined test node")
write_error(w)
return
}
@ -88,33 +90,33 @@ func lnurlw_callback(w http.ResponseWriter, req *http.Request) {
invoice_sats := int(bolt11.MSatoshi / 1000)
day_total_sats, err := db_get_card_totals(p.card_id)
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)
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
write_error(w)
return
}
c, err := db_get_card_from_card_id(p.card_id)
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)
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
write_error(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!")
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!")
write_error(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!")
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!")
write_error(w)
return
}
@ -122,27 +124,27 @@ func lnurlw_callback(w http.ResponseWriter, req *http.Request) {
// 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 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)
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
write_error(w)
return
}
if card_total-invoice_sats < 0 {
log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Warn("not enough balance")
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn("not enough balance")
write_error(w)
return
}
}
log.WithFields(log.Fields{"card_payment_id": p.card_payment_id}).Info("paying invoice")
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)
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)
log.WithFields(log.Fields{"card_payment_id": p.Card_payment_id}).Warn(err)
write_error(w)
return
}
@ -153,7 +155,7 @@ func lnurlw_callback(w http.ResponseWriter, req *http.Request) {
// {"status": "ERROR", "reason": "error details..."}
// JSON response and then attempts to pay the invoices asynchronously.
go pay_invoice(p.card_payment_id, param_pr)
go lnd.Pay_invoice(p.Card_payment_id, param_pr)
log.Debug("sending 'status OK' response")

View file

@ -9,6 +9,7 @@ import (
"os"
"strconv"
"strings"
"github.com/boltcard/boltcard/db"
)
type Response struct {
@ -74,10 +75,10 @@ func setup_card_record(uid string, ctr uint32, uid_bin []byte, ctr_bin []byte, c
// find the card record by matching the cmac
// get possible card records from the database
cards, err := db_get_cards_blank_uid()
cards, err := db.Get_cards_blank_uid()
if err != nil {
return errors.New("db_get_cards_blank_uid errored")
return errors.New("db.Get_cards_blank_uid errored")
}
// check card records for a matching cmac
@ -85,7 +86,7 @@ func setup_card_record(uid string, ctr uint32, uid_bin []byte, ctr_bin []byte, c
for i, card := range cards {
// check the cmac
k2_cmac_key, err := hex.DecodeString(card.k2_cmac_key)
k2_cmac_key, err := hex.DecodeString(card.K2_cmac_key)
if err != nil {
return errors.New("card.k2_cmac_key decode failed")
@ -100,12 +101,12 @@ func setup_card_record(uid string, ctr uint32, uid_bin []byte, ctr_bin []byte, c
if cmac_valid == true {
log.WithFields(log.Fields{
"i": i,
"card.card_id": card.card_id,
"card.k2_cmac_key": card.k2_cmac_key,
"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)
err := db.Update_card_uid_ctr(card.Card_id, uid, ctr)
if err != nil {
return err
@ -150,7 +151,7 @@ func parse_request(req *http.Request) (int, error) {
// decrypt p with aes_decrypt_key
aes_decrypt_key := db_get_setting("AES_DECRYPT_KEY")
aes_decrypt_key := db.Get_setting("AES_DECRYPT_KEY")
key_sdm_file_read, err := hex.DecodeString(aes_decrypt_key)
@ -179,7 +180,7 @@ func parse_request(req *http.Request) (int, error) {
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)
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")
@ -197,7 +198,7 @@ func parse_request(req *http.Request) (int, error) {
// get card record from database for UID
c, err := db_get_card_from_uid(uid_str)
c, err := db.Get_card_from_uid(uid_str)
if err != nil {
return 0, errors.New("card not found for uid")
@ -205,13 +206,13 @@ func parse_request(req *http.Request) (int, error) {
// check if card is enabled
if c.lnurlw_enable != "Y" {
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)
k2_cmac_key, err := hex.DecodeString(c.K2_cmac_key)
if err != nil {
return 0, err
@ -229,7 +230,7 @@ func parse_request(req *http.Request) (int, error) {
// check and update last_counter_value
counter_ok, err := db_check_and_update_counter(c.card_id, ctr_int)
counter_ok, err := db.Check_and_update_counter(c.Card_id, ctr_int)
if err != nil {
return 0, err
@ -239,14 +240,14 @@ func parse_request(req *http.Request) (int, error) {
return 0, errors.New("counter not increasing")
}
log.WithFields(log.Fields{"card_id": c.card_id, "counter": ctr_int}).Info("validated")
log.WithFields(log.Fields{"card_id": c.Card_id, "counter": ctr_int}).Info("validated")
return c.card_id, nil
return c.Card_id, nil
}
func lnurlw_response(w http.ResponseWriter, req *http.Request) {
env_host_domain := db_get_setting("HOST_DOMAIN")
env_host_domain := db.Get_setting("HOST_DOMAIN")
if req.Host != env_host_domain {
log.Warn("wrong host domain")
write_error(w)
@ -271,7 +272,7 @@ func lnurlw_response(w http.ResponseWriter, req *http.Request) {
// store k1 in database and include in response
err = db_insert_payment(card_id, lnurlw_k1)
err = db.Insert_payment(card_id, lnurlw_k1)
if err != nil {
log.Warn(err.Error())
@ -286,7 +287,7 @@ func lnurlw_response(w http.ResponseWriter, req *http.Request) {
lnurlw_cb_url = "https://" + req.Host + "/cb"
}
min_withdraw_sats_str := db_get_setting("MIN_WITHDRAW_SATS")
min_withdraw_sats_str := db.Get_setting("MIN_WITHDRAW_SATS")
min_withdraw_sats, err := strconv.Atoi(min_withdraw_sats_str)
if err != nil {
@ -295,7 +296,7 @@ func lnurlw_response(w http.ResponseWriter, req *http.Request) {
return
}
max_withdraw_sats_str := db_get_setting("MAX_WITHDRAW_SATS")
max_withdraw_sats_str := db.Get_setting("MAX_WITHDRAW_SATS")
max_withdraw_sats, err := strconv.Atoi(max_withdraw_sats_str)
if err != nil {

View file

@ -5,6 +5,7 @@ import (
log "github.com/sirupsen/logrus"
"net/http"
"time"
"github.com/boltcard/boltcard/db"
)
var router = mux.NewRouter()
@ -24,7 +25,7 @@ func write_error_message(w http.ResponseWriter, message string) {
}
func main() {
log_level := db_get_setting("LOG_LEVEL")
log_level := db.Get_setting("LOG_LEVEL")
switch log_level {
case "DEBUG":
@ -50,7 +51,7 @@ func main() {
router.Path("/.well-known/lnurlp/{name}").Methods("GET").HandlerFunc(lnurlp_response)
router.Path("/lnurlp/{name}").Methods("GET").HandlerFunc(lnurlp_callback)
port := db_get_setting("HOST_PORT")
port := db.Get_setting("HOST_PORT")
if port == "" {
port = "9000"
}

View file

@ -5,6 +5,7 @@ import (
"encoding/json"
log "github.com/sirupsen/logrus"
"net/http"
"github.com/boltcard/boltcard/db"
)
/**
@ -55,7 +56,7 @@ func new_card_request(w http.ResponseWriter, req *http.Request) {
lnurlw_base := "lnurlw://" + req.Host + "/ln"
c, err := db_get_new_card(a)
c, err := db.Get_new_card(a)
if err == sql.ErrNoRows {
log.Debug(err)
@ -69,19 +70,19 @@ func new_card_request(w http.ResponseWriter, req *http.Request) {
return
}
k1_decrypt_key := db_get_setting("AES_DECRYPT_KEY")
k1_decrypt_key := db.Get_setting("AES_DECRYPT_KEY")
response := NewCardResponse{}
response.PROTOCOL_NAME = "create_bolt_card_response"
response.PROTOCOL_VERSION = 2
response.CARD_NAME = c.card_name
response.CARD_NAME = c.Card_name
response.LNURLW_BASE = lnurlw_base
response.K0 = c.k0_auth_key
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.K2 = c.K2_cmac_key
response.K3 = c.K3
response.K4 = c.K4
response.UID_PRIVACY = c.Uid_privacy
log.SetFormatter(&log.JSONFormatter{
DisableHTMLEscape: true,

View file

@ -21,3 +21,5 @@ 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 ('EMAIL_MAX_TXS', '');
INSERT INTO settings (name, value) VALUES ('FUNCTION_LNDHUB', '');
INSERT INTO settings (name, value) VALUES ('LNDHUB_URL', '');