commit fbf33892e87b4888cfa5bf1882ada66b19b32cbb
parent dd1dcebaff3dbf676e5e445f79e4db84fd3bd3cc
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date: Mon, 10 Nov 2025 22:46:24 +0100
update with newer api spec
Diffstat:
3 files changed, 103 insertions(+), 73 deletions(-)
diff --git a/internal/gana/taler_signatures.go b/internal/gana/taler_signatures.go
@@ -471,7 +471,7 @@ const (
/**
- * Signature over new key set in key update (Gnu Taler)
+ * Signature for mailbox registration request (Gnu Taler)
*/
- TalerSignaturePurposeMailboxKeysUpdate = 1552
+ TalerSignaturePurposeMailboxRegister = 1552
)
diff --git a/mailbox.conf.example b/mailbox.conf.example
@@ -3,8 +3,9 @@ bind_to = localhost:11000
base_url = https://example.com
production = false
message_body_bytes = 256
-message_response_limit
-message_fee = KUDOS:0
+message_response_limit = 50
+registration_fee = KUDOS:0
+registration_period = 8760h
[mailbox-pq]
host = localhost
diff --git a/pkg/rest/mailbox.go b/pkg/rest/mailbox.go
@@ -108,8 +108,8 @@ type Mailbox struct {
// Base URL
BaseUrl string
- // MessageFee for sending message
- MessageFee *talerutil.Amount
+ // Registration fee for registering mailbox
+ RegistrationFee *talerutil.Amount
// How many messages will a single response
// contain at maximum.
@@ -117,6 +117,12 @@ type Mailbox struct {
// Logger
Logger *log.Logger
+
+ // Currency Spec
+ CurrencySpec talerutil.CurrencySpecification
+
+ // Registration period
+ RegistrationPeriod time.Duration
}
type RelativeTime struct {
@@ -137,9 +143,6 @@ type VersionResponse struct {
// Name of the protocol.
Name string `json:"name"` // "taler-mailbox"
- // fee for one month of registration
- MessageFee string `json:"message_fee"`
-
// Fixed size of message bodies
MessageBodyBytes int64 `json:"message_body_bytes"`
@@ -150,6 +153,15 @@ type VersionResponse struct {
// How many messages will a single response
// contain at maximum.
MessageResponseLimit uint64 `json:"message_response_limit"`
+
+ // How much is the cost of a single
+ // registration period of a mailbox
+ // May be 0 for a free registration.
+ RegistrationFee string `json:"registration_fee"`
+
+ // How long is a registration period
+ // a mailbox
+ RegistrationPeriod int64 `json:"registration_period"`
}
type MailboxMessageKeys struct {
@@ -201,7 +213,6 @@ type KeyUpdateRequest struct {
Signature string `json:"signature"`
}
-
// MessageDeletionRequest is used to request the deletion of already received
// messages from the mailbox.
type MessageDeletionRequest struct {
@@ -254,8 +265,9 @@ func (m *Mailbox) configResponse(w http.ResponseWriter, r *http.Request) {
Name: "taler-mailbox",
MessageBodyBytes: m.MessageBodyBytes,
MessageResponseLimit: m.MessageResponseLimit,
- MessageFee: m.MessageFee.String(),
- DeliveryPeriod: RelativeTime{D_us: uint64(dp.Microseconds())},
+ RegistrationFee: m.RegistrationFee.String(),
+ DeliveryPeriod: RelativeTime{D_us: uint64(dp.Microseconds())},
+ RegistrationPeriod: m.RegistrationPeriod.Microseconds(),
}
w.Header().Set("Content-Type", "application/json")
response, _ := json.Marshal(cfg)
@@ -312,64 +324,8 @@ func (m *Mailbox) sendMessageResponse(w http.ResponseWriter, r *http.Request) {
}
entry.HMailbox = vars["h_mailbox"]
entry.Body = body
- if m.MessageFee.IsZero() {
- m.Db.Save(&entry)
- w.WriteHeader(http.StatusNoContent)
- return
- }
-
- // Check if order exists and was paid already.
- h := sha256.New()
- h.Sum(body)
- orderId := util.Base32CrockfordEncode(h.Sum(nil))
- httpStatus, paymentStatus, payto, paytoErr := m.Merchant.IsOrderPaid(orderId)
- if paytoErr != nil {
- fmt.Println(paytoErr)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- switch httpStatus {
- case http.StatusNotFound:
- // Not found. Create new order.
- var order merchant.CommonOrder
- order.OrderId = orderId
- order.Amount = m.MessageFee.String()
- order.Summary = "Mailbox message dispatch"
- order.MerchantBaseUrl = m.BaseUrl
- _, newOrderErr := m.Merchant.CreateOrder(order)
- if newOrderErr != nil {
- fmt.Println(newOrderErr)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- // Check for order again to get payto.
- _, _, payto, paytoErr = m.Merchant.IsOrderPaid(orderId)
- if paytoErr != nil {
- fmt.Println(paytoErr)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- if payto == "" {
- fmt.Println(paytoErr)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- w.WriteHeader(http.StatusPaymentRequired)
- w.Header().Set("Taler", payto)
- return
- case http.StatusOK:
- // Check if it was actually paid.
- if paymentStatus == "paid" {
- m.Db.Save(&entry)
- w.WriteHeader(http.StatusNoContent)
- return
- }
- w.WriteHeader(http.StatusPaymentRequired)
- if payto != "" {
- w.Header().Set("Taler", payto)
- }
- return
- }
+ m.Db.Save(&entry)
+ w.WriteHeader(http.StatusNoContent)
}
func (m *Mailbox) getKeysResponse(w http.ResponseWriter, r *http.Request) {
@@ -415,6 +371,60 @@ func (m *Mailbox) updateKeysResponse(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
return
}
+ if !m.RegistrationFee.IsZero() {
+
+ // Check if order exists and was paid already.
+ h := sha256.New()
+ h.Sum(pk)
+ orderID := util.Base32CrockfordEncode(h.Sum(nil))
+ httpStatus, paymentStatus, payto, paytoErr := m.Merchant.IsOrderPaid(orderID)
+ if paytoErr != nil {
+ fmt.Println(paytoErr)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ switch httpStatus {
+ case http.StatusNotFound:
+ // Not found. Create new order.
+ var order merchant.CommonOrder
+ order.OrderId = orderID
+ order.Amount = m.RegistrationFee.String()
+ order.Summary = "Mailbox registration"
+ order.MerchantBaseUrl = m.BaseUrl
+ _, newOrderErr := m.Merchant.CreateOrder(order)
+ if newOrderErr != nil {
+ fmt.Println(newOrderErr)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ // Check for order again to get payto.
+ _, _, payto, paytoErr = m.Merchant.IsOrderPaid(orderID)
+ if paytoErr != nil {
+ fmt.Println(paytoErr)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ if payto == "" {
+ fmt.Println(paytoErr)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ w.WriteHeader(http.StatusPaymentRequired)
+ w.Header().Set("Taler", payto)
+ return
+ case http.StatusOK:
+ // Check if it was actually paid.
+ if paymentStatus == "paid" {
+ break
+ }
+ default:
+ w.WriteHeader(http.StatusPaymentRequired)
+ if payto != "" {
+ w.Header().Set("Taler", payto)
+ }
+ return
+ }
+ }
var expNbo [8]byte
var signedMsg [72]byte
binary.BigEndian.PutUint64(expNbo[:], msg.Keys.Expiration.T_s)
@@ -604,13 +614,19 @@ func (m *Mailbox) Initialize(cfg MailboxConfig) {
m.BaseUrl = cfg.Ini.Section("mailbox").Key("base_url").MustString("https://example.com")
m.MessageBodyBytes = cfg.Ini.Section("mailbox").Key("message_body_bytes").MustInt64(256)
m.MessageResponseLimit = cfg.Ini.Section("mailbox").Key("message_response_limit").MustUint64(50)
- // FIXME actual cost
- fee, err := talerutil.ParseAmount(cfg.Ini.Section("mailbox").Key("message_fee").MustString("KUDOS:1"))
+ registrationPeriodStr := cfg.Ini.Section("mailbox").Key("registration_period").MustString("8760h")
+ registrationPeriod, err := time.ParseDuration(registrationPeriodStr)
+ if err != nil {
+ fmt.Printf("Failed to parse duration: %v", err)
+ os.Exit(1)
+ }
+ m.RegistrationPeriod = registrationPeriod
+ fee, err := talerutil.ParseAmount(cfg.Ini.Section("mailbox").Key("registration_fee").MustString("KUDOS:0"))
if err != nil {
fmt.Printf("Failed to parse cost: %v", err)
os.Exit(1)
}
- m.MessageFee = fee
+ m.RegistrationFee = fee
_db, err := gorm.Open(cfg.Db, &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
@@ -626,5 +642,18 @@ func (m *Mailbox) Initialize(cfg MailboxConfig) {
}
m.Merchant = cfg.Merchant
+ if !fee.IsZero() {
+ merchConfig, err := m.Merchant.GetConfig()
+ if err != nil {
+ fmt.Printf("Failed to get merchant config: %v", err)
+ os.Exit(1)
+ }
+ currencySpec, currencySupported := merchConfig.Currencies[fee.Currency]
+ for !currencySupported {
+ fmt.Printf("Currency `%s' not supported by merchant!\n", fee.Currency)
+ os.Exit(1)
+ }
+ m.CurrencySpec = currencySpec
+ }
m.setupHandlers()
}