commit
de14c32867
10 changed files with 163 additions and 43 deletions
46
db/db.go
46
db/db.go
|
|
@ -29,6 +29,9 @@ type Card struct {
|
|||
One_time_code string
|
||||
Card_name string
|
||||
Allow_negative_balance string
|
||||
Pin_enable string
|
||||
Pin_number string
|
||||
Pin_limit_sats int
|
||||
}
|
||||
|
||||
type Payment struct {
|
||||
|
|
@ -350,7 +353,8 @@ func Get_card_from_card_id(card_id int) (*Card, error) {
|
|||
`last_counter_value, lnurlw_request_timeout_sec, ` +
|
||||
`lnurlw_enable, tx_limit_sats, day_limit_sats, ` +
|
||||
`email_enable, email_address, card_name, ` +
|
||||
`allow_negative_balance FROM cards WHERE card_id=$1;`
|
||||
`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,
|
||||
|
|
@ -364,7 +368,10 @@ func Get_card_from_card_id(card_id int) (*Card, error) {
|
|||
&c.Email_enable,
|
||||
&c.Email_address,
|
||||
&c.Card_name,
|
||||
&c.Allow_negative_balance)
|
||||
&c.Allow_negative_balance,
|
||||
&c.Pin_enable,
|
||||
&c.Pin_number,
|
||||
&c.Pin_limit_sats)
|
||||
if err != nil {
|
||||
return &c, err
|
||||
}
|
||||
|
|
@ -385,7 +392,7 @@ func Get_card_from_card_name(card_name string) (*Card, error) {
|
|||
|
||||
sqlStatement := `SELECT card_id, k2_cmac_key, uid,` +
|
||||
` last_counter_value, lnurlw_request_timeout_sec,` +
|
||||
` lnurlw_enable, tx_limit_sats, day_limit_sats` +
|
||||
` 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(
|
||||
|
|
@ -396,7 +403,9 @@ func Get_card_from_card_name(card_name string) (*Card, error) {
|
|||
&c.Lnurlw_request_timeout_sec,
|
||||
&c.Lnurlw_enable,
|
||||
&c.Tx_limit_sats,
|
||||
&c.Day_limit_sats)
|
||||
&c.Day_limit_sats,
|
||||
&c.Pin_enable,
|
||||
&c.Pin_limit_sats)
|
||||
if err != nil {
|
||||
return &c, err
|
||||
}
|
||||
|
|
@ -773,7 +782,7 @@ func Get_card_name_count(card_name string) (card_count int, err error) {
|
|||
|
||||
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 {
|
||||
allow_neg_bal_ptr bool, pin_enable bool, pin_number string, pin_limit_sats int) error {
|
||||
|
||||
lnurlw_enable_yn := "N"
|
||||
if lnurlw_enable {
|
||||
|
|
@ -790,6 +799,11 @@ func Insert_card(one_time_code string, k0_auth_key string, k2_cmac_key string, k
|
|||
allow_neg_bal_yn = "Y"
|
||||
}
|
||||
|
||||
pin_enable_yn := "N"
|
||||
if pin_enable {
|
||||
pin_enable_yn = "Y"
|
||||
}
|
||||
|
||||
db, err := open()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -811,11 +825,12 @@ func Insert_card(one_time_code string, k0_auth_key string, k2_cmac_key string, k
|
|||
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);`
|
||||
` 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)
|
||||
allow_neg_bal_yn, pin_enable_yn, pin_number, pin_limit_sats)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -871,13 +886,19 @@ func Wipe_card(card_name string) (*Card_wipe_info, error) {
|
|||
return &card_wipe_info, nil
|
||||
}
|
||||
|
||||
func Update_card(card_name string, lnurlw_enable bool, tx_limit_sats int, day_limit_sats int) error {
|
||||
func Update_card(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 {
|
||||
|
|
@ -886,10 +907,11 @@ func Update_card(card_name string, lnurlw_enable bool, tx_limit_sats int, day_li
|
|||
|
||||
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';`
|
||||
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)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -83,12 +83,33 @@ func Createboltcard(w http.ResponseWriter, r *http.Request) {
|
|||
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 := "updateboltcard: 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 := "updateboltcard: 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}).Info("createboltcard API request")
|
||||
"allow_neg_bal": allow_neg_bal_flag, "enable_pin": pin_enable_flag,
|
||||
"pin_number": pin_number, "pin_limit_sats": pin_limit_sats}).Info("createboltcard API request")
|
||||
|
||||
// create the keys
|
||||
|
||||
|
|
@ -102,7 +123,7 @@ func Createboltcard(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
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)
|
||||
uid_privacy_flag, allow_neg_bal_flag, pin_enable_flag, pin_number, pin_limit_sats)
|
||||
if err != nil {
|
||||
log.Warn(err.Error())
|
||||
return
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ func Getboltcard(w http.ResponseWriter, r *http.Request) {
|
|||
`"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) + `"}`)
|
||||
`"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)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,26 @@ func Updateboltcard(w http.ResponseWriter, r *http.Request) {
|
|||
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 := "updateboltcard: 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 := "updateboltcard: 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
|
||||
|
|
@ -64,11 +84,12 @@ func Updateboltcard(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
log.WithFields(log.Fields{
|
||||
"card_name": card_name, "tx_max": tx_max, "day_max": day_max,
|
||||
"enable": enable_flag}).Info("updateboltcard API request")
|
||||
"enable": enable_flag, "enable_pin": pin_enable_flag,
|
||||
"pin_number": pin_number, "pin_limit_sats": pin_limit_sats}).Info("updateboltcard API request")
|
||||
|
||||
// update the card record
|
||||
|
||||
err = db.Update_card(card_name, enable_flag, tx_max, day_max)
|
||||
err = db.Update_card(card_name, enable_flag, tx_max, day_max, pin_enable_flag, pin_number, pin_limit_sats)
|
||||
if err != nil {
|
||||
log.Warn(err.Error())
|
||||
return
|
||||
|
|
|
|||
|
|
@ -225,17 +225,15 @@ func 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"]
|
||||
// get k1 value
|
||||
param_k1 := req.URL.Query().Get("k1")
|
||||
|
||||
if !ok || len(params_k1[0]) < 1 {
|
||||
if param_k1 == "" {
|
||||
log.WithFields(log.Fields{"url": url}).Debug("k1 not found")
|
||||
resp_err.Write(w)
|
||||
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)
|
||||
|
|
@ -263,14 +261,14 @@ func Callback(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
params_pr, ok := req.URL.Query()["pr"]
|
||||
if !ok || len(params_pr[0]) < 1 {
|
||||
// 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
|
||||
}
|
||||
|
||||
param_pr := params_pr[0]
|
||||
bolt11, _ := decodepay.Decodepay(param_pr)
|
||||
|
||||
// record the lightning invoice
|
||||
|
|
@ -283,6 +281,23 @@ func Callback(w http.ResponseWriter, req *http.Request) {
|
|||
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -14,15 +14,6 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
type ResponseData struct {
|
||||
Tag string `json:"tag"`
|
||||
Callback string `json:"callback"`
|
||||
LnurlwK1 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]
|
||||
|
|
@ -255,6 +246,7 @@ func parse_request(req *http.Request) (int, error) {
|
|||
func Response(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)
|
||||
|
|
@ -312,15 +304,29 @@ func Response(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
defalut_description := db.Get_setting("DEFAULT_DESCRIPTION")
|
||||
// get pin_enable & pin_limit_sats
|
||||
|
||||
response := ResponseData{}
|
||||
response.Tag = "withdrawRequest"
|
||||
response.Callback = lnurlw_cb_url
|
||||
response.LnurlwK1 = lnurlw_k1
|
||||
response.DefaultDescription = defalut_description
|
||||
response.MinWithdrawable = min_withdraw_sats * 1000 // milliSats
|
||||
response.MaxWithdrawable = max_withdraw_sats * 1000 // milliSats
|
||||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ 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
|
||||
psql postgres -f sql/settings.sql.secret
|
||||
echo Database created
|
||||
else
|
||||
echo No action
|
||||
|
|
|
|||
6
script/s_setup_test_data
Executable file
6
script/s_setup_test_data
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
# to close any database connections
|
||||
sudo systemctl stop postgresql
|
||||
sudo systemctl start postgresql
|
||||
|
||||
psql postgres -f sql/data.test.sql
|
||||
echo Test data added
|
||||
|
|
@ -28,6 +28,9 @@ CREATE TABLE cards (
|
|||
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,
|
||||
wiped CHAR(1) NOT NULL DEFAULT 'N',
|
||||
PRIMARY KEY(card_id)
|
||||
);
|
||||
|
|
|
|||
24
sql/data.test.sql
Normal file
24
sql/data.test.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
-- 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);
|
||||
Loading…
Add table
Add a link
Reference in a new issue