commit 3997503ee1339a957a8275cb7e8c724ad618d25d
parent a84002ca1ad4f70cc7f6c5105424f7a8ab1af6d8
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date: Wed, 6 Dec 2023 16:40:05 +0100
Towards reservation flows.
Diffstat:
2 files changed, 110 insertions(+), 81 deletions(-)
diff --git a/pkg/rest/gnsregistrar.go b/pkg/rest/gnsregistrar.go
@@ -118,9 +118,6 @@ type Registrar struct {
// Gnunet REST API basename
GnunetUrl string
- // Registration policy; fcfs or paid
- RegistrationPolicy string
-
// Cost for a registration
RegistrationCost *talerutil.Amount
@@ -231,11 +228,29 @@ func (t *Registrar) expireRegistration(label string) (error) {
return nil
}
+func (t *Registrar) createOrUpdateRegistration(nsRecord *NamestoreRecord) (error) {
+ var gnunetError GnunetError
+ reqString, _ := json.Marshal(nsRecord)
+ fmt.Println(nsRecord)
+ client := &http.Client{}
+ req, _ := http.NewRequest(http.MethodPut,t.GnunetUrl+"/namestore/" + t.RootZoneName, bytes.NewBuffer(reqString))
+ resp, err := client.Do(req)
+ if nil != err {
+ return err
+ }
+ resp.Body.Close()
+ if http.StatusNoContent != resp.StatusCode {
+ fmt.Printf("Got error: %d\n", resp.StatusCode)
+ err = json.NewDecoder(resp.Body).Decode(&gnunetError)
+ return errors.New("GNUnet REST API error: " + gnunetError.Description)
+ }
+ return nil
+}
+
func (t *Registrar) setupRegistrationMetadataBeforePayment(label string, zkey string, orderId string, paymentUntil time.Time) (error) {
var namestoreRequest NamestoreRecord
var delegationRecord RecordData
var metadataRecord RecordData
- var gnunetError GnunetError
var registrationMetadata RegistrationMetadata
delegationRecord.IsPrivate = true // Private until payment is through
delegationRecord.IsRelativeExpiration = true
@@ -265,30 +280,15 @@ func (t *Registrar) setupRegistrationMetadataBeforePayment(label string, zkey st
metadataRecord.Value = string(metadataRecordValue)
namestoreRequest.RecordName = label
namestoreRequest.Records = []RecordData{delegationRecord,metadataRecord}
- reqString, _ := json.Marshal(namestoreRequest)
- // FIXME handle errors here
- fmt.Println(namestoreRequest)
- resp, err := http.Post(t.GnunetUrl+"/namestore/" + t.RootZoneName, "application/json", bytes.NewBuffer(reqString))
- resp.Body.Close()
- if http.StatusNoContent != resp.StatusCode {
- fmt.Printf("Got error: %d\n", resp.StatusCode)
- err = json.NewDecoder(resp.Body).Decode(&gnunetError)
- return errors.New("GNUnet REST API error: " + gnunetError.Description)
- }
- return nil
+ return t.createOrUpdateRegistration(&namestoreRequest)
}
+
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)
- return
- }*/
- var metadataResponse RegistrationMetadata
var namestoreResponse NamestoreRecord
+ var regMetadata *RegistrationMetadata
w.Header().Set("Content-Type", "text/html; charset=utf-8")
- var metadataExists = false
- // FIXME redirect back if label empty
resp, err := http.Get(t.GnunetUrl + "/namestore/" + t.RootZoneName + "/" + vars["label"] + "?include_maintenance=yes")
if err != nil {
fmt.Printf("Failed to get zone contents")
@@ -306,35 +306,19 @@ func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Failed to get zone contents" + err.Error())
return
}
- for _, record := range namestoreResponse.Records {
- if record.RecordType == "PKEY" {
- continue
- }
- if record.RecordType == "TXT" {
- err = json.Unmarshal([]byte(record.Value), &metadataResponse)
- if err != nil {
- fmt.Printf("Failed to get zone contents" + err.Error())
- return
- }
- metadataExists = true
- }
+ regMetadata, err = t.getCurrentRegistrationMetadata(vars["label"], &namestoreResponse)
+ if err != nil {
+ fmt.Printf("Failed to get registration metadata" + err.Error())
+ return
}
- } else {
- fmt.Printf("Failed to get zone contents" + err.Error())
+ } else if http.StatusNotFound != resp.StatusCode {
+ http.Redirect(w, r, "/name/" + vars["label"] + "?error=Registration failed: Error determining zone status", http.StatusSeeOther)
return
}
var errorMsg = ""
- // FIXME check for order expiration
- if metadataExists {
- if metadataResponse.Paid {
- http.Redirect(w, r, "/name/" +vars["label"] + "?error=Registration failed: Already paid", http.StatusSeeOther)
- return
- }
- if !time.Now().After(metadataResponse.NeedsPaymentUntil) {
- http.Redirect(w, r, "/name/" + vars["label"] + "?error=Registration failed: Name is being paid", http.StatusSeeOther)
- return
- }
- t.expireRegistration(vars["label"])
+ if nil != regMetadata {
+ http.Redirect(w, r, "/name/"+vars["label"] + "?error=Registration failed: Pending buy order", http.StatusSeeOther)
+ return
}
orderID, newOrderErr := t.Merchant.AddNewOrder(*t.RegistrationCost, "GNS registrar name registration", "/name/" + vars["label"])
if newOrderErr != nil {
@@ -342,9 +326,7 @@ func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/name/"+vars["label"] + "?error=Registration failed: Unable to create order", http.StatusSeeOther)
return
}
- metadataResponse.OrderID = orderID
-
- payto, paytoErr := t.Merchant.IsOrderPaid(metadataResponse.OrderID)
+ payto, paytoErr := t.Merchant.IsOrderPaid(orderID)
if paytoErr != nil {
http.Redirect(w, r, "/name/"+vars["label"] + "?error=Registration failed: Error getting payment data", http.StatusSeeOther)
return
@@ -355,7 +337,12 @@ func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) {
return
}
paymentUntil := time.Now().Add(t.PaymentExpiration)
- err = t.setupRegistrationMetadataBeforePayment(vars["label"], vars["zkey"], orderID, paymentUntil)
+ err = t.setupRegistrationMetadataBeforePayment(vars["label"], r.URL.Query().Get("zkey"), orderID, paymentUntil)
+ if err != nil {
+ fmt.Println(err)
+ http.Redirect(w, r, "/name/"+vars["label"] + "?error=Registration failed: Internal error", http.StatusSeeOther)
+ return
+ }
encodedPng := base64.StdEncoding.EncodeToString(qrPng)
fullData := map[string]interface{}{
"qrCode": template.URL("data:image/png;base64," + encodedPng),
@@ -370,14 +357,60 @@ func (t *Registrar) buyPage(w http.ResponseWriter, r *http.Request) {
return
}
+func (t *Registrar) getCurrentRegistrationMetadata(label string, nsRecord *NamestoreRecord) (*RegistrationMetadata, error) {
+ var regMetadata RegistrationMetadata
+ var haveMetadata = false
+ for _, record := range nsRecord.Records {
+ if record.RecordType == "TXT" {
+ err := json.Unmarshal([]byte(record.Value), ®Metadata)
+ if err != nil {
+ fmt.Printf("Failed to get zone contents" + err.Error())
+ return nil, err
+ }
+ haveMetadata = true
+ }
+ }
+ if !haveMetadata {
+ return nil, nil
+ }
+ if !regMetadata.Paid {
+ payto, paytoErr := t.Merchant.IsOrderPaid(regMetadata.OrderID)
+ if nil != paytoErr {
+ return nil, errors.New("Error determining payment status")
+ }
+ if "" == payto {
+ // Order was paid!
+ regMetadata.Paid = true
+ for _, record := range nsRecord.Records {
+ if record.RecordType == "PKEY" {
+ record.IsPrivate = false
+ }
+ if record.RecordType == "TXT" {
+ metadataRecordValue, err := json.Marshal(regMetadata)
+ if nil != err {
+ return nil, err
+ }
+ record.Value = string(metadataRecordValue)
+ }
+ }
+ t.createOrUpdateRegistration(nsRecord)
+ } else {
+ if time.Now().After(regMetadata.NeedsPaymentUntil) {
+ t.expireRegistration(label)
+ return nil, nil
+ }
+ }
+ }
+ return ®Metadata, nil
+}
+
func (t *Registrar) namePage(w http.ResponseWriter, r *http.Request) {
- var metadataResponse RegistrationMetadata
var namestoreResponse NamestoreRecord
vars := mux.Vars(r)
w.Header().Set("Content-Type", "text/html; charset=utf-8")
- var available = false
var value = ""
- var registeredUntil = "unkown"
+ var registeredUntil = ""
+ var regMetadata *RegistrationMetadata
var registered = r.URL.Query().Get("registered") == "true"
// FIXME redirect back if label empty
resp, err := http.Get(t.GnunetUrl + "/namestore/" + t.RootZoneName + "/" + vars["label"] + "?include_maintenance=yes")
@@ -389,40 +422,40 @@ func (t *Registrar) namePage(w http.ResponseWriter, r *http.Request) {
if http.StatusOK == resp.StatusCode {
respData, err := io.ReadAll(resp.Body)
if err != nil {
- fmt.Printf("Failed to get zone contents" + err.Error())
+ fmt.Println("Failed to get zone contents: " + err.Error())
return
}
err = json.NewDecoder(bytes.NewReader(respData)).Decode(&namestoreResponse)
if err != nil {
- fmt.Printf("Failed to get zone contents" + err.Error())
+ fmt.Println("Failed to get zone contents: " + err.Error())
return
}
- for _, record := range namestoreResponse.Records {
- if record.RecordType == "PKEY" {
- value = record.Value
- }
- if record.RecordType == "TXT" {
- err = json.Unmarshal([]byte(record.Value), &metadataResponse)
- if err != nil {
- fmt.Printf("Failed to get zone contents" + err.Error())
- return
- }
- registeredUntil = time.UnixMicro(int64(metadataResponse.Expiration)).String()
- }
+ regMetadata, err = t.getCurrentRegistrationMetadata(vars["label"], &namestoreResponse)
+ if err != nil {
+ fmt.Println("Failed to get registration metadata: " + err.Error())
+ return
}
- } else {
- fmt.Printf("Failed to get zone contents" + err.Error())
+ } else if http.StatusNotFound != resp.StatusCode {
+ http.Redirect(w, r, "/name/" + vars["label"] + "?error=Error retrieving zone information.", http.StatusSeeOther)
return
}
- available = value == ""
+ for _, record := range namestoreResponse.Records {
+ if record.RecordType == "PKEY" {
+ value = record.Value
+ }
+ }
+ if regMetadata != nil {
+ if regMetadata.Paid {
+ registeredUntil = time.UnixMicro(int64(regMetadata.Expiration)).String()
+ }
+ }
fullData := map[string]interface{}{
"label": vars["label"],
"error": r.URL.Query().Get("error"),
"cost": t.RegistrationCost,
- "available": available,
+ "available": regMetadata == nil,
"currentValue": value,
"suffixHint": t.SuffixHint,
- "registrationPolicy": t.RegistrationPolicy,
"registeredUntil": registeredUntil,
"registrationSuccess": registered,
}
diff --git a/web/templates/name.html b/web/templates/name.html
@@ -32,25 +32,21 @@
<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>
<input class="btn btn-primary" type="submit" value="Register for {{.cost}}">
</div>
</form>
{{else}}
- <h1 class="mb-5"><i class="text-primary">{{.label}}</i> is already <span class="text-danger">taken</span>!</h1>
+ <h1 class="mb-5"><i class="text-primary">{{.label}}</i> is already <span class="text-danger">reserved</span>!</h1>
<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>
- {{if .modificationAllowed}}
- <input class="btn btn-primary" disabled="{{.modificationAllowed}}" type="submit" value="Update">
- {{end}}
</div>
</form>
- <form action="/renew" method="get" class="align-items-center">
- <span>Registration valid until: <i>{{.registeredUntil}}</i></span><br/>
- </form>
+ {{if ne .registeredUntil ""}}
+ <span>Registration valid until: <i>{{.registeredUntil}}</i></span><br/>
+ {{end}}
{{end}}
<a class="btn btn-primary mt-5" href="/">Back</a>
</div>