gnunet-gns-registrar

GNU Name System registrar
Log | Files | Refs | README

commit 92910c7f03a60e9863bae960c14549aa96c263e8
parent 24faf45f89cd0f1c73389639f2d8c2d397c975e7
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Wed,  1 May 2024 14:44:45 +0200

Fix HAN a11y issue 4: Button under QR code removed. Also automatic redirects after payment to registration page.

Diffstat:
Mpkg/rest/gnsregistrar.go | 120++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mweb/templates/buy.html | 7+++----
Mweb/templates/edit.html | 112++++++++++++++++++++++++++++++++++++++++----------------------------------------
3 files changed, 156 insertions(+), 83 deletions(-)

diff --git a/pkg/rest/gnsregistrar.go b/pkg/rest/gnsregistrar.go @@ -516,6 +516,10 @@ func (t *Registrar) editRegistration(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Unauthorized", http.StatusSeeOther) return } + if !regMetadata.Paid { + http.Redirect(w, r, "/name/" + sanitizedLabel + "/buy/payment?token=" + regMetadata.RegistrationID, http.StatusSeeOther) + return; + } for _, record := range namestoreResponse.Records { if isDelegationRecordType(record.RecordType) { value = record.Value @@ -545,13 +549,102 @@ func (t *Registrar) editRegistration(w http.ResponseWriter, r *http.Request) { return } -func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) { +func (t *Registrar) paymentPage(w http.ResponseWriter, r *http.Request) { var ( namestoreResponse NamestoreRecord regMetadata *RegistrationMetadata client *http.Client label string errorMsg string + ) + vars := mux.Vars(r) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + client = &http.Client{} + label = vars["label"] + sanitizedLabel := url.QueryEscape(vars["label"]) + err := t.isNameValid(label) + if nil != err { + http.Redirect(w, r, fmt.Sprintf("/?error=%s", err), http.StatusSeeOther) + return + } + req, _ := http.NewRequest(http.MethodGet,t.GnunetUrl + "/namestore/" + t.RootZoneName + "/" + sanitizedLabel + "?include_maintenance=yes", nil) + if t.GnunetBasicAuthEnabled { + req.SetBasicAuth(t.GnunetUsername, t.GnunetPassword) + } + resp, err := client.Do(req) + if err != nil { + http.Redirect(w, r, "/" + "?error=Registration failed: Failed to get zone contents", http.StatusSeeOther) + fmt.Printf("Failed to get zone contents") + return + } + defer resp.Body.Close() + if http.StatusOK == resp.StatusCode { + respData, err := io.ReadAll(resp.Body) + if err != nil { + http.Redirect(w, r, "/" + "?error=Registration failed: Failed to get zone contents", http.StatusSeeOther) + fmt.Printf("Failed to get zone contents" + err.Error()) + return + } + err = json.NewDecoder(bytes.NewReader(respData)).Decode(&namestoreResponse) + if err != nil { + http.Redirect(w, r, "/" + "?error=Registration failed: Failed to get zone contents", http.StatusSeeOther) + fmt.Printf("Failed to get zone contents" + err.Error()) + return + } + regMetadata, err = t.getCurrentRegistrationMetadata(sanitizedLabel, &namestoreResponse) + if err != nil { + http.Redirect(w, r, "/" + "?error=Registration failed: Failed to get registration metadata", http.StatusSeeOther) + fmt.Printf("Failed to get registration metadata" + err.Error()) + return + } + } else if http.StatusNotFound != resp.StatusCode { + http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Payment failed: Error determining zone status", http.StatusSeeOther) + return + } + if nil == regMetadata { + http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Payment failed: Please try again.", http.StatusSeeOther) + return + } + if regMetadata.Paid { + http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Payment already paid.", http.StatusSeeOther) + return + } + _, payto, paytoErr := t.Merchant.IsOrderPaid(regMetadata.OrderID) + if paytoErr != nil { + http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Payment failed: Error getting payment data", http.StatusSeeOther) + return + } + qrPng, qrErr := qrcode.Encode(payto, qrcode.Medium, 256) + if qrErr != nil { + http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Registration failed: Error generating QR code", http.StatusSeeOther) + return + } + encodedPng := base64.StdEncoding.EncodeToString(qrPng) + cost, _ := t.RegistrationCost.FormatWithCurrencySpecification(t.CurrencySpec) + w.Header().Set("Refresh", "20;url=" + t.BaseUrl + "/name/" + sanitizedLabel + "/edit?token=" + regMetadata.RegistrationID) + fullData := map[string]interface{}{ + "qrCode": template.URL("data:image/png;base64," + encodedPng), + "payto": template.URL(payto), + "fulfillmentUrl": template.URL(t.BaseUrl + "/name/" + sanitizedLabel + "/edit?token=" + regMetadata.RegistrationID), + "registrationId": regMetadata.RegistrationID, + "label": sanitizedLabel, + "error": errorMsg, + "cost": cost, + "suffixHint": t.SuffixHint, + } + err = t.BuyTpl.Execute(w, fullData) + if err != nil { + fmt.Println(err) + } + return +} + +func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) { + var ( + namestoreResponse NamestoreRecord + regMetadata *RegistrationMetadata + client *http.Client + label string regId string ) vars := mux.Vars(r) @@ -615,16 +708,11 @@ func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Registration failed: Unable to create order", http.StatusSeeOther) return } - _, payto, paytoErr := t.Merchant.IsOrderPaid(orderID) + _, _, paytoErr := t.Merchant.IsOrderPaid(orderID) if paytoErr != nil { http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Registration failed: Error getting payment data", http.StatusSeeOther) return } - qrPng, qrErr := qrcode.Encode(payto, qrcode.Medium, 256) - if qrErr != nil { - http.Redirect(w, r, "/name/" + sanitizedLabel + "?error=Registration failed: Error generating QR code", http.StatusSeeOther) - return - } paymentUntil := time.Now().Add(t.PaymentExpiration) if nil != regMetadata { var newZkeyRecord RecordData @@ -661,22 +749,7 @@ func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) { return } } - encodedPng := base64.StdEncoding.EncodeToString(qrPng) - cost, _ := t.RegistrationCost.FormatWithCurrencySpecification(t.CurrencySpec) - fullData := map[string]interface{}{ - "qrCode": template.URL("data:image/png;base64," + encodedPng), - "payto": template.URL(payto), - "fulfillmentUrl": template.URL(t.BaseUrl + "/name/" + sanitizedLabel + "/edit?token=" + regId), - "registrationId": regId, - "label": sanitizedLabel, - "error": errorMsg, - "cost": cost, - "suffixHint": t.SuffixHint, - } - err = t.BuyTpl.Execute(w, fullData) - if err != nil { - fmt.Println(err) - } + http.Redirect(w, r, "/name/" + sanitizedLabel + "/buy/payment?token=" + regId, http.StatusSeeOther) return } @@ -877,6 +950,7 @@ func (t *Registrar) setupHandlers() { t.Router.HandleFunc("/", t.landingPage).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}/buy/payment", t.paymentPage).Methods("GET") t.Router.HandleFunc("/name/{label}/edit", t.editRegistration).Methods("GET") t.Router.HandleFunc("/name/{label}/edit", t.updateRegistration).Methods("POST") t.Router.HandleFunc("/search", t.searchPage).Methods("GET") diff --git a/web/templates/buy.html b/web/templates/buy.html @@ -14,13 +14,12 @@ <a class="link-dark" href="{{.payto}}" class="btn btn-success mb-3">Pay {{.cost}} with your Taler wallet</a><br/> Alternatively, you can pay using your mobile wallet by scanning the QR code below:<br/> - <a class="link-dark" href="{{.fulfillmentUrl}}"> - <img class="qr" src="{{.qrCode}}"/> - </a><br/> + <img class="qr" src="{{.qrCode}}"/> + <br/> </div> <div class="alert alert-warning"> <h4>Important</h4> - After you pay with a mobile wallet, please click on the QR code to finalize your registration or visit <a class="link-dark" href="{{.fulfillmentUrl}}">your registration management page</a>. + After you pay with a mobile wallet, you should be redirected automatically. If not, you can visit <a class="link-dark" href="{{.fulfillmentUrl}}">your registration management page</a> directly. <br/> Your unique registration identifier is <b>{{.registrationId}}</b>. <br/> diff --git a/web/templates/edit.html b/web/templates/edit.html @@ -1,67 +1,67 @@ <!DOCTYPE html> <html lang="en"> - <head> - <!-- Required meta tags --> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <link href="/css/bootstrap.min.css" rel="stylesheet"> - <title>Edit registration</title> - </head> - <body> - {{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> + <head> + <!-- Required meta tags --> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <link href="/css/bootstrap.min.css" rel="stylesheet"> + <title>Edit registration</title> + </head> + <body> + {{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> - {{end}} - {{if eq .remainingDays 0}} - <div class="container pt-5"> - <div class="alert alert-danger" role="alert"> - <h4 class="alert-heading">Registration inactive!</h4> - <hr> - <p class="mb-0">Your registration is not yet active. Have you completed the payment yet?</p> - </div> + </div> + {{end}} + {{if eq .remainingDays 0}} + <div class="container pt-5"> + <div class="alert alert-danger" role="alert"> + <h4 class="alert-heading">Registration inactive!</h4> + <hr> + <p class="mb-0">Your registration is not yet active. Have you completed the payment yet?</p> </div> - {{end}} - <div class="container pt-5"> - <h1 class="mb-5">Manage registration for <i class="text-primary">{{.label}}</i></h1> - <form action="/name/{{.label}}/edit" method="post" class="align-items-center mb-5"> - <div class="row"> - <div class="col-md-12 alert alert-light"> - <h4>Zone information</h4> - <input type="hidden" value="{{.token}}" name="token"> - {{if ne .remainingDays 0}} - <div class="form-floating mb-3"> - <input name="zkey" id="zkeyInput" class="form-control" value="{{.zkey}}" maxlength="63" type="text" placeholder="Enter your zone key here!" required autofocus> - <label for="zkeyInput">Enter your PKEY or EDKEY here</label> - </div> - <input class="btn btn-primary" type="submit" value="Update zone key"> - {{else}} - <div class="form-floating mb-3"> - <input name="zkey" id="zkeyInput" class="form-control" value="{{.zkey}}" disabled="true" maxlength="63" type="text" placeholder="Enter your zone key here!" required autofocus> - <label for="zkeyInput">Enter your PKEY or EDKEY here</label> - </div> - {{end}} - </div> - </div> - </form> - {{if ne .remainingDays 0}} - <div class="row mt-1"> + </div> + {{end}} + <div class="container pt-5"> + <h1 class="mb-5">Manage registration for <i class="text-primary">{{.label}}</i></h1> + <form action="/name/{{.label}}/edit" method="post" class="align-items-center mb-5"> + <div class="row"> <div class="col-md-12 alert alert-light"> - <h4>Extension</h4> + <h4>Zone information</h4> + <input type="hidden" value="{{.token}}" name="token"> + {{if ne .remainingDays 0}} <div class="form-floating mb-3"> - <input disabled="true" id="expInput" class="form-control" value="{{.registeredUntil}}" type="text" required autofocus> - <label for="expInput">Registration expires in {{.remainingDays}} days:</label> + <input name="zkey" id="zkeyInput" class="form-control" value="{{.zkey}}" maxlength="63" type="text" placeholder="Enter your zone key here!" required autofocus> + <label for="zkeyInput">Enter your PKEY or EDKEY here</label> </div> - <a class="btn btn-primary" href="/name/{{.label}}/buy">Extend registration for {{.extensionDaysCount}} days until <b>{{.extendedExpiration}}</b> for <b>{{.cost}}</b></a> + <input class="btn btn-primary" type="submit" value="Update zone key"> + {{else}} + <div class="form-floating mb-3"> + <input name="zkey" id="zkeyInput" class="form-control" value="{{.zkey}}" disabled="true" maxlength="63" type="text" placeholder="Enter your zone key here!" required autofocus> + <label for="zkeyInput">Enter your PKEY or EDKEY here</label> + </div> + {{end}} + </div> + </div> + </form> + {{if ne .remainingDays 0}} + <div class="row mt-1"> + <div class="col-md-12 alert alert-light"> + <h4>Extension</h4> + <div class="form-floating mb-3"> + <input disabled="true" id="expInput" class="form-control" value="{{.registeredUntil}}" type="text" required autofocus> + <label for="expInput">Registration expires in {{.remainingDays}} days:</label> </div> + <a class="btn btn-primary" href="/name/{{.label}}/buy">Extend registration for {{.extensionDaysCount}} days until <b>{{.extendedExpiration}}</b> for <b>{{.cost}}</b></a> </div> - <hr/> - <a class="btn btn-secondary" href="/">Back</a> </div> - {{end}} - </body> + </div> + {{end}} + <hr/> + <a class="btn btn-secondary" href="/">Back</a> + </body> </html>