taldir

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

commit 7441f2098b2a38d09360796eb0c0d9b14a2735ac
parent 40b100e7fcf032622e4c88cea2f3f5d3580d0700
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Tue, 12 Jul 2022 15:34:47 +0200

some linting

Diffstat:
Mgo.mod | 2++
Mpkg/rest/taldir.go | 113++++++++++++++++++++++++++++++++++---------------------------------------------
2 files changed, 51 insertions(+), 64 deletions(-)

diff --git a/go.mod b/go.mod @@ -8,7 +8,9 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/text v0.3.7 + golang.org/x/tools v0.1.11 // indirect gopkg.in/ini.v1 v1.66.4 gorm.io/driver/postgres v1.3.4 gorm.io/gorm v1.23.4 diff --git a/pkg/rest/taldir.go b/pkg/rest/taldir.go @@ -54,6 +54,7 @@ import ( "golang.org/x/text/language" ) +// Taldir is the primary object of the Taldir service type Taldir struct { // The main router @@ -97,6 +98,7 @@ type Taldir struct { MonthlyFee string } +// VersionResponse is the JSON response of the /config enpoint type VersionResponse struct { // libtool-style representation of the Merchant protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning @@ -114,6 +116,7 @@ type VersionResponse struct { } +// Method is part of the VersionResponse and contains a supported validator type Method struct { // Name of the method, e.g. "email" or "sms". @@ -124,6 +127,7 @@ type Method struct { } +// RateLimitedResponse is the JSON response when a rate limit is hit type RateLimitedResponse struct { // Taler error code, TALER_EC_TALDIR_REGISTER_RATE_LIMITED. @@ -136,6 +140,7 @@ type RateLimitedResponse struct { Hint string `json:"hint"` } +// RegisterMessage is the JSON paylaod when a registration is requested type RegisterMessage struct { // Address, in method-specific format @@ -151,14 +156,16 @@ type RegisterMessage struct { Duration int64 `json:"duration"` } +// Order is part of the RegisterMessage payload but optional and as such +// processed separately type Order struct { // Order ID, if the client recently paid for this registration - Id string `json:"order_id"` + ID string `json:"order_id"` } -// A mappind entry from the identity key hash to a wallet key -// The identity key hash is sha256(sha256(identity)|salt) where identity is -// one of the identity key types supported (e.g. email) +// Entry is a mapping from the identity key hash to a wallet key +// The identity key hash is sha512(sha512(address)|salt) where identity is +// one of the identity key types supported (e.g. an email address) type Entry struct { // ORM @@ -177,7 +184,7 @@ type Entry struct { Duration time.Duration `json:"-"` } -// A validation is created when a registration for an entry is initiated. +// Validation is the object created when a registration for an entry is initiated. // The validation stores the identity key (sha256(identity)) the secret // validation reference. The validation reference is sent to the identity // depending on the out-of-band chennel defined through the identity key type. @@ -208,10 +215,11 @@ type Validation struct { LastSolutionTimeframeStart time.Time // The order ID associated with this validation - OrderId string `json:"-"` + OrderID string `json:"-"` } -type ValidationMetadata struct { + +type validationMetadata struct { // ORM gorm.Model `json:"-"` @@ -225,6 +233,7 @@ type ValidationMetadata struct { InitiationCount int } +// ErrorDetail is the detailed error payload returned from Taldir endpoints type ErrorDetail struct { // Numeric error code unique to the condition. @@ -263,6 +272,8 @@ type ErrorDetail struct { TypeActual string `json:"type_actual,omitempty"` } +// ValidationConfirmation is the payload sent by the client t complete a +// registration. type ValidationConfirmation struct { // The solution is the SHA-512 hash of the challenge value // chosen by TalDir (encoded as string just as given in the URL, but @@ -273,10 +284,10 @@ type ValidationConfirmation struct { } // NOTE: Go stores durations as nanoseconds. TalDir usually operates on microseconds -const MONTH_DURATION_US = 2592000000000 +const monthDurationUs = 2592000000000 // 1 Month as Go duration -const MONTH_DURATION = time.Duration(MONTH_DURATION_US * 1000) +const monthDuration = time.Duration(monthDurationUs * 1000) // Primary lookup function. @@ -285,8 +296,8 @@ const MONTH_DURATION = time.Duration(MONTH_DURATION_US * 1000) func (t *Taldir) getSingleEntry(w http.ResponseWriter, r *http.Request){ vars := mux.Vars(r) var entry Entry - hs_address := saltHAddress(vars["h_address"], t.Salt) - var err = t.Db.First(&entry, "hs_address = ?", hs_address).Error + hsAddress := saltHAddress(vars["h_address"], t.Salt) + var err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error if err == nil { w.Header().Set("Content-Type", "application/json") resp, _ := json.Marshal(entry) @@ -298,9 +309,9 @@ func (t *Taldir) getSingleEntry(w http.ResponseWriter, r *http.Request){ // Hashes an identity key (e.g. sha256(<email address>)) with a salt for // Lookup and storage. -func saltHAddress(h_address string, salt string) string { +func saltHAddress(hAddress string, salt string) string { h := sha512.New() - h.Write([]byte(h_address)) + h.Write([]byte(hAddress)) h.Write([]byte(salt)) return util.EncodeBinaryToString(h.Sum(nil)) } @@ -373,9 +384,9 @@ func (t *Taldir) validationRequest(w http.ResponseWriter, r *http.Request){ w.WriteHeader(http.StatusNoContent) } -func (t *Taldir) IsRateLimited(h_address string) (bool, error) { +func (t *Taldir) isRateLimited(hAddress string) (bool, error) { var validationMetadata ValidationMetadata - err := t.Db.First(&validationMetadata, "h_address = ?", h_address).Error + err := t.Db.First(&validationMetadata, "h_address = ?", hAddress).Error // NOTE: Check rate limit if err == nil { // Limit re-initiation attempts @@ -391,7 +402,7 @@ func (t *Taldir) IsRateLimited(h_address string) (bool, error) { } err = t.Db.Save(&validationMetadata).Error } else { - validationMetadata.HAddress = h_address + validationMetadata.HAddress = hAddress validationMetadata.InitiationCount = 1 validationMetadata.TimeframeStart = time.Now() err = t.Db.Create(&validationMetadata).Error @@ -438,13 +449,13 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request){ // exists. h := sha512.New() h.Write([]byte(req.Address)) - h_address := util.EncodeBinaryToString(h.Sum(nil)) - validation.HAddress = h_address - hs_address := saltHAddress(validation.HAddress, t.Salt) - err = t.Db.First(&entry, "hs_address = ?", hs_address).Error + hAddress := util.EncodeBinaryToString(h.Sum(nil)) + validation.HAddress = hAddress + hsAddress := saltHAddress(validation.HAddress, t.Salt) + err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error // Round to the nearest multiple of a month reqDuration := time.Duration(req.Duration * 1000) - reqDuration = reqDuration.Round(MONTH_DURATION) + reqDuration = reqDuration.Round(monthDuration) if err == nil { // Check if this entry is to be modified or extended entryModified := (req.Inbox != entry.Inbox) || @@ -457,11 +468,9 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request){ w.Header().Set("Content-Type", "application/json") w.Write([]byte(fmt.Sprintf("{\"valid_for\": %d}", time.Until(entryValidity).Microseconds()))) return - } else { - // Entry modified or duration extension requested } } - rateLimited, err := t.IsRateLimited(h_address) + rateLimited, err := t.isRateLimited(hAddress) if nil != err { log.Printf("Error checking rate limit! %w", err) w.WriteHeader(http.StatusInternalServerError) @@ -479,7 +488,7 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request){ return } err = t.Db.First(&validation, "h_address = ? AND public_key = ? AND inbox = ? AND duration = ?", - h_address, req.PublicKey, req.Inbox, reqDuration).Error + hAddress, req.PublicKey, req.Inbox, reqDuration).Error validationExists := (nil == err) // FIXME: Always set new challenge? validation.Challenge = util.GenerateChallenge(t.ChallengeBytes) @@ -496,7 +505,7 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request){ cost, currency, err := util.CalculateCost(t.MonthlyFee, fixedCost, sliceDuration, - MONTH_DURATION) //Fixme 1 Month in us + monthDuration) if err != nil { w.WriteHeader(http.StatusInternalServerError) return @@ -504,25 +513,25 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request){ if cost > 0 { if validationExists { - if order.Id != validation.OrderId { + 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 { + if len(validation.OrderID) == 0 { // Add new order for new validations - orderId, newOrderErr := t.Merchant.AddNewOrder(cost, currency) + orderID, newOrderErr := t.Merchant.AddNewOrder(cost, currency) if newOrderErr != nil { w.WriteHeader(http.StatusInternalServerError) return } - validation.OrderId = 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(validation.OrderId) + payto, paytoErr := t.Merchant.IsOrderPaid(validation.OrderID) if paytoErr != nil { w.WriteHeader(http.StatusInternalServerError) log.Println(paytoErr) @@ -574,7 +583,7 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request){ func (t *Taldir) configResponse(w http.ResponseWriter, r *http.Request) { meths := []Method{} i := 0 - for key, _ := range t.Validators { + for key := range t.Validators { var meth Method meth.Name = key meth.ChallengeFee = t.Cfg.Section("taldir-" + key).Key("challenge_fee").MustString("KUDOS:1") @@ -622,34 +631,7 @@ func (t *Taldir) validationPage(w http.ResponseWriter, r *http.Request) { return } -func (t *Taldir) DeleteValidation(addr string) error { - - var validation Validation - h := sha512.New() - h.Write([]byte(addr)) - h_addr := util.EncodeBinaryToString(h.Sum(nil)) - err := t.Db.First(&validation, "h_address = ?", h_addr).Error - if nil == err { - err = t.Db.Delete(&validation).Error - } - return err -} - - -func (t *Taldir) DeleteEntry(addr string) error { - - var entry Entry - h := sha512.New() - h.Write([]byte(addr)) - h_addr := util.EncodeBinaryToString(h.Sum(nil)) - hs_address := saltHAddress(h_addr, t.Salt) - err := t.Db.First(&entry, "hs_address = ?", hs_address).Error - if nil == err { - err = t.Db.Delete(&entry).Error - } - return err -} - +// ClearDatabase nukes the database (for tests) func (t *Taldir) ClearDatabase() { t.Db.Where("1 = 1").Delete(&Entry{}) t.Db.Where("1 = 1").Delete(&Validation{}) @@ -766,6 +748,7 @@ func (t *Taldir) handleRequests() { log.Fatal(http.ListenAndServe(t.Cfg.Section("taldir").Key("bind_to").MustString("localhost:11000"), t.Router)) } +// Initialize the Taldir instance with cfgfile func (t *Taldir) Initialize(cfgfile string) { _cfg, err := ini.Load(cfgfile) if err != nil { @@ -785,8 +768,8 @@ func (t *Taldir) Initialize(cfgfile string) { t.ValidationInitiationMax = t.Cfg.Section("taldir").Key("validation_initiation_max").MustInt(3) t.SolutionAttemptsMax = t.Cfg.Section("taldir").Key("solution_attempt_max").MustInt(3) - validationTtlStr := t.Cfg.Section("taldir").Key("validation_timeframe").MustString("5m") - t.ValidationTimeframe, err = time.ParseDuration(validationTtlStr) + validationTTLStr := t.Cfg.Section("taldir").Key("validation_timeframe").MustString("5m") + t.ValidationTimeframe, err = time.ParseDuration(validationTTLStr) if err != nil { log.Fatal(err) } @@ -844,12 +827,14 @@ func (t *Taldir) Initialize(cfgfile string) { if "" == t.Salt { t.Salt = t.Cfg.Section("taldir").Key("salt").MustString("ChangeMe") } - merchUrl := t.Cfg.Section("taldir").Key("merchant_baseurl_private").MustString("http://merchant.taldir/instances/myInstance") + merchURL := t.Cfg.Section("taldir").Key("merchant_baseurl_private").MustString("http://merchant.taldir/instances/myInstance") merchToken := t.Cfg.Section("taldir").Key("merchant_token").MustString("secretAccessToken") - t.Merchant = taler.NewMerchant(merchUrl, merchToken) + t.Merchant = taler.NewMerchant(merchURL, merchToken) t.setupHandlers() } + +// Run the server and listen for requests func (t *Taldir) Run() { t.handleRequests() }