gnunet-gns-registrar

GNU Name System registrar
Log | Files | Refs | README

commit c72db71ea48e9023b2f2dbb68d1e144a5c729731
parent 5b0eaec6a47cdc27094d8b03ee75bf07bc5bfdcc
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Tue,  5 Dec 2023 08:20:17 +0100

Use path elements for labels and actions

Diffstat:
Mpkg/rest/gnsregistrar.go | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mweb/templates/landing.html | 6+++---
Mweb/templates/name.html | 19++++++++++++++-----
3 files changed, 89 insertions(+), 15 deletions(-)

diff --git a/pkg/rest/gnsregistrar.go b/pkg/rest/gnsregistrar.go @@ -32,6 +32,12 @@ import ( "taler.net/taler-go.git/pkg/merchant" ) +type IdentityInfo struct { + Pubkey string `json:"pubkey"` + Name string `json:"name"` +} + + type GnunetError struct { Description string `json:"error"` Code uint32 `json:"error_code"` @@ -83,6 +89,10 @@ type Registrar struct { // Name of our root zone RootZoneName string + + // Key of our root zone + RootZoneKey string + // Suggested suffix for our zone SuffixHint string @@ -91,6 +101,12 @@ type Registrar struct { // Registration policy; fcfs or paid RegistrationPolicy string + + // Cost for a registration + RegistrationCost uint64 + + // Currency to use + RegistrationCostCurrency string } type VersionResponse struct { @@ -114,12 +130,14 @@ func (t *Registrar) landingPage(w http.ResponseWriter, r *http.Request) { fullData := map[string]interface{}{ "suffixHint": t.SuffixHint, + "zoneKey": t.RootZoneKey, } t.LandingTpl.Execute(w, fullData) return } func (t *Registrar) registerName(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) var namestoreRequest NamestoreRecord var delegationRecord RecordData var gnunetError GnunetError @@ -131,7 +149,7 @@ func (t *Registrar) registerName(w http.ResponseWriter, r *http.Request) { delegationRecord.RecordType = "PKEY" // FIXME delegationRecord.RelativeExpiration = t.RelativeDelegationExpiration delegationRecord.Value = r.URL.Query().Get("zkey") - namestoreRequest.RecordName = r.URL.Query().Get("label") + namestoreRequest.RecordName = vars["label"] namestoreRequest.Records = []RecordData{delegationRecord} reqString, _ := json.Marshal(namestoreRequest) // FIXME handle errors here @@ -146,20 +164,35 @@ func (t *Registrar) registerName(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/name?label="+r.URL.Query().Get("label") + "&error=" + gnunetError.Description, http.StatusSeeOther) return } - http.Redirect(w, r, "/name?label="+r.URL.Query().Get("label") + "&registered=true", http.StatusSeeOther) + http.Redirect(w, r, "/name/"+ vars["label"] + "?registered=true", http.StatusSeeOther) return } +func (t *Registrar) searchPage(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + http.Redirect(w, r, "/name/"+r.URL.Query().Get("label"), http.StatusSeeOther) + return +} + +func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + if t.RegistrationCost == 0 { + http.Redirect(w, r, "/name/"+vars["label"]+"/register?zkey="+r.URL.Query().Get("zkey"), http.StatusSeeOther) + } + http.Redirect(w, r, "/name/"+vars["label"]+"?error=Not implemented", http.StatusSeeOther) + return +} func (t *Registrar) namePage(w http.ResponseWriter, r *http.Request) { var namestoreResponse NamestoreRecord + vars := mux.Vars(r) w.Header().Set("Content-Type", "text/html; charset=utf-8") var available = false var value = "" var registered = r.URL.Query().Get("registered") == "true" // FIXME redirect back if label empty - resp, err := http.Get(t.GnunetUrl + "/namestore/" + t.RootZoneName + "/" + r.URL.Query().Get("label")) + resp, err := http.Get(t.GnunetUrl + "/namestore/" + t.RootZoneName + "/" + vars["label"]) if err != nil { fmt.Printf("Failed to get zone contents") return @@ -184,7 +217,10 @@ func (t *Registrar) namePage(w http.ResponseWriter, r *http.Request) { return } fullData := map[string]interface{}{ - "label": r.URL.Query().Get("label"), + "label": vars["label"], + "error": r.URL.Query().Get("error"), + "cost": t.RegistrationCost, + "currency": t.RegistrationCostCurrency, "available": available, "currentValue": value, "suffixHint": t.SuffixHint, @@ -227,8 +263,10 @@ func (t *Registrar) setupHandlers() { t.Router = mux.NewRouter().StrictSlash(true) t.Router.HandleFunc("/", t.landingPage).Methods("GET") - t.Router.HandleFunc("/name", t.namePage).Methods("GET") - t.Router.HandleFunc("/register", t.registerName).Methods("GET") + t.Router.HandleFunc("/name/{label}", t.namePage).Methods("GET") + t.Router.HandleFunc("/name/{label}/buy", t.buyPage).Methods("GET") + t.Router.HandleFunc("/name/{label}/register", t.registerName).Methods("GET") + t.Router.HandleFunc("/search", t.searchPage).Methods("GET") t.Router.HandleFunc("/names", t.allNamesPage).Methods("GET") /* ToS API */ @@ -244,6 +282,7 @@ func (t *Registrar) setupHandlers() { // Initialize the gnsregistrar instance with cfgfile func (t *Registrar) Initialize(cfgfile string) { + var identityResponse IdentityInfo _cfg, err := ini.Load(cfgfile) if err != nil { fmt.Printf("Failed to read config: %v", err) @@ -268,11 +307,37 @@ func (t *Registrar) Initialize(cfgfile string) { if err != nil { fmt.Println(err) } + t.RegistrationCost = t.Cfg.Section("gns-registrar").Key("registration_cost").MustUint64(0) t.RelativeDelegationExpiration = t.Cfg.Section("gns-registrar").Key("relative_delegation_expiration").MustUint64(86400000) - t.RegistrationPolicy = t.Cfg.Section("gns-registrar").Key("registration_policy").MustString("paid") + t.RegistrationCostCurrency = t.Cfg.Section("gns-registrar").Key("registration_cost_currency").MustString("EUR") t.SuffixHint = t.Cfg.Section("gns-registrar").Key("suffix_hint").MustString("example.alt") t.RootZoneName = t.Cfg.Section("gns-registrar").Key("root_zone_name").MustString("master") t.GnunetUrl = t.Cfg.Section("gns-registrar").Key("gnunet_baseurl_private").MustString("http://localhost:7776") + resp, err := http.Get(t.GnunetUrl + "/identity/name/" + t.RootZoneName) + if err != nil { + fmt.Printf("Failed to get zone key") + return + } + defer resp.Body.Close() + if http.StatusNotFound == resp.StatusCode { + fmt.Printf("Zone not found.") + os.Exit(1) + } else if http.StatusOK == resp.StatusCode { + respData, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Printf("Failed to get zone contents" + err.Error()) + os.Exit(1) + } + err = json.NewDecoder(bytes.NewReader(respData)).Decode(&identityResponse) + if err != nil { + fmt.Printf("Failed to get zone contents" + err.Error()) + os.Exit(1) + } + t.RootZoneKey = identityResponse.Pubkey + } else { + fmt.Printf("Failed to get zone contents" + err.Error()) + os.Exit(1) + } merchURL := t.Cfg.Section("gns-registrar").Key("merchant_baseurl_private").MustString("http://merchant.gnsregistrar/instances/myInstance") merchToken := t.Cfg.Section("gns-registrar").Key("merchant_token").MustString("secretAccessToken") t.Merchant = merchant.NewMerchant(merchURL, merchToken) diff --git a/web/templates/landing.html b/web/templates/landing.html @@ -9,8 +9,8 @@ </head> <body> <div class="container pt-5"> - <h1 class="text-center mb-5">.{{.suffixHint}} is TODOFIXMETHEACTUALKEY</h1> - <form action="/name" method="get"> + <h1 class="text-center mb-5">.{{.suffixHint}} is {{.zoneKey}}</h1> + <form action="/search" method="get"> <label for="label" class="form-label">Check availability:</label> <div class="input-group mb-2 w-50"> <input id="label" name="label" class="form-control form-control-lg text-end" maxlength="63" type="text" aria-describedby="reg-suffix" required autofocus> @@ -24,7 +24,7 @@ <h4 class="alert-heading">The .{{.suffixHint}} Zone!</h4> <p>If you do not have our zone configured in your <i>Start Zones</i>, we suggest to do it as:</p> <hr> - <p class="mb-0">.{{.suffixHint}} = TODOFIXMETHEACTUALKEY</p> + <p class="mb-0">.{{.suffixHint}} = {{.zoneKey}}</p> </div> </div> </body> diff --git a/web/templates/name.html b/web/templates/name.html @@ -17,24 +17,33 @@ </div> </div> {{end}} + {{if .error}} + <div class="container pt-5"> + <div class="alert alert-danger" role="alert"> + <h4 class="alert-heading">Oh no!</h4> + <hr> + <p class="mb-0">{{.error}}.</p> + </div> + </div> + {{end}} <div class="container pt-5"> {{if .available}} <h1 class="mb-5"><i class="text-primary">{{.label}}</i> is still <span class="text-success">available</span> for registration.</h1> - <form action="/register" method="get" class="align-items-center"> + <form action="/name/{{.label}}/buy" method="get" class="align-items-center"> <div class="input-group mb-2 w-75"> <span class="input-group-text" id="reg-prefix"><i class="text-primary">{{.label}}</i>.<i class="text-secondary">{{.suffixHint}}</i>: </span> <input type="hidden" name="label" value="{{.label}}"> <input name="zkey" class="form-control form-control-lg" maxlength="63" type="text" placeholder="Enter your zone key here!" required autofocus> - {{if eq .registrationPolicy "fcfs"}} - <input class="btn btn-primary" type="submit" value="Register"> + {{if eq .cost 0}} + <input class="btn btn-primary" type="submit" value="Register for free"> {{else}} - <input class="btn btn-primary" type="submit" value="Buy"> + <input class="btn btn-primary" type="submit" value="Register for {{.cost}} {{.currency}}"> {{end}} </div> </form> {{else}} <h1 class="mb-5"><i class="text-primary">{{.label}}</i> is already <span class="text-danger">taken</span>!</h1> - <form action="/renew" method="get" class="align-items-center"> + <form action="/name/{{.label}}/renew" method="get" class="align-items-center"> <div class="input-group mb-2 w-75"> <span class="input-group-text" id="reg-prefix"><i class="text-primary">{{.label}}</i>.<i class="text-secondary">{{.suffixHint}}</i>: </span> <input name="label" disabled="{{.modificationAllowed}}" class="form-control form-control-lg" maxlength="63" type="text" placeholder="Enter your zone key here!" value="{{.currentValue}}" required autofocus>