[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taldir] branch master updated: improve handling of registrations
From: |
gnunet |
Subject: |
[taler-taldir] branch master updated: improve handling of registrations |
Date: |
Tue, 12 Jul 2022 12:43:29 +0200 |
This is an automated email from the git hooks/post-receive script.
martin-schanzenbach pushed a commit to branch master
in repository taldir.
The following commit(s) were added to refs/heads/master by this push:
new eb21817 improve handling of registrations
eb21817 is described below
commit eb21817b69582e5774a07e2ae306f76b85aefba7
Author: Martin Schanzenbach <schanzen@gnunet.org>
AuthorDate: Tue Jul 12 12:43:26 2022 +0200
improve handling of registrations
---
cmd/taldir-server/main_test.go | 6 +-
pkg/rest/taldir.go | 160 ++++++++++++++++++++++++++++-------------
2 files changed, 113 insertions(+), 53 deletions(-)
diff --git a/cmd/taldir-server/main_test.go b/cmd/taldir-server/main_test.go
index a0dfbd4..4390037 100644
--- a/cmd/taldir-server/main_test.go
+++ b/cmd/taldir-server/main_test.go
@@ -47,12 +47,12 @@ var validRegisterRequest = []byte(`
}
`)
-var validRegisterRequestShort = []byte(`
+var validRegisterRequestUnmodified = []byte(`
{
"address": "abc@test",
"public_key": "000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946A90",
"inbox_url": "myinbox@xyz",
- "duration": 23328000000000
+ "duration": 0
}
`)
@@ -194,7 +194,7 @@ func TestReRegisterRequest(s *testing.T) {
if http.StatusNoContent != response.Code {
s.Errorf("Expected response code %d. Got %d\n", http.StatusNoContent,
response.Code)
}
- req, _ = http.NewRequest("POST", "/register/test",
bytes.NewBuffer(validRegisterRequestShort))
+ req, _ = http.NewRequest("POST", "/register/test",
bytes.NewBuffer(validRegisterRequestUnmodified))
response = executeRequest(req)
if http.StatusOK != response.Code {
diff --git a/pkg/rest/taldir.go b/pkg/rest/taldir.go
index 280664a..95e2c71 100644
--- a/pkg/rest/taldir.go
+++ b/pkg/rest/taldir.go
@@ -203,17 +203,28 @@ type Validation struct {
// Public key of the user to register
PublicKey string `json:"public_key"`
- // When does this validation timeframe begin (for retry calculation)
- TimeframeStart time.Time
-
- // How often was this validation re-initiated
- InitiationCount int
-
// How often was a solution for this validation tried
SolutionAttemptCount int
// The beginning of the last solution timeframe
LastSolutionTimeframeStart time.Time
+
+ // The order ID associated with this validation
+ OrderId string `json:"-"`
+}
+
+type ValidationMetadata struct {
+ // ORM
+ gorm.Model `json:"-"`
+
+ // The hash (SHA512) of the address
+ HAddress string `json:"h_address"`
+
+ // When does this validation timeframe begin (for retry calculation)
+ TimeframeStart time.Time
+
+ // How often was this validation re-initiated for this address
+ InitiationCount int
}
type ErrorDetail struct {
@@ -365,6 +376,34 @@ func (t *Taldir) validationRequest(w http.ResponseWriter,
r *http.Request){
w.WriteHeader(http.StatusNoContent)
}
+func (t *Taldir) IsRateLimited(h_address string) (bool, error) {
+ var validationMetadata ValidationMetadata
+ err := t.Db.First(&validationMetadata, "h_address = ?", h_address).Error
+ // NOTE: Check rate limit
+ if err == nil {
+ // Limit re-initiation attempts
+ validationMetadata.InitiationCount++
+ if
time.Now().Before(validationMetadata.TimeframeStart.Add(t.ValidationTimeframe))
{
+ if validationMetadata.InitiationCount > t.ValidationInitiationMax {
+ return true, nil
+ }
+ } else {
+ log.Println("Validation stale, resetting retry counter")
+ validationMetadata.TimeframeStart = time.Now()
+ validationMetadata.InitiationCount = 1
+ }
+ err = t.Db.Save(&validationMetadata).Error
+ } else {
+ validationMetadata.HAddress = h_address
+ validationMetadata.InitiationCount = 1
+ validationMetadata.TimeframeStart = time.Now()
+ err = t.Db.Create(&validationMetadata).Error
+ }
+ if err != nil {
+ return false, err
+ }
+ return false, nil
+}
func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request){
vars := mux.Vars(r)
@@ -409,59 +448,54 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r
*http.Request){
// Round to the nearest multiple of a month
reqDuration := time.Duration(req.Duration * 1000)
reqDuration = reqDuration.Round(MONTH_DURATION)
- validation.Duration = reqDuration.Microseconds()
if err == nil {
+ // Check if this entry is to be modified or extended
+ entryModified := (req.Inbox != entry.Inbox) ||
+ (req.PublicKey != entry.PublicKey)
log.Println("Entry for this address already exists..")
regAt := time.UnixMicro(entry.RegisteredAt)
entryValidity := regAt.Add(entry.Duration)
- requestedValidity := time.Now().Add(reqDuration)
- log.Printf("Entry valid until: %s , requested until: %s\n", entryValidity,
time.Now().Add(reqDuration))
+ requestedValidity := entryValidity.Add(reqDuration)
+ log.Printf("Entry valid until: %s , requested until: %s\n", entryValidity,
requestedValidity)
// NOTE: The extension must be at least one month
- if requestedValidity.Before(entryValidity.Add(MONTH_DURATION)) {
+ if (reqDuration.Microseconds() == 0) && !entryModified {
+ // Nothing changed. Return validity
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"valid_until\": " + entryValidity.String() + "}"))
return
} else {
- validation.Duration =
entryValidity.Sub(requestedValidity).Round(MONTH_DURATION).Microseconds()
+ // Entry modified or duration extension requested
}
}
- err = t.Db.First(&validation, "h_address = ?", h_address).Error
- validation.Challenge = util.GenerateChallenge(t.ChallengeBytes)
- validation.Inbox = req.Inbox
- validation.PublicKey = req.PublicKey
- validation.SolutionAttemptCount = 0
- validation.LastSolutionTimeframeStart = time.Now()
- if err == nil {
- // Limit re-initiation attempts
- validation.InitiationCount++
- if time.Now().Before(validation.TimeframeStart.Add(t.ValidationTimeframe))
{
- if validation.InitiationCount > t.ValidationInitiationMax {
- w.WriteHeader(429)
- rlResponse := RateLimitedResponse{
- Code: gana.TALDIR_REGISTER_RATE_LIMITED,
- RequestFrequency: t.ValidationTimeframe.Microseconds() /
int64(t.ValidationInitiationMax),
- Hint: "Registration rate limit reached",
- }
- jsonResp, _ := json.Marshal(rlResponse)
- w.Write(jsonResp)
- t.Db.Delete(&validation)
- return
- }
- } else {
- log.Println("Validation stale, resetting retry counter")
- validation.TimeframeStart = time.Now()
- validation.InitiationCount = 1
- }
- err = t.Db.Save(&validation).Error
- } else {
- validation.InitiationCount = 1
- validation.TimeframeStart = time.Now()
- err = t.Db.Create(&validation).Error
- }
- if err != nil {
+ rateLimited, err := t.IsRateLimited(h_address)
+ if nil != err {
+ log.Printf("Error checking rate limit! %w", err)
w.WriteHeader(http.StatusInternalServerError)
return
+ } else if rateLimited {
+ w.WriteHeader(http.StatusTooManyRequests)
+ rlResponse := RateLimitedResponse{
+ Code: gana.TALDIR_REGISTER_RATE_LIMITED,
+ RequestFrequency: t.ValidationTimeframe.Microseconds() /
int64(t.ValidationInitiationMax),
+ Hint: "Registration rate limit reached",
+ }
+ jsonResp, _ := json.Marshal(rlResponse)
+ w.Write(jsonResp)
+ t.Db.Delete(&validation)
+ return
+ }
+ err = t.Db.First(&validation, "h_address = ? AND public_key = ? AND inbox =
? AND duration = ?",
+ h_address, req.PublicKey, req.Inbox,
reqDuration).Error
+ validationExists := (nil == err)
+ // FIXME: Always set new challenge?
+ validation.Challenge = util.GenerateChallenge(t.ChallengeBytes)
+ if !validationExists {
+ validation.Inbox = req.Inbox
+ validation.PublicKey = req.PublicKey
+ validation.SolutionAttemptCount = 0
+ validation.LastSolutionTimeframeStart = time.Now()
+ validation.Duration = reqDuration.Microseconds()
}
fixedCost := t.Cfg.Section("taldir-" +
vars["method"]).Key("challenge_fee").MustString("KUDOS:0")
@@ -477,31 +511,49 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r
*http.Request){
log.Printf("The calculated cost for this registration is: %s:%f for a delta
duration of %f", currency, cost, float64(validation.Duration) /
float64(MONTH_DURATION.Microseconds()))
if cost > 0 {
- // FIXME what if provided order ID and validation order ID differ???
- if len(order.Id) == 0 {
+ if validationExists {
+ if order.Id != validation.OrderId {
+ log.Fatalf("Order ID is not validation ID what to do?")
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ }
+ if len(validation.OrderId) == 0 {
// Add new order for new validations
orderId, newOrderErr := t.Merchant.AddNewOrder(cost, currency)
if newOrderErr != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
- order.Id = orderId
+ validation.OrderId = orderId
}
+
+ // FIXME what if provided order ID and validation order ID differ???
// Check if order paid. FIXME: How to check if this the a correct order??
- payto, paytoErr := t.Merchant.IsOrderPaid(order.Id)
+ payto, paytoErr := t.Merchant.IsOrderPaid(validation.OrderId)
if paytoErr != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Println(paytoErr)
return
}
if len(payto) != 0 {
+ t.Db.Save(&validation)
w.WriteHeader(http.StatusPaymentRequired)
w.Header().Set("Location", payto) // FIXME no idea what to do with this.
return
}
// In this case, this order was paid
}
-
+ if validationExists {
+ err = t.Db.Save(&validation).Error
+ } else {
+ err = t.Db.Create(&validation).Error
+ }
+ if err != nil {
+ log.Println(err)
+ w.WriteHeader(500)
+ return
+ }
log.Println("Address registration request created:", validation)
if !t.Cfg.Section("taldir-" + vars["method"]).HasKey("command") {
@@ -615,6 +667,7 @@ func (t *Taldir) DeleteEntry(addr string) error {
func (t *Taldir) ClearDatabase() {
t.Db.Where("1 = 1").Delete(&Entry{})
t.Db.Where("1 = 1").Delete(&Validation{})
+ t.Db.Where("1 = 1").Delete(&ValidationMetadata{})
}
func (t *Taldir) termsResponse(w http.ResponseWriter, r *http.Request) {
@@ -776,7 +829,14 @@ func (t *Taldir) Initialize(cfgfile string) {
if err := t.Db.AutoMigrate(&Validation{}); err != nil {
panic(err)
}
+ if err := t.Db.AutoMigrate(&ValidationMetadata{}); err != nil {
+ panic(err)
+ }
+
+ // Clean up validations
+ tx := t.Db.Where("created_at < ?", time.Now().AddDate(0, 0,
-1)).Delete(&Validation{})
+ log.Printf("Cleaned up %d stale validations.\n", tx.RowsAffected)
validationLandingTplFile :=
t.Cfg.Section("taldir").Key("validation_landing").MustString("templates/validation_landing.html")
t.ValidationTpl, err = template.ParseFiles(validationLandingTplFile)
if err != nil {
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-taldir] branch master updated: improve handling of registrations,
gnunet <=