taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

commit 493615f700e38ef7db25b3a0a8a034dc2cc7454d
parent 93c8da8d359b3ce06fa51d259d3339ccde6e60ee
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Tue,  5 Jul 2022 12:40:38 +0200

Enable test runs for registration

Diffstat:
Mtaldir.go | 126+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Atest.sh | 11+++++++++++
Mvalidate_test.sh | 1+
3 files changed, 81 insertions(+), 57 deletions(-)

diff --git a/taldir.go b/taldir.go @@ -12,7 +12,6 @@ import ( "gorm.io/gorm" "encoding/base32" "math/rand" - "net/smtp" "crypto/sha512" "gorm.io/driver/postgres" "gopkg.in/ini.v1" @@ -32,7 +31,7 @@ type VersionResponse struct { Methods []Method `json:"methods"` // fee for one month of registration - Monthly_fee string `json:"monthly_fee"` + MonthlyFee string `json:"monthly_fee"` } @@ -41,7 +40,7 @@ type Method struct { Name string `json:"name"` // per challenge fee - Challenge_fee string `json:"challenge_fee"` + ChallengeFee string `json:"challenge_fee"` } @@ -63,7 +62,7 @@ type RegisterMessage struct { Address string `json:"address"` // Public key of the user to register - Public_key string `json:"public_key"` + PublicKey string `json:"public_key"` // (HTTPS) endpoint URL for the inbox service for this address Inbox string `json:"inbox_url"` @@ -81,11 +80,12 @@ type RegisterMessage struct { // The identity key hash is sha256(sha256(identity)|salt) where identity is // one of the identity key types supported (e.g. email) type Entry struct { - gorm.Model - HAddress string `json:"h_address"` + gorm.Model `json:"-"` + HsAddress string `json:"-"` + Inbox string `json:"inbox_url"` PublicKey string `json:"public_key"` - RegisteredAt int64 `json:"valid_until"` - Duration int64 `json:"duration"` + RegisteredAt int64 `json:"-"` + Duration int64 `json:"-"` } // A validation is created when a registration for an entry is initiated. @@ -93,10 +93,12 @@ type Entry struct { // validation reference. The validation reference is sent to the identity // depending on the out-of-band chennel defined through the identity key type. type Validation struct { - gorm.Model + gorm.Model `json:"-"` HAddress string `json:"h_address"` Method string `json:"method"` - ValidationReference string `json:"reference"` + Duration int64 `json:"duration"` + Inbox string `json:"inbox_url"` + Solution string `json:"solution"` PublicKey string `json:"public_key"` } @@ -132,10 +134,14 @@ type ErrorDetail struct { Currency string `json:"currency,omitempty"` // Expected type (if applicable). - Type_expected string `json:"type_expected,omitempty"` + TypeExpected string `json:"type_expected,omitempty"` // Type that was provided instead (if applicable). - Type_actual string `json:"type_actual,omitempty"` + TypeActual string `json:"type_actual,omitempty"` +} + +type ValidationConfirmation struct { + Solution string `json:"solution"` } // The main DB handle @@ -147,29 +153,6 @@ var cfg *ini.File // Map of supported validators as defined in the configuration var validators map[string]bool -// Send an email for email identities -func sendEmail(recipient string, ref Validation) { - - from := cfg.Section("taldir-email").Key("sender").MustString("taldir@example.com") - to := []string{ - recipient, - } - - smtpHost := "localhost" - smtpPort := "587" - - message := fmt.Sprintf("Please click here to validate your Taldir identity: %s%s", - cfg.Section("taldir").Key("host").MustString("http://localhost"), - ref.ValidationReference) - - err := smtp.SendMail(smtpHost+":"+smtpPort, nil, from, to, []byte(message)) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("Email Sent Successfully!") -} - // Primary lookup function. // Allows the caller to query a wallet key using the hash(!) of the // identity, e.g. sha256(<email address>) @@ -177,10 +160,12 @@ 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, "h_address = ?", vars["h_address"]).Error + hs_address := saltHAddress(vars["h_address"]) + var err = db.First(&entry, "hs_address = ?", hs_address).Error if err == nil { w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(entry) + resp, _ := json.Marshal(entry) + w.Write(resp) return } w.WriteHeader(http.StatusNotFound) @@ -188,14 +173,14 @@ func getSingleEntry(w http.ResponseWriter, r *http.Request){ // Hashes an identity key (e.g. sha256(<email address>)) with a salt for // Lookup and storage. -func hashIdentityKey(idkey string) string { +func saltHAddress(h_address string) string { salt := os.Getenv("TALDIR_SALT") if "" == salt { salt = cfg.Section("taldir").Key("salt").MustString("ChangeMe") } fmt.Println("Using salt " + salt) h := sha512.New() - h.Write([]byte(idkey)) + h.Write([]byte(h_address)) h.Write([]byte(salt)) return base32.StdEncoding.EncodeToString(h.Sum(nil)) } @@ -206,12 +191,27 @@ func validationRequest(w http.ResponseWriter, r *http.Request){ vars := mux.Vars(r) var entry Entry var validation Validation - err := db.First(&validation, "h_address = ?", vars["h_address"]).Error + var confirm ValidationConfirmation + var errDetail ErrorDetail + if r.Body == nil { + http.Error(w, "No request body", 400) + return + } + err := json.NewDecoder(r.Body).Decode(&confirm) + if err != nil { + errDetail.Code = 1006 //TALER_EC_JSON_INVALID + errDetail.Hint = "Unable to parse JSON" + resp, _ := json.Marshal(errDetail) + w.WriteHeader(400) + w.Write(resp) + return + } + err = db.First(&validation, "h_address = ?", vars["h_address"]).Error if err != nil { w.WriteHeader(http.StatusNotFound) return } - if vars["validation_code"] != validation.ValidationReference { + if confirm.Solution != validation.Solution { // FIXME how TF do we rate limit here?? w.WriteHeader(http.StatusForbidden) return @@ -223,19 +223,21 @@ func validationRequest(w http.ResponseWriter, r *http.Request){ return } // FIXME are we still doing this?? - //entry.IdentityKeyHash = hashIdentityKey(validation.IdentityKey) - entry.HAddress = validation.HAddress + entry.HsAddress = saltHAddress(validation.HAddress) + entry.Inbox = validation.Inbox + entry.Duration = validation.Duration + entry.RegisteredAt = time.Now().UnixMicro() entry.PublicKey = validation.PublicKey - err = db.First(&entry, "h_address = ?", entry.HAddress).Error + err = db.First(&entry, "hs_address = ?", entry.HsAddress).Error if err == nil { - // FIXME is this not in theory possible that we find such an entry?? - w.WriteHeader(http.StatusConflict) - return - } - err = db.Create(&entry).Error - if err != nil { - w.WriteHeader(http.StatusInternalServerError) + db.Save(&entry) return + } else { + err = db.Create(&entry).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } } w.WriteHeader(http.StatusNoContent) } @@ -284,7 +286,8 @@ func registerRequest(w http.ResponseWriter, r *http.Request){ validation.HAddress = base32.StdEncoding.EncodeToString(h.Sum(nil)) // 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 + hs_address := saltHAddress(validation.HAddress) + err = db.First(&entry, "hs_address = ?", hs_address).Error if err != nil { lastRegValidity := entry.RegisteredAt + entry.Duration requestedValidity := time.Now().UnixMicro() + req.Duration @@ -316,7 +319,10 @@ func registerRequest(w http.ResponseWriter, r *http.Request){ w.WriteHeader(202) return } else { - validation.ValidationReference = generateToken() + validation.Solution = generateToken() + validation.Inbox = req.Inbox + validation.Duration = req.Duration + validation.PublicKey = req.PublicKey err = db.Create(&validation).Error if err != nil { // FIXME: API needs 400 error codes in such cases @@ -334,7 +340,7 @@ func registerRequest(w http.ResponseWriter, r *http.Request){ return } command := cfg.Section("taldir-" + vars["method"]).Key("command").String() - out, err := exec.Command(command, req.Address, validation.ValidationReference).Output() + out, err := exec.Command(command, req.Address, validation.Solution).Output() if err != nil { log.Fatal(err) db.Delete(&validation) @@ -355,14 +361,14 @@ func configResponse(w http.ResponseWriter, r *http.Request) { for key, _ := range validators { var meth Method meth.Name = key - meth.Challenge_fee = cfg.Section("taldir-" + key).Key("challenge_fee").MustString("1 Kudos") + meth.ChallengeFee = cfg.Section("taldir-" + key).Key("challenge_fee").MustString("1 Kudos") i++ meths = append(meths, meth) } cfg := VersionResponse{ Version: "0:0:0", Name: "taler-directory", - Monthly_fee: cfg.Section("taldir").Key("monthly_fee").MustString("1 Kudos"), + MonthlyFee: cfg.Section("taldir").Key("monthly_fee").MustString("1 Kudos"), Methods: meths, } w.Header().Set("Content-Type", "application/json") @@ -370,6 +376,11 @@ func configResponse(w http.ResponseWriter, r *http.Request) { w.Write(response) } +func validationPage(w http.ResponseWriter, r *http.Request) { + // FIXME provided HTML page here + return +} + func handleRequests() { myRouter := mux.NewRouter().StrictSlash(true) @@ -386,7 +397,8 @@ func handleRequests() { //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") + myRouter.HandleFunc("/register/{h_address}/{validation_code}", validationPage).Methods("GET") + myRouter.HandleFunc("/{h_address}", validationRequest).Methods("POST") log.Fatal(http.ListenAndServe(cfg.Section("taldir").Key("bind_to").MustString("localhost:11000"), myRouter)) } diff --git a/test.sh b/test.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# New request +curl -v localhost:11000/register/test --data '{"address": "abc@test", "public_key": "pkey", "inbox_url": "myinbox@xyz", "duration": 23}' +# Read validation code from tempfile +CODE=`cat validation_code` +H_ADDRESS=`echo -n abc@test | openssl dgst -binary -sha512 | base32 -w0` +echo "Code: $CODE; Address: $H_ADDRESS" +# Validate +curl -v localhost:11000/$H_ADDRESS --data "{\"solution\": \"${CODE}\"}" +# Get mapping +curl -v localhost:11000/$H_ADDRESS diff --git a/validate_test.sh b/validate_test.sh @@ -1,2 +1,3 @@ #!/bin/bash echo $1 $2 +echo $2 > validation_code