gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taldir] 02/03: add additional endpoints


From: gnunet
Subject: [taler-taldir] 02/03: add additional endpoints
Date: Tue, 05 Jul 2022 12:40:45 +0200

This is an automated email from the git hooks/post-receive script.

martin-schanzenbach pushed a commit to branch master
in repository taldir.

commit 93c8da8d359b3ce06fa51d259d3339ccde6e60ee
Author: Martin Schanzenbach <schanzen@gnunet.org>
AuthorDate: Tue Jul 5 11:50:01 2022 +0200

    add additional endpoints
---
 taldir.go | 102 +++++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 65 insertions(+), 37 deletions(-)

diff --git a/taldir.go b/taldir.go
index 387cf33..2b05657 100644
--- a/taldir.go
+++ b/taldir.go
@@ -3,6 +3,7 @@ package main
 import (
   "os"
   "os/exec"
+  "time"
   "fmt"
   "log"
   "net/http"
@@ -12,7 +13,7 @@ import (
   "encoding/base32"
   "math/rand"
   "net/smtp"
-  "crypto/sha256"
+  "crypto/sha512"
   "gorm.io/driver/postgres"
   "gopkg.in/ini.v1"
   "strings"
@@ -50,7 +51,7 @@ type RateLimitedResponse struct {
   Code int `json:"code"`
 
   // At what frequency are new registrations allowed. FIXME: In what?
-  Request_frequency uint `json:"request_frequency"`
+  RequestFrequency int64 `json:"request_frequency"`
 
   // The human readable error message.
   Hint string `json:"hint"`
@@ -68,7 +69,7 @@ type RegisterMessage struct {
   Inbox string `json:"inbox_url"`
 
   // For how long should the registration last
-  Duration uint64 `json:"duration"`
+  Duration int64 `json:"duration"`
 
   // Order ID, if the client recently paid for this registration
   // FIXME: As an optional field, maybe we want to parse this separately
@@ -81,8 +82,10 @@ type RegisterMessage struct {
 // one of the identity key types supported (e.g. email)
 type Entry struct {
   gorm.Model
-  IdentityKeyHash string `json:"identity_key_hash"`
-  TalerWalletKey string `json:"taler_wallet_key"`
+  HAddress string `json:"h_address"`
+  PublicKey string `json:"public_key"`
+  RegisteredAt int64 `json:"valid_until"`
+  Duration int64 `json:"duration"`
 }
 
 // A validation is created when a registration for an entry is initiated.
@@ -95,7 +98,6 @@ type Validation struct {
   Method string `json:"method"`
   ValidationReference string `json:"reference"`
   PublicKey string `json:"public_key"`
-  RetryCount uint
 }
 
 type ErrorDetail struct {
@@ -171,18 +173,18 @@ func sendEmail(recipient string, ref Validation) {
 // Primary lookup function.
 // Allows the caller to query a wallet key using the hash(!) of the
 // identity, e.g. sha256(<email address>)
-/*func returnSingleEntry(w http.ResponseWriter, r *http.Request){
+func getSingleEntry(w http.ResponseWriter, r *http.Request){
   vars := mux.Vars(r)
   var entry Entry
-  identityKeyHash := hashIdentityKey(vars["identity_key"])
-  var err = db.First(&entry, "identity_key_hash = ?", identityKeyHash).Error
+  //identityKeyHash := hashIdentityKey(vars["identity_key"])
+  var err = db.First(&entry, "h_address = ?", vars["h_address"]).Error
   if err == nil {
     w.Header().Set("Content-Type", "application/json")
     json.NewEncoder(w).Encode(entry)
     return
   }
   w.WriteHeader(http.StatusNotFound)
-}*/
+}
 
 // Hashes an identity key (e.g. sha256(<email address>)) with a salt for
 // Lookup and storage.
@@ -192,7 +194,7 @@ func hashIdentityKey(idkey string) string {
     salt = cfg.Section("taldir").Key("salt").MustString("ChangeMe")
   }
   fmt.Println("Using salt " + salt)
-  h := sha256.New()
+  h := sha512.New()
   h.Write([]byte(idkey))
   h.Write([]byte(salt))
   return base32.StdEncoding.EncodeToString(h.Sum(nil))
@@ -200,26 +202,33 @@ func hashIdentityKey(idkey string) string {
 
 // Called by the registrant to validate the registration request. The 
reference ID was
 // provided "out of band" using a validation method such as email or SMS
-/*func validateSingleEntry(w http.ResponseWriter, r *http.Request){
+func validationRequest(w http.ResponseWriter, r *http.Request){
   vars := mux.Vars(r)
   var entry Entry
   var validation Validation
-  var err = db.First(&validation, "validation_reference = ?", 
vars["reference"]).Error
+  err := db.First(&validation, "h_address = ?", vars["h_address"]).Error
   if err != nil {
     w.WriteHeader(http.StatusNotFound)
+    return
   }
-  err = db.First(&validation, "identity_key = ?", validation.IdentityKey).Error
-  if err != nil {
-    w.WriteHeader(http.StatusNotFound)
+  if vars["validation_code"] != validation.ValidationReference {
+    // FIXME how TF do we rate limit here??
+    w.WriteHeader(http.StatusForbidden)
+    return
   }
+  // FIXME: Expire validations somewhere?
   err = db.Delete(&validation).Error
   if err != nil {
     w.WriteHeader(http.StatusInternalServerError)
+    return
   }
-  entry.IdentityKeyHash = hashIdentityKey(validation.IdentityKey)
-  entry.TalerWalletKey = validation.TalerWalletKey
-  err = db.First(&entry, "identity_key_hash = ?", entry.IdentityKeyHash).Error
+  // FIXME are we still doing this??
+  //entry.IdentityKeyHash = hashIdentityKey(validation.IdentityKey)
+  entry.HAddress = validation.HAddress
+  entry.PublicKey = validation.PublicKey
+  err = db.First(&entry, "h_address = ?", entry.HAddress).Error
   if err == nil {
+    // FIXME is this not in theory possible that we find such an entry??
     w.WriteHeader(http.StatusConflict)
     return
   }
@@ -228,8 +237,8 @@ func hashIdentityKey(idkey string) string {
     w.WriteHeader(http.StatusInternalServerError)
     return
   }
-  w.WriteHeader(http.StatusCreated)
-}*/
+  w.WriteHeader(http.StatusNoContent)
+}
 
 
 // Generates random reference token used in the validation flow.
@@ -247,6 +256,7 @@ func registerRequest(w http.ResponseWriter, r 
*http.Request){
   var req RegisterMessage
   var errDetail ErrorDetail
   var validation Validation
+  var entry Entry
   if r.Body == nil {
     http.Error(w, "No request body", 400)
     return
@@ -269,29 +279,42 @@ func registerRequest(w http.ResponseWriter, r 
*http.Request){
     w.Write(resp)
     return
   }
-  // TODO make sure sha256(vars["identity"]) == validation.IdentityKey or 
simply set it?
-  h := sha256.New()
+  h := sha512.New()
   h.Write([]byte(req.Address))
   validation.HAddress = base32.StdEncoding.EncodeToString(h.Sum(nil))
-  err = db.First(&validation, "h_address = ?", validation.HAddress).Error
-  if err == nil {
-    reqFrequency := cfg.Section("taldir").Key("request_frequency").MustUint(1)
-    if validation.RetryCount >= reqFrequency - 1 {
+  // We first try if there is already an entry for this address which
+  // is still valid and the duration is not extended.
+  err = db.First(&entry, "h_address = ?", validation.HAddress).Error
+  if err != nil {
+    lastRegValidity := entry.RegisteredAt + entry.Duration
+    requestedValidity := time.Now().UnixMicro() + req.Duration
+    reqFrequency := 
cfg.Section("taldir").Key("request_frequency").MustInt64(1000)
+    earliestReRegistration := entry.RegisteredAt + reqFrequency
+    // Rate limit re-registrations.
+    if time.Now().UnixMicro() < earliestReRegistration {
       w.WriteHeader(429)
       rlResponse := RateLimitedResponse{
         Code: 23, //FIXME TALER_EC_TALDIR_REGISTER_RATE_LIMITED
-        Request_frequency: reqFrequency,
-        Hint: "Retry maximum reached. Deleting validation",
+        RequestFrequency: reqFrequency,
+        Hint: "Registration rate limit reached",
       }
       jsonResp, _ := json.Marshal(rlResponse)
       w.Write(jsonResp)
-      db.Delete(&validation)
       return
     }
-    validation.RetryCount++
-    validation.ValidationReference = generateToken()
-    db.Save(&validation)
-    fmt.Printf("Retrying validation send\n")
+    // Do not allow re-registrations with shorter duration.
+    if requestedValidity <= lastRegValidity {
+      w.WriteHeader(200)
+      // FIXME how to return how long it is already paid for??
+      return
+    }
+  }
+  err = db.First(&validation, "h_address = ?", validation.HAddress).Error
+  if err == nil {
+    // Validation already pending for this address
+    db.Delete(&validation) // FIXME for debugging only
+    w.WriteHeader(202)
+    return
   } else {
     validation.ValidationReference = generateToken()
     err = db.Create(&validation).Error
@@ -302,21 +325,24 @@ func registerRequest(w http.ResponseWriter, r 
*http.Request){
     }
     fmt.Println("Address registration request created:", validation)
   }
-  w.WriteHeader(202)
   // FIXME: Here we should call the validator shell script with the
   // parsed parameters to initiate the validation.
   if !cfg.Section("taldir-" + vars["method"]).HasKey("command") {
     log.Fatal(err)
-    // FIXME cleanup validation?
+    db.Delete(&validation)
+    w.WriteHeader(500)
     return
   }
   command := cfg.Section("taldir-" + vars["method"]).Key("command").String()
   out, err := exec.Command(command, req.Address, 
validation.ValidationReference).Output()
   if err != nil {
     log.Fatal(err)
+    db.Delete(&validation)
+    w.WriteHeader(500)
+    return
   }
+  w.WriteHeader(202)
   fmt.Printf("Output from method script is %s\n", out)
-  // sendEmail(vars["identity"], validation)
 }
 
 func notImplemented(w http.ResponseWriter, r *http.Request) {
@@ -358,7 +384,9 @@ func handleRequests() {
   /* Registration API */
   //myRouter.HandleFunc("/directory/{identity_key}", 
returnSingleEntry).Methods("GET")
   //myRouter.HandleFunc("/validation/{reference}", 
validateSingleEntry).Methods("GET")
+  myRouter.HandleFunc("/{h_address}", getSingleEntry).Methods("GET")
   myRouter.HandleFunc("/register/{method}", registerRequest).Methods("POST")
+  myRouter.HandleFunc("/register/{h_address}/{validation_code}", 
validationRequest).Methods("GET")
 
   
log.Fatal(http.ListenAndServe(cfg.Section("taldir").Key("bind_to").MustString("localhost:11000"),
 myRouter))
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]