diff --git a/createboltcard/database.go b/createboltcard/database.go deleted file mode 100644 index e8383d1..0000000 --- a/createboltcard/database.go +++ /dev/null @@ -1,119 +0,0 @@ -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_get_setting(setting_name string) string { - - setting_value := "" - - db, err := db_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 db_get_card_name_count(card_name string) (card_count int, err error) { - - card_count = 0 - - db, err := db_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 db_insert_card(one_time_code string, k0_auth_key string, k2_cmac_key string, k3 string, k4 string, - tx_max_sats int, day_max_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 := db_open() - if err != nil { - return err - } - defer db.Close() - - // 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_max_sats, day_max_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 -} diff --git a/createboltcard/main.go b/createboltcard/main.go deleted file mode 100644 index 8287fcd..0000000 --- a/createboltcard/main.go +++ /dev/null @@ -1,86 +0,0 @@ -package main - -import ( - "crypto/rand" - "encoding/hex" - "flag" - "fmt" - log "github.com/sirupsen/logrus" - qrcode "github.com/skip2/go-qrcode" - "strings" -) - -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() { - - tx_max_ptr := flag.Int("tx_max", 0, "set the maximum satoshis per transaction") - day_max_ptr := flag.Int("day_max", 0, "set the maximum satoshis per 24 hour day") - enable_flag_ptr := flag.Bool("enable", false, "enable the card for payments") - card_name_ptr := flag.String("name", "", "set a name for the card (must be set)") - uid_privacy_ptr := flag.Bool("uid_privacy", false, "select enhanced privacy for the card (cannot undo)") - allow_neg_bal_ptr := flag.Bool("allow_neg_bal", false, "allow the card to have a negative balance") - - flag.Parse() - - if *card_name_ptr == "" { - flag.PrintDefaults() - return - } - - // check if card_name already exists - - card_count, err := db_get_card_name_count(*card_name_ptr) - if err != nil { - log.Warn(err.Error()) - return - } - - if card_count > 0 { - fmt.Println("the card name already exists in the database") - return - } - - // 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_ptr, *day_max_ptr, *enable_flag_ptr, *card_name_ptr, - *uid_privacy_ptr, *allow_neg_bal_ptr) - if err != nil { - log.Warn(err.Error()) - return - } - - // show a QR code on the console for the URI + one_time_code - - hostdomain := db_get_setting("HOST_DOMAIN") - url := "" - if strings.HasSuffix(hostdomain, ".onion") { - url = "http://" + hostdomain + "/new?a=" + one_time_code - } else { - url = "https://" + hostdomain + "/new?a=" + one_time_code - } - - fmt.Println() - fmt.Println(url) - fmt.Println() - q, _ := qrcode.New(url, qrcode.Medium) - fmt.Println(q.ToSmallString(false)) -} diff --git a/db/db.go b/db/db.go index 8a6f3b7..0d8c17a 100644 --- a/db/db.go +++ b/db/db.go @@ -739,7 +739,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_max_sats int, day_max_sats int, lnurlw_enable bool, card_name string, uid_privacy bool, + 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" @@ -771,7 +771,7 @@ func Insert_card(one_time_code string, k0_auth_key string, k2_cmac_key string, k ` 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_max_sats, day_max_sats, lnurlw_enable_yn, card_name, uid_privacy_yn, + tx_limit_sats, day_limit_sats, lnurlw_enable_yn, card_name, uid_privacy_yn, allow_neg_bal_yn) if err != nil { return err diff --git a/docs/CARD_ANDROID.md b/docs/CARD_ANDROID.md index 64ed052..e0858bc 100644 --- a/docs/CARD_ANDROID.md +++ b/docs/CARD_ANDROID.md @@ -37,13 +37,10 @@ export DB_NAME=card_db echo "writing host_domain to env vars" export HOST_DOMAIN=card.yourdomain.com -``` -- enter the `createboltcard` directory -- `$ go build` -- run the creation program - - `./createboltcard` to see options - - `./createboltcard -enable -allow_neg_bal -tx_max=1000 -day_max=10000 -name=card_1` for example -- this will give you a one-time link in text and QR code form + +- use the internal API to create a card +- `$ curl 'localhost:9001/createboltcard?card_name=card_5&enable=false&tx_max=1000&day_max=10000&uid_privacy=true&allow_neg_bal=true'` +- this will give you a one-time link on the app - click `scan QR code` @@ -55,3 +52,14 @@ on the app - 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'` + +### 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/DOCKER_INSTALL.md b/docs/DOCKER_INSTALL.md index af46719..8145361 100644 --- a/docs/DOCKER_INSTALL.md +++ b/docs/DOCKER_INSTALL.md @@ -54,7 +54,7 @@ $ docker logs [OPTIONS] CONTAINER Run `$ docker ps` to list containers and get container names/ids -#### running create bolt card command -- `docker exec boltcard_main createboltcard/createboltcard` to see options -- `docker exec boltcard_main createboltcard/createboltcard -enable -allow_neg_bal -tx_max=1000 -day_max=10000 -name=card_1` for example -- this will give you a one-time link in text and QR code form +#### 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'` +- `docker exec boltcard_main curl 'localhost:9001/wipeboltcard?card_name=card_5'` diff --git a/internalapi/updateboltcard.go b/internalapi/updateboltcard.go index 1df3e67..b754456 100644 --- a/internalapi/updateboltcard.go +++ b/internalapi/updateboltcard.go @@ -16,10 +16,10 @@ func Updateboltcard(w http.ResponseWriter, r *http.Request) { return } - tx_limit_sats_str := r.URL.Query().Get("tx_limit_sats") - tx_limit_sats, err := strconv.Atoi(tx_limit_sats_str) + tx_max_str := r.URL.Query().Get("tx_max") + tx_max, err := strconv.Atoi(tx_max_str) if err != nil { - msg := "updateboltcard: tx_limit_sats is not a valid integer" + msg := "updateboltcard: tx_max is not a valid integer" log.Warn(msg) resp_err.Write_message(w, msg) return @@ -54,12 +54,12 @@ func Updateboltcard(w http.ResponseWriter, r *http.Request) { // log the request log.WithFields(log.Fields{ - "card_name": card_name, "tx_limit_sats": tx_limit_sats, + "card_name": card_name, "tx_max": tx_max, "enable": enable_flag}).Info("updateboltcard API request") // update the card record - err = db.Update_card(card_name, tx_limit_sats, enable_flag) + err = db.Update_card(card_name, tx_max, enable_flag) if err != nil { log.Warn(err.Error()) return diff --git a/script/s_build b/script/s_build index 964d0d9..48e26fe 100755 --- a/script/s_build +++ b/script/s_build @@ -1,8 +1,3 @@ -cd createboltcard -go build -cd ../wipeboltcard -go build -cd .. go build sudo cp boltcard.service /etc/systemd/system/boltcard.service sudo systemctl daemon-reload diff --git a/wipeboltcard/database.go b/wipeboltcard/database.go deleted file mode 100644 index b42e715..0000000 --- a/wipeboltcard/database.go +++ /dev/null @@ -1,118 +0,0 @@ -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_get_setting(setting_name string) string { - - setting_value := "" - - db, err := db_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 db_get_card_name_count(card_name string) (card_count int, err error) { - - card_count = 0 - - db, err := db_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 db_wipe_card(card_name string) (*card_wipe_info, error) { - - card_wipe_info := card_wipe_info{} - - db, err := db_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;` - res, err := db.Exec(sqlStatement, card_name) - if err != nil { - return &card_wipe_info, err - } - count, err := res.RowsAffected() - if err != nil { - return &card_wipe_info, err - } - if count != 1 { - return &card_wipe_info, errors.New("not one card record updated") - } - - // get card keys - - sqlStatement = `SELECT card_id, uid, k0_auth_key, k2_cmac_key, k3, k4` + - ` FROM cards WHERE card_name = $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 = db_get_setting("AES_DECRYPT_KEY") - - return &card_wipe_info, nil -} diff --git a/wipeboltcard/main.go b/wipeboltcard/main.go deleted file mode 100644 index 11858c8..0000000 --- a/wipeboltcard/main.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "flag" - "fmt" - log "github.com/sirupsen/logrus" - qrcode "github.com/skip2/go-qrcode" - "strconv" -) - -type card_wipe_info struct { - id int - k0 string - k1 string - k2 string - k3 string - k4 string - uid string -} - -func main() { - - card_name_ptr := flag.String("name", "", "select the card to be wiped by name") - - flag.Parse() - - if *card_name_ptr == "" { - flag.PrintDefaults() - return - } - - // check if card_name exists - - card_count, err := db_get_card_name_count(*card_name_ptr) - if err != nil { - log.Warn(err.Error()) - return - } - - if card_count == 0 { - fmt.Println("the card name does not exist in the database") - return - } - - // set the card as wiped and disabled, get the keys - - card_wipe_info_values, err := db_wipe_card(*card_name_ptr) - if err != nil { - log.Warn(err.Error()) - return - } - - // show a QR code on the console - - qr := `{` + - `"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` + - `}` - - fmt.Println() - q, _ := qrcode.New(qr, qrcode.Medium) - fmt.Println(q.ToSmallString(false)) -}