taldir

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

commit 8fbc813afb14807dbc62c4c95402f282a8165f07
parent 6de38ffd56734f9877f8f1ea090210b644cf2783
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Wed, 15 Oct 2025 22:37:02 +0200

this renames address to alias and method to alias type as per spec change

Diffstat:
Mcmd/taldir-cli/main.go | 31++++++++++++++++++++++---------
Mcmd/taldir-server/main_test.go | 40++++++++++++++++++++--------------------
Mpkg/taldir/command_validator.go | 6+++---
Mpkg/taldir/db.go | 10++++------
Mpkg/taldir/disseminator_gns.go | 8++++----
Mpkg/taldir/oidc_validator.go | 2+-
Mpkg/taldir/taldir.go | 153++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mpkg/taldir/validator.go | 2+-
Mscripts/validators/taldir-validate-mail | 2+-
Mscripts/validators/taldir-validate-phone | 2+-
Mweb/templates/landing_email.html | 2+-
Mweb/templates/landing_phone.html | 2+-
Mweb/templates/lookup_result.html | 22++++++++++------------
Mweb/templates/validation_landing.html | 8++++----
14 files changed, 150 insertions(+), 140 deletions(-)

diff --git a/cmd/taldir-cli/main.go b/cmd/taldir-cli/main.go @@ -20,6 +20,7 @@ package main import ( "crypto/sha512" + "encoding/binary" "flag" "fmt" "log" @@ -30,12 +31,23 @@ import ( "taler.net/taldir/internal/util" ) -// Generates a link from a challenge and address -func generateLink(host string, addr string, challenge string) string { +// Hashes the alias with its type in a prefix-free fashion +// SHA512(len(atype||alias)||atype||alias) +func HashAlias(atype string, alias string) []byte { h := sha512.New() - h.Write([]byte(addr)) - h_addr := util.Base32CrockfordEncode(h.Sum(nil)) - return host + "/register/" + url.QueryEscape(h_addr) + "/" + url.QueryEscape(challenge) + "?address=" + url.QueryEscape(addr) + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, uint32(len(atype)+len(alias))) + h.Write(b) + h.Write([]byte(atype)) + h.Write([]byte(alias)) + return h.Sum(nil) +} + +// Generates a link from a challenge and alias +func generateLink(host string, alias string, atype string, challenge string) string { + h_alias := HashAlias(atype, alias) + h_alias_s := util.Base32CrockfordEncode(h_alias) + return host + "/register/" + url.QueryEscape(h_alias_s) + "/" + url.QueryEscape(challenge) + "?alias=" + url.QueryEscape(alias) } func main() { @@ -43,7 +55,8 @@ func main() { var linkFlag = flag.Bool("l", false, "Provide a link for activation") var challengeFlag = flag.String("c", "", "Activation challenge") var pubkeyFlag = flag.String("p", "", "Public key") - var addressFlag = flag.String("a", "", "Address") + var aliasFlag = flag.String("a", "", "Alias") + var atypeFlag = flag.String("t", "", "Alias type") flag.Parse() cfgfile := "taldir.conf" _cfg, err := ini.LooseLoad(cfgfile) @@ -61,11 +74,11 @@ func main() { os.Exit(0) } if *linkFlag { - if len(*challengeFlag) == 0 || len(*addressFlag) == 0 { - fmt.Println("You need to provide an activation challenge and an address to generate a link") + if len(*challengeFlag) == 0 || len(*aliasFlag) == 0 || len(*atypeFlag) == 0 { + fmt.Println("You need to provide an activation challenge and an alias to generate a link") os.Exit(1) } - fmt.Println(generateLink(host, *addressFlag, *challengeFlag)) + fmt.Println(generateLink(host, *aliasFlag, *atypeFlag, *challengeFlag)) os.Exit(0) } } diff --git a/cmd/taldir-server/main_test.go b/cmd/taldir-server/main_test.go @@ -42,7 +42,7 @@ var t taldir.Taldir // Note: This duration will be rounded down to 20 Months (= 51840000000000) var validRegisterRequest = []byte(` { - "address": "abc@test", + "alias": "abc@test", "target_uri": "myinbox@xyz", "duration": 53135000000000 } @@ -50,7 +50,7 @@ var validRegisterRequest = []byte(` var validRegisterRequestUnmodified = []byte(` { - "address": "abc@test", + "alias": "abc@test", "target_uri": "myinbox@xyz", "duration": 0 } @@ -146,16 +146,16 @@ func TestMain(m *testing.M) { os.Exit(code) } -func getHAddress(addr string) string { - ha := t.HashAlias("test", addr) +func getHAlias(alias string) string { + ha := t.HashAlias("test", alias) return util.Base32CrockfordEncode(ha) } func TestNoEntry(s *testing.T) { t.ClearDatabase() - h_addr := getHAddress("jdoe@example.com") - req, _ := http.NewRequest("GET", "/"+h_addr, nil) + h_alias := getHAlias("jdoe@example.com") + req, _ := http.NewRequest("GET", "/"+h_alias, nil) response := executeRequest(req) if http.StatusNotFound != response.Code { @@ -186,11 +186,11 @@ func TestRegisterRequest(s *testing.T) { if err != nil { s.Errorf("Error reading validation code file contents!\n") } - h_addr := getHAddress("abc@test") + h_alias := getHAlias("abc@test") trimCode := strings.Trim(string(code), " \r\n") solution := util.GenerateSolution("myinbox@xyz", trimCode) solutionJSON := "{\"solution\": \"" + solution + "\"}" - req, _ = http.NewRequest("POST", "/"+h_addr, bytes.NewBuffer([]byte(solutionJSON))) + req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) response = executeRequest(req) if http.StatusNoContent != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusNoContent, response.Code) @@ -220,9 +220,9 @@ func TestRegisterQRPageRequest(s *testing.T) { if err != nil { s.Errorf("Error reading validation code file contents!\n") } - h_addr := getHAddress("abc@test") + h_alias := getHAlias("abc@test") trimCode := strings.Trim(string(code), " \r\n") - req, _ = http.NewRequest("GET", "/register/"+h_addr+"/"+trimCode+"?address="+"abc@test", nil) + req, _ = http.NewRequest("GET", "/register/"+h_alias+"/"+trimCode+"?alias="+"abc@test", nil) response = executeRequest(req) if http.StatusOK != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, response.Code) @@ -246,11 +246,11 @@ func TestReRegisterRequest(s *testing.T) { if err != nil { s.Errorf("Error reading validation code file contents!\n") } - h_addr := getHAddress("abc@test") + h_alias := getHAlias("abc@test") trimCode := strings.Trim(string(code), " \r\n") solution := util.GenerateSolution("myinbox@xyz", trimCode) solutionJSON := "{\"solution\": \"" + solution + "\"}" - req, _ = http.NewRequest("POST", "/"+h_addr, bytes.NewBuffer([]byte(solutionJSON))) + req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) response = executeRequest(req) if http.StatusNoContent != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusNoContent, response.Code) @@ -303,25 +303,25 @@ func TestSolutionRequestTooMany(s *testing.T) { if http.StatusAccepted != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) } - h_addr := getHAddress("abc@test") + h_alias := getHAlias("abc@test") solution := util.GenerateSolution("myinbox@xyz", "wrongSolution") solutionJSON := "{\"solution\": \"" + solution + "\"}" - req, _ = http.NewRequest("POST", "/"+h_addr, bytes.NewBuffer([]byte(solutionJSON))) + req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) response = executeRequest(req) if http.StatusForbidden != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) } - req, _ = http.NewRequest("POST", "/"+h_addr, bytes.NewBuffer([]byte(solutionJSON))) + req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) response = executeRequest(req) if http.StatusForbidden != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) } - req, _ = http.NewRequest("POST", "/"+h_addr, bytes.NewBuffer([]byte(solutionJSON))) + req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) response = executeRequest(req) if http.StatusForbidden != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) } - req, _ = http.NewRequest("POST", "/"+h_addr, bytes.NewBuffer([]byte(solutionJSON))) + req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) response = executeRequest(req) if http.StatusTooManyRequests != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusTooManyRequests, response.Code) @@ -346,18 +346,18 @@ func TestRegisterRequestWrongTargetUri(s *testing.T) { if err != nil { s.Errorf("Error reading validation code file contents!\n") } - h_addr := getHAddress("abc@test") + h_alias := getHAlias("abc@test") trimCode := strings.Trim(string(code), " \r\n") solution := util.GenerateSolution("myinox@xyz", trimCode) solutionJSON := "{\"solution\": \"" + solution + "\"}" - req, _ = http.NewRequest("POST", "/"+h_addr, bytes.NewBuffer([]byte(solutionJSON))) + req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) response = executeRequest(req) if http.StatusForbidden != response.Code { s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) } } -func TestUnsupportedMethod(s *testing.T) { +func TestUnsupportedAliasType(s *testing.T) { t.ClearDatabase() req, _ := http.NewRequest("POST", "/register/email", bytes.NewBuffer(validRegisterRequest)) diff --git a/pkg/taldir/command_validator.go b/pkg/taldir/command_validator.go @@ -73,14 +73,14 @@ func (t *CommandValidator) IsAliasValid(alias string) (err error) { return } -func (t *CommandValidator) RegistrationStart(topic string, link string, message string, address string, challenge string) (string, error) { +func (t *CommandValidator) RegistrationStart(topic string, link string, message string, alias string, challenge string) (string, error) { path, err := exec.LookPath(t.command) if err != nil { return "", err } - out, err := exec.Command(path, address, challenge, topic, message).Output() + out, err := exec.Command(path, alias, challenge, topic, message).Output() // FIXME logger - fmt.Printf("Executing `%s %s %s %s %s`\n", path, address, challenge, topic, message) + fmt.Printf("Executing `%s %s %s %s %s`\n", path, alias, challenge, topic, message) if err != nil { fmt.Printf("%s, %v\n", out, err) return "", err diff --git a/pkg/taldir/db.go b/pkg/taldir/db.go @@ -23,18 +23,16 @@ import ( "time" ) -// 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) +// Entry is a mapping from the alias hash to a target URI type Entry struct { // ORM gorm.Model `json:"-"` - // The salted hash (SHA512) of the hashed address (h_address) - HsAddress string `json:"-"` + // The salted hash (SHA512) of the hashed alias + HsAlias string `json:"-"` - // Target URI to associate with this address + // Target URI to associate with this alias TargetUri string `json:"target_uri"` // How long the registration lasts in microseconds diff --git a/pkg/taldir/disseminator_gns.go b/pkg/taldir/disseminator_gns.go @@ -35,7 +35,7 @@ func (d *GnsDisseminator) gns_check_is_disseminated(e *Entry) bool { return false } zone := d.config.Ini.Section("taldir-disseminator-gns").Key("zone").MustString("taldir") - out, err := exec.Command(path, "--lookup", e.HsAddress+"."+zone, "--type", "TXT").Output() + out, err := exec.Command(path, "--lookup", e.HsAlias+"."+zone, "--type", "TXT").Output() if err != nil { return false } @@ -51,7 +51,7 @@ func (d *GnsDisseminator) DisseminateStop(e *Entry) error { return fmt.Errorf("path of command not found: %w", err) } zone := d.config.Ini.Section("taldir-disseminator-gns").Key("zone").MustString("taldir") - out, err := exec.Command(path, "--delete", "--public", "--zone", zone, "--type", "TXT", "--name", e.HsAddress, "--value", e.TargetUri).Output() + out, err := exec.Command(path, "--delete", "--public", "--zone", zone, "--type", "TXT", "--name", e.HsAlias, "--value", e.TargetUri).Output() if err != nil { return fmt.Errorf("failed to execute disseminator command: `%s', %w", out, err) } @@ -60,7 +60,7 @@ func (d *GnsDisseminator) DisseminateStop(e *Entry) error { func (d *GnsDisseminator) DisseminateStart(e *Entry) error { if d.gns_check_is_disseminated(e) { - fmt.Printf("`%s' is already being disseminated\n", e.HsAddress) + fmt.Printf("`%s' is already being disseminated\n", e.HsAlias) return nil } path, err := exec.LookPath("gnunet-namestore") @@ -69,7 +69,7 @@ func (d *GnsDisseminator) DisseminateStart(e *Entry) error { } expiration := d.config.Ini.Section("taldir-disseminator-gns").Key("expiration").MustString("1d") zone := d.config.Ini.Section("taldir-disseminator-gns").Key("zone").MustString("taldir") - out, err := exec.Command(path, "--add", "--public", "--expiration", expiration, "--zone", zone, "--type", "TXT", "--name", e.HsAddress, "--value", e.TargetUri).Output() + out, err := exec.Command(path, "--add", "--public", "--expiration", expiration, "--zone", zone, "--type", "TXT", "--name", e.HsAlias, "--value", e.TargetUri).Output() if err != nil { return fmt.Errorf("failed to execute disseminator command: `%s', %w", out, err) } diff --git a/pkg/taldir/oidc_validator.go b/pkg/taldir/oidc_validator.go @@ -81,7 +81,7 @@ func (t *OidcValidator) IsAliasValid(alias string) (err error) { return } -func (t *OidcValidator) RegistrationStart(topic string, link string, message string, address string, challenge string) (string, error) { +func (t *OidcValidator) RegistrationStart(topic string, link string, message string, alias string, challenge string) (string, error) { // FIXME return t.authorizationEndpoint, nil } diff --git a/pkg/taldir/taldir.go b/pkg/taldir/taldir.go @@ -85,7 +85,7 @@ type Taldir struct { // about page AboutPageTpl *template.Template - // The address salt + // The alias salt Salt string // The host base url @@ -138,17 +138,17 @@ type VersionResponse struct { // Name of the protocol. Name string `json:"name"` // "taler-directory" - // Supported registration methods - Methods []Method `json:"methods"` + // Supported alias types + AliasType []AliasType `json:"alias_type"` // fee for one month of registration MonthlyFee string `json:"monthly_fee"` } -// Method is part of the VersionResponse and contains a supported validator -type Method struct { +// AliasType is part of the VersionResponse and contains a supported validator +type AliasType struct { - // Name of the method, e.g. "email" or "sms". + // Name of the alias type, e.g. "email" or "sms". Name string `json:"name"` // per challenge fee @@ -171,10 +171,10 @@ type RateLimitedResponse struct { // RegisterMessage is the JSON paylaod when a registration is requested type RegisterMessage struct { - // Address, in method-specific format - Address string `json:"address"` + // Alias, in type-specific format + Alias string `json:"alias"` - // Target URI to associate with this address + // Target URI to associate with this alias TargetUri string `json:"target_uri"` // For how long should the registration last @@ -190,13 +190,13 @@ type Validation struct { // ORM gorm.Model `json:"-"` - // The hash (SHA512) of the address - HAddress string `json:"h_address"` + // The hash (SHA512) of the alias + HAlias string `json:"h_alias"` // For how long should the registration last Duration int64 `json:"duration"` - // Target URI to associate with this address + // Target URI to associate with this alias TargetUri string `json:"target_uri"` // The activation code sent to the client @@ -281,7 +281,7 @@ func (t *Taldir) isPMSValid(pms string) (err error) { if t.ValidPMSRegex != "" { matched, _ := regexp.MatchString(t.ValidPMSRegex, pms) if !matched { - return fmt.Errorf("payment System Address `%s' invalid", pms) // TODO i18n + return fmt.Errorf("Payment System Address `%s' invalid", pms) // TODO i18n } } return @@ -289,12 +289,12 @@ func (t *Taldir) isPMSValid(pms string) (err error) { // Primary lookup function. // Allows the caller to query a wallet key using the hash(!) of the -// identity, e.g. SHA512(<email address>) +// alias func (t *Taldir) getSingleEntry(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) var entry Entry - hsAddress := saltHAddress(vars["h_address"], t.Salt) - var err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error + hsAlias := saltHAlias(vars["h_alias"], t.Salt) + var err = t.Db.First(&entry, "hs_alias = ?", hsAlias).Error if err == nil { w.Header().Set("Content-Type", "application/json") resp, _ := json.Marshal(entry) @@ -309,7 +309,7 @@ func (t *Taldir) disseminateStop(e Entry) error { for _, d := range t.Disseminators { err := d.DisseminateStop(&e) if err != nil { - t.Logger.Logf(LogWarning, "Dissemination stop failed for disseminator `%s' and entry `%s'", d.Name(), e.HsAddress) + t.Logger.Logf(LogWarning, "Dissemination stop failed for disseminator `%s' and entry `%s'", d.Name(), e.HsAlias) } } return nil @@ -320,7 +320,7 @@ func (t *Taldir) disseminateStart(e Entry) { for _, d := range t.Disseminators { err := d.DisseminateStart(&e) if err != nil { - t.Logger.Logf(LogWarning, "Dissemination start failed for disseminator `%s' and entry `%s': %v", d.Name(), e.HsAddress, err) + t.Logger.Logf(LogWarning, "Dissemination start failed for disseminator `%s' and entry `%s': %v", d.Name(), e.HsAlias, err) } } } @@ -349,9 +349,9 @@ func (t *Taldir) HashAlias(atype string, alias string) []byte { // Hashes an identity key (see hashAlias) with a salt for // Lookup and storage. -func saltHAddress(hAddress string, salt string) string { +func saltHAlias(hAlias string, salt string) string { h := sha512.New() - h.Write([]byte(hAddress)) + h.Write([]byte(hAlias)) h.Write([]byte(salt)) return util.Base32CrockfordEncode(h.Sum(nil)) } @@ -377,7 +377,7 @@ func (t *Taldir) validationRequest(w http.ResponseWriter, r *http.Request) { w.Write(resp) return } - err = t.Db.First(&validation, "h_address = ?", vars["h_address"]).Error + err = t.Db.First(&validation, "h_alias = ?", vars["h_alias"]).Error if err != nil { w.WriteHeader(http.StatusNotFound) return @@ -406,14 +406,14 @@ func (t *Taldir) validationRequest(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) return } - entry.HsAddress = saltHAddress(validation.HAddress, t.Salt) + entry.HsAlias = saltHAlias(validation.HAlias, t.Salt) entry.TargetUri = validation.TargetUri tmpDuration := (entry.Duration.Microseconds() + validation.Duration) * 1000 entry.Duration = time.Duration(tmpDuration) - err = t.Db.First(&entry, "hs_address = ?", entry.HsAddress).Error + err = t.Db.First(&entry, "hs_alias = ?", entry.HsAlias).Error if err == nil { if validation.TargetUri == "" { - t.Logger.Logf(LogDebug, "Deleted entry for '%s´\n", entry.HsAddress) + t.Logger.Logf(LogDebug, "Deleted entry for '%s´\n", entry.HsAlias) err = t.Db.Delete(&entry).Error if err != nil { w.WriteHeader(http.StatusInternalServerError) @@ -426,7 +426,7 @@ func (t *Taldir) validationRequest(w http.ResponseWriter, r *http.Request) { } } else { if validation.TargetUri == "" { - t.Logger.Logf(LogWarning, "Validated a deletion request but no entry found for `%s'\n", entry.HsAddress) + t.Logger.Logf(LogWarning, "Validated a deletion request but no entry found for `%s'\n", entry.HsAlias) } else { err = t.Db.Create(&entry).Error if err != nil { @@ -438,9 +438,9 @@ func (t *Taldir) validationRequest(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } -func (t *Taldir) isRateLimited(hAddress string) (bool, error) { +func (t *Taldir) isRateLimited(hAlias string) (bool, error) { var validations []Validation - res := t.Db.Where("h_address = ?", hAddress).Find(&validations) + res := t.Db.Where("h_alias = ?", hAlias).Find(&validations) // NOTE: Check rate limit if res.Error == nil { // Limit re-initiation attempts to ValidationInitiationMax times @@ -457,11 +457,12 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request) { var validation Validation var entry Entry // Check if this validation method is supported or not. - validator, ok := t.Validators[vars["method"]] + validator, ok := t.Validators[vars["alias_type"]] if !ok { + // FIXME rename GANA entry to alias type errDetail.Code = gana.TALDIR_METHOD_NOT_SUPPORTED - errDetail.Hint = "Unsupported method" - errDetail.Detail = "Given method: " + vars["method"] + errDetail.Hint = "Unsupported alias_type" + errDetail.Detail = "Given alias_type: " + vars["alias_type"] resp, _ := json.Marshal(errDetail) w.WriteHeader(http.StatusNotFound) w.Write(resp) @@ -496,12 +497,12 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request) { // Setup validation object. Retrieve object from DB if it already // exists. - hAddressBin := t.HashAlias(validator.Name(), req.Address) - hAddress := util.Base32CrockfordEncode(hAddressBin) - validation.HAddress = hAddress + hAliasBin := t.HashAlias(validator.Name(), req.Alias) + hAlias := util.Base32CrockfordEncode(hAliasBin) + validation.HAlias = hAlias validation.ValidatorName = validator.Name() - hsAddress := saltHAddress(validation.HAddress, t.Salt) - err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error + hsAlias := saltHAlias(validation.HAlias, t.Salt) + err = t.Db.First(&entry, "hs_alias = ?", hsAlias).Error // Round to the nearest multiple of a month reqDuration := time.Duration(req.Duration * 1000) reqDuration = reqDuration.Round(monthDuration) @@ -518,7 +519,7 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request) { return } } - rateLimited, err := t.isRateLimited(hAddress) + rateLimited, err := t.isRateLimited(hAlias) if nil != err { t.Logger.Logf(LogError, "Error checking rate limit! %v", err) w.WriteHeader(http.StatusInternalServerError) @@ -535,8 +536,8 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request) { t.Db.Delete(&validation) return } - err = t.Db.First(&validation, "h_address = ? AND target_uri = ? AND duration = ?", - hAddress, req.TargetUri, reqDuration).Error + err = t.Db.First(&validation, "h_alias = ? AND target_uri = ? AND duration = ?", + hAlias, req.TargetUri, reqDuration).Error validationExists := (nil == err) // FIXME: Always set new challenge? validation.Challenge = util.GenerateChallenge(t.ChallengeBytes) @@ -596,9 +597,9 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request) { return } topic := t.I18n.GetLocale(r).GetMessage("taldirRegTopic") - link := t.Host + "/register/" + url.QueryEscape(validation.HAddress) + "/" + url.QueryEscape(validation.Challenge) + "?address=" + url.QueryEscape(req.Address) + link := t.Host + "/register/" + url.QueryEscape(validation.HAlias) + "/" + url.QueryEscape(validation.Challenge) + "?alias=" + url.QueryEscape(req.Alias) message := t.I18n.GetLocale(r).GetMessage("taldirRegMessage", link) - redirectionLink, err := validator.RegistrationStart(topic, link, message, req.Address, validation.Challenge) + redirectionLink, err := validator.RegistrationStart(topic, link, message, req.Alias, validation.Challenge) if err != nil { t.Logger.Logf(LogError, err.Error()+"\n") t.Db.Delete(&validation) @@ -616,10 +617,10 @@ func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request) { } func (t *Taldir) configResponse(w http.ResponseWriter, r *http.Request) { - meths := []Method{} + meths := []AliasType{} i := 0 for key := range t.Validators { - var meth Method + var meth AliasType meth.Name = key meth.ChallengeFee = t.Validators[key].ChallengeFee() i++ @@ -629,7 +630,7 @@ func (t *Taldir) configResponse(w http.ResponseWriter, r *http.Request) { Version: "0:0:0", Name: "taler-directory", MonthlyFee: t.Cfg.Ini.Section("taldir").Key("monthly_fee").MustString("KUDOS:1"), - Methods: meths, + AliasType: meths, } w.Header().Set("Content-Type", "application/json") response, _ := json.Marshal(cfg) @@ -639,11 +640,11 @@ func (t *Taldir) configResponse(w http.ResponseWriter, r *http.Request) { func (t *Taldir) validationPage(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) var walletLink string - var address string + var alias string var png []byte var validation Validation - err := t.Db.First(&validation, "h_address = ?", vars["h_address"]).Error + err := t.Db.First(&validation, "h_alias = ?", vars["h_alias"]).Error w.Header().Set("Content-Type", "text/html; charset=utf-8") if err != nil { // This validation does not exist. @@ -656,19 +657,19 @@ func (t *Taldir) validationPage(w http.ResponseWriter, r *http.Request) { return } - address = r.URL.Query().Get("address") + alias = r.URL.Query().Get("alias") - if address == "" { + if alias == "" { w.WriteHeader(404) return } // FIXME requires a prefix-free encoding - hAddressBin := t.HashAlias(validation.ValidatorName, address) - expectedHAddress := util.Base32CrockfordEncode(hAddressBin) + hAliasBin := t.HashAlias(validation.ValidatorName, alias) + expectedHAlias := util.Base32CrockfordEncode(hAliasBin) - if expectedHAddress != validation.HAddress { - t.Logger.Logf(LogWarning, "Address does not match challenge!\n") + if expectedHAlias != validation.HAlias { + t.Logger.Logf(LogWarning, "Alias does not match challenge!\n") w.WriteHeader(400) return } @@ -676,7 +677,7 @@ func (t *Taldir) validationPage(w http.ResponseWriter, r *http.Request) { // FIXME: This is kind of broken and probably requires wallet support/integration first if validation.RequiresPayment { t.Logger.Logf(LogWarning, "Validation requires payment\n") - walletLink = "taler://taldir/" + vars["h_address"] + "/" + vars["challenge"] + "-wallet" + walletLink = "taler://taldir/" + vars["h_alias"] + "/" + vars["challenge"] + "-wallet" png, err = qrcode.Encode(walletLink, qrcode.Medium, 256) if err != nil { w.WriteHeader(500) @@ -695,16 +696,16 @@ func (t *Taldir) validationPage(w http.ResponseWriter, r *http.Request) { expectedSolution := util.GenerateSolution(validation.TargetUri, validation.Challenge) confirmDeletionOrRegistration := "" if validation.TargetUri == "" { - confirmDeletionOrRegistration = t.I18n.GetLocale(r).GetMessage("confirmDelete", address) + confirmDeletionOrRegistration = t.I18n.GetLocale(r).GetMessage("confirmDelete", alias) } else { - confirmDeletionOrRegistration = t.I18n.GetLocale(r).GetMessage("confirmReg", address, validation.TargetUri) + confirmDeletionOrRegistration = t.I18n.GetLocale(r).GetMessage("confirmReg", alias, validation.TargetUri) } fullData := map[string]any{ "version": t.Cfg.Version, "error": r.URL.Query().Get("error"), "target_uri": template.URL(validation.TargetUri), - "address": template.URL(address), - "haddress": template.URL(validation.HAddress), + "alias": template.URL(alias), + "halias": template.URL(validation.HAlias), "solution": template.URL(expectedSolution), "confirmDeletionOrRegistration": template.HTML(confirmDeletionOrRegistration), "productDisclaimerShort": template.HTML(t.I18n.GetLocale(r).GetMessage("productDisclaimerShort")), @@ -792,20 +793,20 @@ func (t *Taldir) aboutPage(w http.ResponseWriter, r *http.Request) { } } -func (t *Taldir) methodLookupResultPage(w http.ResponseWriter, r *http.Request) { +func (t *Taldir) typeLookupResultPage(w http.ResponseWriter, r *http.Request) { var entry Entry vars := mux.Vars(r) w.Header().Set("Content-Type", "text/html; charset=utf-8") - // Check if this validation method is supported or not. - val, ok := t.Validators[vars["method"]] + // Check if this alias type is supported or not. + val, ok := t.Validators[vars["alias_type"]] if !ok { w.WriteHeader(404) return } // Check if alias is valid - alias := r.URL.Query().Get("address") + alias := r.URL.Query().Get("alias") err := val.IsAliasValid(alias) emsg := "" found := false @@ -815,12 +816,12 @@ func (t *Taldir) methodLookupResultPage(w http.ResponseWriter, r *http.Request) http.Redirect(w, r, fmt.Sprintf("/landing/"+val.Name()+"?error=%s", emsg), http.StatusSeeOther) return } else { - hAddressBin := t.HashAlias(val.Name(), r.URL.Query().Get("address")) - hAddress := util.Base32CrockfordEncode(hAddressBin[:]) - hsAddress := saltHAddress(hAddress, t.Salt) - err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error + hAliasBin := t.HashAlias(val.Name(), r.URL.Query().Get("alias")) + hAlias := util.Base32CrockfordEncode(hAliasBin[:]) + hsAlias := saltHAlias(hAlias, t.Salt) + err = t.Db.First(&entry, "hs_alias = ?", hsAlias).Error if err != nil { - t.Logger.Logf(LogError, "`%s` not found.\n", hAddress) + t.Logger.Logf(LogError, "`%s` not found.\n", hAlias) } else { found = true } @@ -828,8 +829,8 @@ func (t *Taldir) methodLookupResultPage(w http.ResponseWriter, r *http.Request) fullData := map[string]any{ "version": t.Cfg.Version, "available": !found, - "method": val.Name(), - "address": r.URL.Query().Get("address"), + "alias_type": val.Name(), + "alias": r.URL.Query().Get("alias"), "result": entry.TargetUri, "error": emsg, "productDisclaimerShort": template.HTML(t.I18n.GetLocale(r).GetMessage("productDisclaimerShort")), @@ -841,12 +842,12 @@ func (t *Taldir) methodLookupResultPage(w http.ResponseWriter, r *http.Request) } } -func (t *Taldir) methodLandingPage(w http.ResponseWriter, r *http.Request) { +func (t *Taldir) typeLandingPage(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) w.Header().Set("Content-Type", "text/html; charset=utf-8") - // Check if this validation method is supported or not. - val, ok := t.Validators[vars["method"]] + // Check if this alias type is supported or not. + val, ok := t.Validators[vars["alias_type"]] if !ok { w.WriteHeader(404) return @@ -884,12 +885,12 @@ func (t *Taldir) setupHandlers() { /* Registration API */ t.Router.HandleFunc("/", t.landingPage).Methods("GET") - t.Router.HandleFunc("/{h_address}", t.getSingleEntry).Methods("GET") - t.Router.HandleFunc("/lookup/{method}", t.methodLookupResultPage).Methods("GET") - t.Router.HandleFunc("/landing/{method}", t.methodLandingPage).Methods("GET") - t.Router.HandleFunc("/register/{method}", t.registerRequest).Methods("POST") - t.Router.HandleFunc("/register/{h_address}/{challenge}", t.validationPage).Methods("GET") - t.Router.HandleFunc("/{h_address}", t.validationRequest).Methods("POST") + t.Router.HandleFunc("/{h_alias}", t.getSingleEntry).Methods("GET") + t.Router.HandleFunc("/lookup/{alias_type}", t.typeLookupResultPage).Methods("GET") + t.Router.HandleFunc("/landing/{alias_type}", t.typeLandingPage).Methods("GET") + t.Router.HandleFunc("/register/{alias_type}", t.registerRequest).Methods("POST") + t.Router.HandleFunc("/register/{h_alias}/{challenge}", t.validationPage).Methods("GET") + t.Router.HandleFunc("/{h_alias}", t.validationRequest).Methods("POST") } diff --git a/pkg/taldir/validator.go b/pkg/taldir/validator.go @@ -47,5 +47,5 @@ type Validator interface { IsAliasValid(alias string) error // Start registration - RegistrationStart(topic string, link string, message string, address string, challenge string) (string, error) + RegistrationStart(topic string, link string, message string, alias string, challenge string) (string, error) } diff --git a/scripts/validators/taldir-validate-mail b/scripts/validators/taldir-validate-mail @@ -2,7 +2,7 @@ # USER_MAIL=$1 CODE=$2 -LINK=$(taldir-cli -l -a $1 -c $2) +LINK=$(taldir-cli -l -a $1 -t email -c $2) TOPIC=$3 MESSAGE=$4 # Interpret backslash (newline etc) echo -e $MESSAGE | mail -s "Taldir Registration Confirmation" $USER_MAIL diff --git a/scripts/validators/taldir-validate-phone b/scripts/validators/taldir-validate-phone @@ -11,7 +11,7 @@ fi USER_MAIL=$1 CODE=$2 -LINK=$(taldir-cli -l -a $1 -c $2) +LINK=$(taldir-cli -l -a $1 -t phone -c $2) TOPIC=$3 diff --git a/web/templates/landing_email.html b/web/templates/landing_email.html @@ -42,7 +42,7 @@ <div class="col-lg-6 offset-lg-3 text-center"> <div class="input-group mb-3"> <div class="form-floating"> - <input type="email" name="address" id="floatingInput" class="form-control" placeholder="jdoe@example.com" aria-label="Default" aria-describedby="inputGroup-sizing-default" data-sb-validations="required,email"> + <input type="email" name="alias" id="floatingInput" class="form-control" placeholder="jdoe@example.com" aria-label="Default" aria-describedby="inputGroup-sizing-default" data-sb-validations="required,email"> <label for="floatingInput">{{ call .tr "email" }}</label> </div> <div class="invalid-feedback text-white" data-sb-feedback="emailAddressBelow:required">Email Address is required.</div> diff --git a/web/templates/landing_phone.html b/web/templates/landing_phone.html @@ -42,7 +42,7 @@ <div class="input-group mb-3"> <span class="input-group-text" id="inputGroup-sizing-default">+</span> <div class="form-floating"> - <input type="text" name="address" id="phoneInput" class="form-control" aria-label="Default" placeholder="49123456789" aria-describedby="inputGroup-sizing-default"> + <input type="text" name="alias" id="phoneInput" class="form-control" aria-label="Default" placeholder="49123456789" aria-describedby="inputGroup-sizing-default"> <label for="phoneInput">{{ call .tr "phone" }}</label> </div> <input class="input-group-text btn btn-outline-primary" type="submit" value="{{ call .tr "lookup" }}"> diff --git a/web/templates/lookup_result.html b/web/templates/lookup_result.html @@ -42,15 +42,14 @@ <div class="card-body"> <h4 class="card-title">{{ call .tr "available" }}</h4> <hr> - <p class="card-text">{{ call .tr "notYetLinked" .address}}</p> + <p class="card-text">{{ call .tr "notYetLinked" .alias}}</p> </div> <form id="regform"> - <input id="methodInput" type="hidden" name="method" value="{{.method}}"> - <input id="addrInput" type="hidden" name="address" value="{{.address}}"> + <input id="atypeInput" type="hidden" name="alias_type" value="{{.alias_type}}"> + <input id="addrInput" type="hidden" name="alias" value="{{.alias}}"> <div class="row"> <div class="col-lg-8 offset-lg-2 text-center"> <div class="input-group mb-3"> - <!--<span class="input-group-text" id="inputGroup-sizing-default">{{.address}}: </span>--> <input id="uriInput" name="target_uri" type="text" class="form-control" placeholder="{{ call .tr "paymentSystemAddressExample" }}" aria-label="Default" aria-describedby="inputGroup-sizing-default"> <input class="input-group-text btn btn-outline-primary" type="submit" value="{{ call .tr "linkIt" }}"> </div> @@ -61,16 +60,15 @@ <div class="card-body" role="alert"> <h4 class="card-title">{{ call .tr "lookupResultFound" }}</h4> <hr> - <p class="card-text">{{ call .tr "isLinked" .address }}</p> + <p class="card-text">{{ call .tr "isLinked" .alias }}</p> </div> <form id="regform"> - <input id="methodInput" type="hidden" name="method" value="{{.method}}"> - <input id="addrInput" type="hidden" name="address" value="{{.address}}"> + <input id="atypeInput" type="hidden" name="alias_type" value="{{.alias_type}}"> + <input id="addrInput" type="hidden" name="alias" value="{{.alias}}"> <input id="uriInput" type="hidden" name="target_uri" value=""> <div class="row"> <div class="col-lg-6 offset-lg-3 text-center"> <div class="input-group mb-3"> - <!--<span class="input-group-text" id="inputGroup-sizing-default">{{.address}}: </span>--> <input disabled="disabled" type="text" class="form-control" aria-label="Default" aria-describedby="inputGroup-sizing-default" value="{{.result}}"> <input class="input-group-text btn btn-outline-danger" type="submit" value="{{ call .tr "deleteIt" }}"> </div> @@ -89,10 +87,10 @@ form.onsubmit = function(event){ var xhr = new XMLHttpRequest(); var data = new FormData(form); - var method = data.get("method"); - var addr = data.get("address"); - data.delete("method"); - xhr.open('POST','/register/' + method) // FIXME method + var atype = data.get("alias_type"); + var alias = data.get("alias"); + data.delete("alias_type"); + xhr.open('POST','/register/' + atype) xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); var json = JSON.stringify(Object.fromEntries(data)); json["duration"] = 1000000000 diff --git a/web/templates/validation_landing.html b/web/templates/validation_landing.html @@ -53,7 +53,7 @@ <div class="row mt-2"> <div class="col-lg-6 offset-lg-3 text-center"> <form id="regform"> - <input id="haddrInput" name="haddr" type="hidden" value="{{.haddress}}"> + <input id="haliasInput" name="halias" type="hidden" value="{{.halias}}"> <input id="solutionInput" name="solution" type="hidden" value="{{.solution}}"> <input id="confirmbutton" class="btn btn-outline-primary" type="submit" value="{{ call .tr "confirm" }}"> </form> @@ -71,9 +71,9 @@ form.onsubmit = function(event){ var xhr = new XMLHttpRequest(); var data = new FormData(form); - var haddr = data.get("haddr"); - data.delete("haddr"); - xhr.open('POST','/' + haddr) + var halias = data.get("halias"); + data.delete("halias"); + xhr.open('POST','/' + halias) xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); var json = JSON.stringify(Object.fromEntries(data)); xhr.send(json);