commit ce24fe047bbe7b763fee142f60439b28e8c6563a
parent 0ebeb2c197f8fc45101862b960ce629d7c9be6f3
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date: Mon, 11 Dec 2023 17:15:27 +0100
towards editing registration; potentially refund
Diffstat:
3 files changed, 95 insertions(+), 66 deletions(-)
diff --git a/gns-registrar.conf b/gns-registrar.conf.example
diff --git a/go.mod b/go.mod
@@ -3,6 +3,7 @@ module gnunet.org/gnunet-gns-registrar
go 1.18
require (
+ github.com/google/uuid v1.4.0
github.com/gorilla/mux v1.8.1
github.com/schanzen/taler-go v0.0.4
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
diff --git a/pkg/rest/gnsregistrar.go b/pkg/rest/gnsregistrar.go
@@ -39,6 +39,7 @@ import (
"golang.org/x/text/message"
"gopkg.in/ini.v1"
"github.com/schanzen/taler-go/pkg/merchant"
+ "github.com/google/uuid"
talerutil "github.com/schanzen/taler-go/pkg/util"
)
@@ -47,6 +48,7 @@ type RegistrationMetadata struct {
Expiration uint64 `json:"expiration"`
Paid bool `json:"paid"`
OrderID string `json:"order_id"`
+ RegistrationID string `json:"registration_id"`
NeedsPaymentUntil time.Time `json:"needs_payment_until"`
}
@@ -99,6 +101,9 @@ type Registrar struct {
// buy names page
BuyTpl *template.Template
+ // edit registration page
+ EditTpl *template.Template
+
// Merchant object
Merchant merchant.Merchant
@@ -125,10 +130,10 @@ type Registrar struct {
// Gnunet basic auth on/off
GnunetBasicAuthEnabled bool
-
+
// Gnunet basic auth
GnunetUsername string
-
+
// Gnunet basic auth
GnunetPassword string
@@ -159,6 +164,10 @@ func (t *Registrar) configResponse(w http.ResponseWriter, r *http.Request) {
w.Write(response)
}
+func generateRegistrationId() string {
+ return uuid.New().String()
+}
+
// FIXME: Implement https://docs.taler.net/design-documents/051-fractional-digits.html and move to taler-go
func (t *Registrar) localizedAmountString() (string) {
p := message.NewPrinter(language.English)
@@ -187,63 +196,6 @@ func (t *Registrar) landingPage(w http.ResponseWriter, r *http.Request) {
return
}
-func (t *Registrar) registerName(w http.ResponseWriter, r *http.Request) {
- vars := mux.Vars(r)
- var namestoreRequest NamestoreRecord
- var delegationRecord RecordData
- var metadataRecord RecordData
- var gnunetError GnunetError
- var registrationMetadata RegistrationMetadata
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- delegationRecord.IsPrivate = false
- delegationRecord.IsRelativeExpiration = true
- delegationRecord.IsSupplemental = false
- delegationRecord.IsMaintenance = false
- delegationRecord.IsShadow = false
- delegationRecord.RecordType = guessDelegationRecordType(r.URL.Query().Get("zkey"))
- delegationRecord.RelativeExpiration = uint64(t.RelativeDelegationExpiration.Microseconds())
- delegationRecord.Value = r.URL.Query().Get("zkey")
- metadataRecord.IsPrivate = true
- metadataRecord.IsRelativeExpiration = true
- metadataRecord.IsSupplemental = false
- metadataRecord.IsMaintenance = true
- metadataRecord.IsShadow = false
- metadataRecord.RecordType = "TXT" // FIXME use new recory type
- metadataRecord.RelativeExpiration = uint64(t.RelativeDelegationExpiration.Microseconds())
- registrationMetadata = RegistrationMetadata{
- Paid: false,
- Expiration: uint64(time.Now().Add(t.RelativeRegistrationExpiration).UnixMicro()),
- }
- metadataRecordValue, err := json.Marshal(registrationMetadata)
- if nil != err {
- http.Redirect(w, r, "/name?label="+vars["label"] + "&error=Registration failed", http.StatusSeeOther)
- return
- }
- metadataRecord.Value = string(metadataRecordValue)
- namestoreRequest.RecordName = vars["label"]
- namestoreRequest.Records = []RecordData{delegationRecord,metadataRecord}
- reqString, _ := json.Marshal(namestoreRequest)
- // FIXME handle errors here
- fmt.Println(namestoreRequest)
- client := &http.Client{}
- req, _ := http.NewRequest(http.MethodPost, t.GnunetUrl+"/namestore/" + t.RootZoneName, bytes.NewBuffer(reqString))
- if t.GnunetBasicAuthEnabled {
- req.SetBasicAuth(t.GnunetUsername, t.GnunetPassword)
- }
- resp, err := client.Do(req)
- resp.Body.Close()
- if http.StatusNoContent != resp.StatusCode {
- fmt.Printf("Got error: %d\n", resp.StatusCode)
- json.NewDecoder(resp.Body).Decode(&gnunetError)
- fmt.Println(gnunetError.Code)
- fmt.Println(err)
- http.Redirect(w, r, "/name?label="+vars["label"] + "&error=" + gnunetError.Description, http.StatusSeeOther)
- return
- }
- 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)
@@ -295,7 +247,7 @@ func (t *Registrar) createOrUpdateRegistration(nsRecord *NamestoreRecord) (error
return nil
}
-func (t *Registrar) setupRegistrationMetadataBeforePayment(label string, zkey string, orderId string, paymentUntil time.Time) (error) {
+func (t *Registrar) setupRegistrationMetadataBeforePayment(label string, zkey string, orderId string, paymentUntil time.Time, regId string) (error) {
var namestoreRequest NamestoreRecord
var delegationRecord RecordData
var metadataRecord RecordData
@@ -319,6 +271,7 @@ func (t *Registrar) setupRegistrationMetadataBeforePayment(label string, zkey st
Paid: false,
OrderID: orderId,
NeedsPaymentUntil: paymentUntil,
+ RegistrationID: regId,
Expiration: uint64(time.Now().Add(t.RelativeRegistrationExpiration).UnixMicro()),
}
metadataRecordValue, err := json.Marshal(registrationMetadata)
@@ -331,6 +284,74 @@ func (t *Registrar) setupRegistrationMetadataBeforePayment(label string, zkey st
return t.createOrUpdateRegistration(&namestoreRequest)
}
+func (t *Registrar) editRegistration(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ var namestoreResponse NamestoreRecord
+ var regMetadata *RegistrationMetadata
+ var value string
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ client := &http.Client{}
+ req, _ := http.NewRequest(http.MethodGet,t.GnunetUrl + "/namestore/" + t.RootZoneName + "/" + vars["label"] + "?include_maintenance=yes", nil)
+ if t.GnunetBasicAuthEnabled {
+ req.SetBasicAuth(t.GnunetUsername, t.GnunetPassword)
+ }
+ resp, err := client.Do(req)
+ if err != nil {
+ 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, "/name/" + vars["label"] + "?error=Error determining zone status", 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, "/name/" + vars["label"] + "?error=Error determining zone status", http.StatusSeeOther)
+ fmt.Printf("Failed to get zone contents" + err.Error())
+ return
+ }
+ regMetadata, err = t.getCurrentRegistrationMetadata(vars["label"], &namestoreResponse)
+ if err != nil {
+ http.Redirect(w, r, "/name/" + vars["label"] + "?error=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/" + vars["label"] + "?error=Error determining zone status", http.StatusSeeOther)
+ return
+ }
+ if nil == regMetadata {
+ http.Redirect(w, r, "/name/"+vars["label"], http.StatusSeeOther)
+ return
+ }
+ if regMetadata.RegistrationID != r.URL.Query().Get("token") {
+ http.Redirect(w, r, "/name/"+vars["label"] + "?error=Unauthorized", http.StatusSeeOther)
+ return
+ }
+ for _, record := range namestoreResponse.Records {
+ if isDelegationRecordType(record.RecordType) {
+ value = record.Value
+ }
+ }
+ registeredUntil := time.UnixMicro(int64(regMetadata.Expiration)).Format(time.UnixDate)
+ extendedExpiration := time.UnixMicro(int64(regMetadata.Expiration)).Add(t.RelativeRegistrationExpiration).Format(time.UnixDate)
+ fullData := map[string]interface{}{
+ "label": vars["label"],
+ "zkey": value,
+ "extendedExpiration": extendedExpiration,
+ "registeredUntil": registeredUntil,
+ "token": r.URL.Query().Get("token"),
+ "error": r.URL.Query().Get("error"),
+ "cost": t.localizedAmountString(),
+ "suffixHint": t.SuffixHint,
+ }
+ t.EditTpl.Execute(w, fullData)
+ return
+}
func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
@@ -374,7 +395,8 @@ func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) {
return
}
summaryMsg := strings.Replace(t.SummaryTemplateString, "${NAME}", vars["label"], 1)
- orderID, newOrderErr := t.Merchant.AddNewOrder(*t.RegistrationCost, summaryMsg, t.BaseUrl + "/name/" + vars["label"])
+ regId := generateRegistrationId()
+ orderID, newOrderErr := t.Merchant.AddNewOrder(*t.RegistrationCost, summaryMsg, t.BaseUrl + "/name/" + vars["label"] + "/edit?token=" + regId)
if newOrderErr != nil {
fmt.Println(newOrderErr)
http.Redirect(w, r, "/name/"+vars["label"] + "?error=Registration failed: Unable to create order", http.StatusSeeOther)
@@ -391,7 +413,7 @@ func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) {
return
}
paymentUntil := time.Now().Add(t.PaymentExpiration)
- err = t.setupRegistrationMetadataBeforePayment(vars["label"], r.URL.Query().Get("zkey"), orderID, paymentUntil)
+ err = t.setupRegistrationMetadataBeforePayment(vars["label"], r.URL.Query().Get("zkey"), orderID, paymentUntil, regId)
if err != nil {
fmt.Println(err)
http.Redirect(w, r, "/name/"+vars["label"] + "?error=Registration failed: Internal error", http.StatusSeeOther)
@@ -433,7 +455,7 @@ func (t *Registrar) getCurrentRegistrationMetadata(label string, nsRecord *Names
if rc == http.StatusNotFound {
fmt.Printf("Registration for %s not found, removing\n", label)
t.expireRegistration(label)
- return nil, nil
+ return nil, nil
}
return nil, errors.New("Error determining payment status: " + paytoErr.Error())
}
@@ -538,7 +560,7 @@ func (t *Registrar) namePage(w http.ResponseWriter, r *http.Request) {
}
if regMetadata != nil {
if regMetadata.Paid {
- registeredUntil = time.UnixMicro(int64(regMetadata.Expiration)).String()
+ registeredUntil = time.UnixMicro(int64(regMetadata.Expiration)).Format(time.UnixDate)
}
}
fullData := map[string]interface{}{
@@ -561,7 +583,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}/register", t.registerName).Methods("GET")
+ t.Router.HandleFunc("/name/{label}/edit", t.editRegistration).Methods("GET")
t.Router.HandleFunc("/search", t.searchPage).Methods("GET")
/* ToS API */
@@ -602,6 +624,11 @@ func (t *Registrar) Initialize(cfgfile string) {
if err != nil {
fmt.Println(err)
}
+ editTplFile := t.Cfg.Section("gns-registrar").Key("edit_template").MustString("web/templates/edit.html")
+ t.EditTpl, err = template.ParseFiles(editTplFile)
+ if err != nil {
+ fmt.Println(err)
+ }
paymentExp := t.Cfg.Section("gns-registrar").Key("payment_required_expiration").MustString("1h")
recordExp := t.Cfg.Section("gns-registrar").Key("relative_delegation_expiration").MustString("24h")
registrationExp := t.Cfg.Section("gns-registrar").Key("registration_expiration").MustString("120h")
@@ -627,7 +654,8 @@ func (t *Registrar) Initialize(cfgfile string) {
}
resp, err := client.Do(req)
if err != nil {
- fmt.Printf("Failed to get zone key")
+ fmt.Println("Failed to get zone key")
+ os.Exit(1)
return
}
defer resp.Body.Close()