gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taldir] branch master updated (333bada -> 1940024)


From: gnunet
Subject: [taler-taldir] branch master updated (333bada -> 1940024)
Date: Mon, 18 Jul 2022 12:55:22 +0200

This is an automated email from the git hooks/post-receive script.

martin-schanzenbach pushed a change to branch master
in repository taldir.

    from 333bada  update sumodule, mod tidy
     new 07b4475  minor refactoring
     new 1940024  go fmt

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 cmd/taldir-cli/main.go         |   75 ++-
 cmd/taldir-server/main.go      |   34 +-
 cmd/taldir-server/main_test.go |  428 +++++++-------
 pkg/rest/taldir.go             | 1237 ++++++++++++++++++++--------------------
 pkg/taler/merchant.go          |  233 ++++----
 pkg/util/helper.go             |   94 ++-
 6 files changed, 1038 insertions(+), 1063 deletions(-)

diff --git a/cmd/taldir-cli/main.go b/cmd/taldir-cli/main.go
index 3aa9c32..83ba368 100644
--- a/cmd/taldir-cli/main.go
+++ b/cmd/taldir-cli/main.go
@@ -16,52 +16,51 @@
 //
 // SPDX-License-Identifier: AGPL3.0-or-later
 
-
 package main
 
 import (
-  "os"
-  "fmt"
-  "flag"
-  "taler.net/taldir/pkg/rest"
-  "taler.net/taldir/pkg/util"
-  gnunetutil "git.gnunet.org/gnunet-go.git/pkg/util"
-  "crypto/sha512"
+       "crypto/sha512"
+       "flag"
+       "fmt"
+       gnunetutil "git.gnunet.org/gnunet-go.git/pkg/util"
+       "os"
+       "taler.net/taldir/pkg/rest"
+       "taler.net/taldir/pkg/util"
 )
 
 // Generates a link from a challenge and address
 func generateLink(host string, addr string, challenge string) string {
-  h := sha512.New()
-  h.Write([]byte(addr))
-  h_addr := gnunetutil.EncodeBinaryToString(h.Sum(nil))
-  return host + "/register/" + h_addr + "/" + challenge
+       h := sha512.New()
+       h.Write([]byte(addr))
+       h_addr := gnunetutil.EncodeBinaryToString(h.Sum(nil))
+       return host + "/register/" + h_addr + "/" + challenge
 }
 
 func main() {
-  var solveFlag = flag.Bool("s", false, "Provide a solution for the 
challenge/pubkey")
-  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")
-  flag.Parse()
-  cfgfile := "taldir.conf"
-  t := taldir.Taldir{}
-  t.Initialize(cfgfile)
-  host := t.Cfg.Section("taldir").Key("host").MustString("http://localhost";)
-  if *solveFlag {
-    if len(*challengeFlag) == 0 || len(*pubkeyFlag) == 0 {
-      fmt.Println("You need to provide an activation challenge and a public 
key to generate a solution")
-      os.Exit(1)
-    }
-    fmt.Println(util.GenerateSolution(*pubkeyFlag, *challengeFlag))
-    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")
-      os.Exit(1)
-    }
-    fmt.Println(generateLink(host, *addressFlag, *challengeFlag))
-    os.Exit(0)
-  }
+       var solveFlag = flag.Bool("s", false, "Provide a solution for the 
challenge/pubkey")
+       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")
+       flag.Parse()
+       cfgfile := "taldir.conf"
+       t := taldir.Taldir{}
+       t.Initialize(cfgfile)
+       host := 
t.Cfg.Section("taldir").Key("host").MustString("http://localhost";)
+       if *solveFlag {
+               if len(*challengeFlag) == 0 || len(*pubkeyFlag) == 0 {
+                       fmt.Println("You need to provide an activation 
challenge and a public key to generate a solution")
+                       os.Exit(1)
+               }
+               fmt.Println(util.GenerateSolution(*pubkeyFlag, *challengeFlag))
+               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")
+                       os.Exit(1)
+               }
+               fmt.Println(generateLink(host, *addressFlag, *challengeFlag))
+               os.Exit(0)
+       }
 }
diff --git a/cmd/taldir-server/main.go b/cmd/taldir-server/main.go
index 205a7e6..9d1a1f6 100644
--- a/cmd/taldir-server/main.go
+++ b/cmd/taldir-server/main.go
@@ -16,7 +16,6 @@
 //
 // SPDX-License-Identifier: AGPL3.0-or-later
 
-
 package main
 
 /* TODO
@@ -28,19 +27,28 @@ package main
 */
 
 import (
-  "flag"
-  "taler.net/taldir/pkg/rest"
+       "flag"
+       "log"
+       "net/http"
+
+       taldir "taler.net/taldir/pkg/rest"
 )
 
+var t taldir.Taldir
+
+func handleRequests() {
+       
log.Fatal(http.ListenAndServe(t.Cfg.Section("taldir").Key("bind_to").MustString("localhost:11000"),
 t.Router))
+}
+
 func main() {
-  var cfgFlag = flag.String("c", "", "Configuration file to use")
-
-  flag.Parse()
-  cfgfile := "taldir.conf"
-  if len(*cfgFlag) != 0 {
-    cfgfile = *cfgFlag
-  }
-  t := taldir.Taldir{}
-  t.Initialize(cfgfile)
-  t.Run()
+       var cfgFlag = flag.String("c", "", "Configuration file to use")
+
+       flag.Parse()
+       cfgfile := "taldir.conf"
+       if len(*cfgFlag) != 0 {
+               cfgfile = *cfgFlag
+       }
+       t := taldir.Taldir{}
+       t.Initialize(cfgfile)
+       handleRequests()
 }
diff --git a/cmd/taldir-server/main_test.go b/cmd/taldir-server/main_test.go
index a61e425..ec475c8 100644
--- a/cmd/taldir-server/main_test.go
+++ b/cmd/taldir-server/main_test.go
@@ -16,23 +16,22 @@
 //
 // SPDX-License-Identifier: AGPL3.0-or-later
 
-
 package main_test
 
 import (
-  "os"
-  "testing"
-  "net/http"
-  "net/http/httptest"
-  "crypto/sha512"
-  "bytes"
-  "strings"
-  "io/ioutil"
-  "taler.net/taldir/pkg/rest"
-  _ "taler.net/taldir/cmd/taldir-server"
-  gnunetutil "git.gnunet.org/gnunet-go.git/pkg/util"
-  "github.com/jarcoal/httpmock"
-  "taler.net/taldir/pkg/util"
+       "bytes"
+       "crypto/sha512"
+       gnunetutil "git.gnunet.org/gnunet-go.git/pkg/util"
+       "github.com/jarcoal/httpmock"
+       "io/ioutil"
+       "net/http"
+       "net/http/httptest"
+       "os"
+       "strings"
+       _ "taler.net/taldir/cmd/taldir-server"
+       "taler.net/taldir/pkg/rest"
+       "taler.net/taldir/pkg/util"
+       "testing"
 )
 
 var t taldir.Taldir
@@ -70,253 +69,248 @@ var newOrderStatusUnpaidMockResponse = `
   }
 `
 
-
-
-
 func TestMain(m *testing.M) {
-  t.Initialize("testdata/taldir-test.conf")
-  code := m.Run()
-  t.ClearDatabase()
-  os.Exit(code)
+       t.Initialize("testdata/taldir-test.conf")
+       code := m.Run()
+       t.ClearDatabase()
+       os.Exit(code)
 }
 
 func getHAddress(addr string) string {
-  h := sha512.New()
-  h.Write([]byte(addr))
-  return gnunetutil.EncodeBinaryToString(h.Sum(nil))
+       h := sha512.New()
+       h.Write([]byte(addr))
+       return gnunetutil.EncodeBinaryToString(h.Sum(nil))
 }
 
 func TestNoEntry(s *testing.T) {
-    t.ClearDatabase()
+       t.ClearDatabase()
 
-    h_addr := getHAddress("jdoe@example.com")
-    req, _ := http.NewRequest("GET", "/" + h_addr, nil)
-    response := executeRequest(req)
+       h_addr := getHAddress("jdoe@example.com")
+       req, _ := http.NewRequest("GET", "/"+h_addr, nil)
+       response := executeRequest(req)
 
-    if http.StatusNotFound != response.Code {
-      s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, 
response.Code)
-    }
+       if http.StatusNotFound != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusNotFound, response.Code)
+       }
 }
 
 func executeRequest(req *http.Request) *httptest.ResponseRecorder {
-  rr := httptest.NewRecorder()
-  t.Router.ServeHTTP(rr, req)
-  return rr
+       rr := httptest.NewRecorder()
+       t.Router.ServeHTTP(rr, req)
+       return rr
 }
 
 func TestRegisterRequest(s *testing.T) {
-  t.ClearDatabase()
-
-  req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response := executeRequest(req)
-
-  if http.StatusAccepted != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, 
response.Code)
-  }
-  file, err := os.Open("validation_code")
-  if err != nil {
-    s.Errorf("No validation code file found!\n")
-  }
-  code, err := ioutil.ReadAll(file)
-  if err != nil {
-    s.Errorf("Error reading validation code file contents!\n")
-  }
-  h_addr := getHAddress("abc@test")
-  trimCode := strings.Trim(string(code), " \r\n")
-  solution := 
util.GenerateSolution("000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946A90",
 trimCode)
-  solutionJSON := "{\"solution\": \"" + solution + "\"}"
-  req, _ = http.NewRequest("POST", "/" + h_addr, 
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)
-  }
+       t.ClearDatabase()
+
+       req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response := executeRequest(req)
+
+       if http.StatusAccepted != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusAccepted, response.Code)
+       }
+       file, err := os.Open("validation_code")
+       if err != nil {
+               s.Errorf("No validation code file found!\n")
+       }
+       code, err := ioutil.ReadAll(file)
+       if err != nil {
+               s.Errorf("Error reading validation code file contents!\n")
+       }
+       h_addr := getHAddress("abc@test")
+       trimCode := strings.Trim(string(code), " \r\n")
+       solution := 
util.GenerateSolution("000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946A90",
 trimCode)
+       solutionJSON := "{\"solution\": \"" + solution + "\"}"
+       req, _ = http.NewRequest("POST", "/"+h_addr, 
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)
+       }
 }
 
 func TestRegisterQRPageRequest(s *testing.T) {
-  t.ClearDatabase()
-
-  req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response := executeRequest(req)
-
-  if http.StatusAccepted != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, 
response.Code)
-  }
-  req, _ = http.NewRequest("GET", "/register/NonSenseAddr/NonSenseCode", nil)
-  response = executeRequest(req)
-  if http.StatusNotFound != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, 
response.Code)
-  }
-
-  file, err := os.Open("validation_code")
-  if err != nil {
-    s.Errorf("No validation code file found!\n")
-  }
-  code, err := ioutil.ReadAll(file)
-  if err != nil {
-    s.Errorf("Error reading validation code file contents!\n")
-  }
-  h_addr := getHAddress("abc@test")
-  trimCode := strings.Trim(string(code), " \r\n")
-  req, _ = http.NewRequest("GET", "/register/" + h_addr + "/" + trimCode, nil)
-  response = executeRequest(req)
-  if http.StatusOK != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, 
response.Code)
-  }
+       t.ClearDatabase()
+
+       req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response := executeRequest(req)
+
+       if http.StatusAccepted != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusAccepted, response.Code)
+       }
+       req, _ = http.NewRequest("GET", "/register/NonSenseAddr/NonSenseCode", 
nil)
+       response = executeRequest(req)
+       if http.StatusNotFound != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusNotFound, response.Code)
+       }
+
+       file, err := os.Open("validation_code")
+       if err != nil {
+               s.Errorf("No validation code file found!\n")
+       }
+       code, err := ioutil.ReadAll(file)
+       if err != nil {
+               s.Errorf("Error reading validation code file contents!\n")
+       }
+       h_addr := getHAddress("abc@test")
+       trimCode := strings.Trim(string(code), " \r\n")
+       req, _ = http.NewRequest("GET", "/register/"+h_addr+"/"+trimCode, nil)
+       response = executeRequest(req)
+       if http.StatusOK != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, 
response.Code)
+       }
 }
 
-
 func TestReRegisterRequest(s *testing.T) {
-  t.ClearDatabase()
-
-  req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response := executeRequest(req)
-
-  if http.StatusAccepted != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, 
response.Code)
-  }
-  file, err := os.Open("validation_code")
-  if err != nil {
-    s.Errorf("No validation code file found!\n")
-  }
-  code, err := ioutil.ReadAll(file)
-  if err != nil {
-    s.Errorf("Error reading validation code file contents!\n")
-  }
-  h_addr := getHAddress("abc@test")
-  trimCode := strings.Trim(string(code), " \r\n")
-  solution := 
util.GenerateSolution("000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946A90",
 trimCode)
-  solutionJSON := "{\"solution\": \"" + solution + "\"}"
-  req, _ = http.NewRequest("POST", "/" + h_addr, 
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)
-  }
-  req, _ = http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequestUnmodified))
-  response = executeRequest(req)
-
-  if http.StatusOK != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, 
response.Code)
-  }
+       t.ClearDatabase()
+
+       req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response := executeRequest(req)
+
+       if http.StatusAccepted != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusAccepted, response.Code)
+       }
+       file, err := os.Open("validation_code")
+       if err != nil {
+               s.Errorf("No validation code file found!\n")
+       }
+       code, err := ioutil.ReadAll(file)
+       if err != nil {
+               s.Errorf("Error reading validation code file contents!\n")
+       }
+       h_addr := getHAddress("abc@test")
+       trimCode := strings.Trim(string(code), " \r\n")
+       solution := 
util.GenerateSolution("000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946A90",
 trimCode)
+       solutionJSON := "{\"solution\": \"" + solution + "\"}"
+       req, _ = http.NewRequest("POST", "/"+h_addr, 
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)
+       }
+       req, _ = http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequestUnmodified))
+       response = executeRequest(req)
+
+       if http.StatusOK != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, 
response.Code)
+       }
 
 }
 
 func TestReRegisterRequestTooMany(s *testing.T) {
-  t.ClearDatabase()
+       t.ClearDatabase()
 
-  req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response := executeRequest(req)
+       req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response := executeRequest(req)
 
-  if http.StatusAccepted != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, 
response.Code)
-  }
-  req, _ = http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response = executeRequest(req)
+       if http.StatusAccepted != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusAccepted, response.Code)
+       }
+       req, _ = http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response = executeRequest(req)
 
-  if http.StatusAccepted != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, 
response.Code)
-  }
-  req, _ = http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response = executeRequest(req)
+       if http.StatusAccepted != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusAccepted, response.Code)
+       }
+       req, _ = http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response = executeRequest(req)
 
-  if http.StatusAccepted != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, 
response.Code)
-  }
-  req, _ = http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response = executeRequest(req)
+       if http.StatusAccepted != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusAccepted, response.Code)
+       }
+       req, _ = http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response = executeRequest(req)
 
-  if http.StatusTooManyRequests != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", 
http.StatusTooManyRequests, response.Code)
-  }
+       if http.StatusTooManyRequests != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusTooManyRequests, response.Code)
+       }
 
 }
 
 func TestSolutionRequestTooMany(s *testing.T) {
-  t.ClearDatabase()
-
-  req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response := executeRequest(req)
-
-  if http.StatusAccepted != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, 
response.Code)
-  }
-  h_addr := getHAddress("abc@test")
-  solution := 
util.GenerateSolution("000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946A90",
 "wrongSolution")
-  solutionJSON := "{\"solution\": \"" + solution + "\"}"
-  req, _ = http.NewRequest("POST", "/" + h_addr, 
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)))
-  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)))
-  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)))
-  response = executeRequest(req)
-  if http.StatusTooManyRequests != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", 
http.StatusTooManyRequests, response.Code)
-  }
+       t.ClearDatabase()
+
+       req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response := executeRequest(req)
+
+       if http.StatusAccepted != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusAccepted, response.Code)
+       }
+       h_addr := getHAddress("abc@test")
+       solution := 
util.GenerateSolution("000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946A90",
 "wrongSolution")
+       solutionJSON := "{\"solution\": \"" + solution + "\"}"
+       req, _ = http.NewRequest("POST", "/"+h_addr, 
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)))
+       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)))
+       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)))
+       response = executeRequest(req)
+       if http.StatusTooManyRequests != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusTooManyRequests, response.Code)
+       }
 
 }
 
 func TestRegisterRequestWrongPubkey(s *testing.T) {
-  t.ClearDatabase()
-
-  req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
-  response := executeRequest(req)
-
-  if http.StatusAccepted != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, 
response.Code)
-  }
-  file, err := os.Open("validation_code")
-  if err != nil {
-    s.Errorf("No validation code file found!\n")
-  }
-  code, err := ioutil.ReadAll(file)
-  if err != nil {
-    s.Errorf("Error reading validation code file contents!\n")
-  }
-  h_addr := getHAddress("abc@test")
-  trimCode := strings.Trim(string(code), " \r\n")
-  solution := 
util.GenerateSolution("000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946AA0",
 trimCode)
-  solutionJSON := "{\"solution\": \"" + solution + "\"}"
-  req, _ = http.NewRequest("POST", "/" + h_addr, 
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)
-  }
+       t.ClearDatabase()
+
+       req, _ := http.NewRequest("POST", "/register/test", 
bytes.NewBuffer(validRegisterRequest))
+       response := executeRequest(req)
+
+       if http.StatusAccepted != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusAccepted, response.Code)
+       }
+       file, err := os.Open("validation_code")
+       if err != nil {
+               s.Errorf("No validation code file found!\n")
+       }
+       code, err := ioutil.ReadAll(file)
+       if err != nil {
+               s.Errorf("Error reading validation code file contents!\n")
+       }
+       h_addr := getHAddress("abc@test")
+       trimCode := strings.Trim(string(code), " \r\n")
+       solution := 
util.GenerateSolution("000G006XE97PTWV3B7AJNCRQZA6BF26HPV3XZ07293FMY7KD4181946AA0",
 trimCode)
+       solutionJSON := "{\"solution\": \"" + solution + "\"}"
+       req, _ = http.NewRequest("POST", "/"+h_addr, 
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) {
-  t.ClearDatabase()
+       t.ClearDatabase()
 
-  req, _ := http.NewRequest("POST", "/register/email", 
bytes.NewBuffer(validRegisterRequest))
-  response := executeRequest(req)
+       req, _ := http.NewRequest("POST", "/register/email", 
bytes.NewBuffer(validRegisterRequest))
+       response := executeRequest(req)
 
-  if http.StatusNotFound != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, 
response.Code)
-  }
+       if http.StatusNotFound != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusNotFound, response.Code)
+       }
 }
 
 func TestPaymentRequiredMethod(s *testing.T) {
-  t.ClearDatabase()
-  t.MonthlyFee = "KUDOS:5"
-  httpmock.Activate()
-  defer httpmock.DeactivateAndReset()
-  req, _ := http.NewRequest("POST", "/register/test-cost", 
bytes.NewBuffer(validRegisterRequest))
-  httpmock.RegisterResponder("POST", 
"http://merchant.taldir/instances/myInstance/private/orders";, 
httpmock.NewStringResponder(200, newOrderMockResponse))
-  httpmock.RegisterResponder("GET", 
"http://merchant.taldir/instances/myInstance/private/orders/testOrder1234";, 
httpmock.NewStringResponder(200, newOrderStatusUnpaidMockResponse))
-
-  response := executeRequest(req)
-  t.MonthlyFee = "KUDOS:0"
-  if http.StatusPaymentRequired != response.Code {
-    s.Errorf("Expected response code %d. Got %d\n", 
http.StatusPaymentRequired, response.Code)
-  }
+       t.ClearDatabase()
+       t.MonthlyFee = "KUDOS:5"
+       httpmock.Activate()
+       defer httpmock.DeactivateAndReset()
+       req, _ := http.NewRequest("POST", "/register/test-cost", 
bytes.NewBuffer(validRegisterRequest))
+       httpmock.RegisterResponder("POST", 
"http://merchant.taldir/instances/myInstance/private/orders";, 
httpmock.NewStringResponder(200, newOrderMockResponse))
+       httpmock.RegisterResponder("GET", 
"http://merchant.taldir/instances/myInstance/private/orders/testOrder1234";, 
httpmock.NewStringResponder(200, newOrderStatusUnpaidMockResponse))
+
+       response := executeRequest(req)
+       t.MonthlyFee = "KUDOS:0"
+       if http.StatusPaymentRequired != response.Code {
+               s.Errorf("Expected response code %d. Got %d\n", 
http.StatusPaymentRequired, response.Code)
+       }
 }
diff --git a/pkg/rest/taldir.go b/pkg/rest/taldir.go
index 5ede30f..afe23d9 100644
--- a/pkg/rest/taldir.go
+++ b/pkg/rest/taldir.go
@@ -19,140 +19,134 @@
 package taldir
 
 /* TODO
- - ToS API (terms, privacy) with localizions
- - ToS compression
- - ToS etag
- - Maintenance of database: When to delete expired validations?
-   Currently, we expire on startup 1 day old validations
+- ToS compression
+- ToS etag
 */
 
 import (
-  "os"
-  "os/exec"
-  "time"
-  "fmt"
-  "log"
-  "io/ioutil"
-  "mime"
-  "net/http"
-  "html/template"
-  "encoding/json"
-  "github.com/gorilla/mux"
-  "gorm.io/gorm"
-  "gorm.io/gorm/logger"
-  "encoding/base64"
-  "taler.net/taldir/pkg/util"
-  "taler.net/taldir/pkg/gana"
-  "taler.net/taldir/pkg/taler"
-  "crypto/sha512"
-  "gorm.io/driver/postgres"
-  "gopkg.in/ini.v1"
-  "strings"
-  "github.com/skip2/go-qrcode"
-  gnunetutil "git.gnunet.org/gnunet-go.git/pkg/util"
-  "golang.org/x/text/language"
+       "crypto/sha512"
+       "encoding/base64"
+       "encoding/json"
+       "fmt"
+       gnunetutil "git.gnunet.org/gnunet-go.git/pkg/util"
+       "github.com/gorilla/mux"
+       "github.com/skip2/go-qrcode"
+       "golang.org/x/text/language"
+       "gopkg.in/ini.v1"
+       "gorm.io/driver/postgres"
+       "gorm.io/gorm"
+       "gorm.io/gorm/logger"
+       "html/template"
+       "io/ioutil"
+       "log"
+       "mime"
+       "net/http"
+       "os"
+       "os/exec"
+       "strings"
+       "taler.net/taldir/pkg/gana"
+       "taler.net/taldir/pkg/taler"
+       "taler.net/taldir/pkg/util"
+       "time"
 )
 
 // Taldir is the primary object of the Taldir service
 type Taldir struct {
 
-  // The main router
-  Router *mux.Router
+       // The main router
+       Router *mux.Router
 
-  // The main DB handle
-  Db *gorm.DB
+       // The main DB handle
+       Db *gorm.DB
 
-  // Our configuration from the config.json
-  Cfg *ini.File
+       // Our configuration from the config.json
+       Cfg *ini.File
 
-  // Map of supported validators as defined in the configuration
-  Validators map[string]bool
+       // Map of supported validators as defined in the configuration
+       Validators map[string]bool
 
-  // landing page
-  ValidationTpl *template.Template
+       // landing page
+       ValidationTpl *template.Template
 
-  // The address salt
-  Salt string
+       // The address salt
+       Salt string
 
-  // The timeframe for the validation requests
-  ValidationTimeframe time.Duration
+       // The timeframe for the validation requests
+       ValidationTimeframe time.Duration
 
-  // How often may a challenge be requested
-  ValidationInitiationMax int64
+       // How often may a challenge be requested
+       ValidationInitiationMax int64
 
-  // How often may a solution be attempted (in the given timeframe)
-  SolutionAttemptsMax int
+       // How often may a solution be attempted (in the given timeframe)
+       SolutionAttemptsMax int
 
-  // The timeframe for the above solution attempts
-  SolutionTimeframe time.Duration
+       // The timeframe for the above solution attempts
+       SolutionTimeframe time.Duration
 
+       // Challenge length in bytes before encoding
+       ChallengeBytes int
 
-  // Challenge length in bytes before encoding
-  ChallengeBytes int
+       // Merchant object
+       Merchant taler.Merchant
 
-  // Merchant object
-  Merchant taler.Merchant
-
-  // Monthly fee amount
-  MonthlyFee string
+       // Monthly fee amount
+       MonthlyFee string
 }
 
 // VersionResponse is the JSON response of the /config enpoint
 type VersionResponse struct {
-  // libtool-style representation of the Merchant protocol version, see
-  // 
https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
-  // The format is "current:revision:age".
-  Version string `json:"version"`
-
-  // Name of the protocol.
-  Name string `json:"name"` // "taler-directory"
+       // libtool-style representation of the Merchant protocol version, see
+       // 
https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+       // The format is "current:revision:age".
+       Version string `json:"version"`
 
-  // Supported registration methods
-  Methods []Method `json:"methods"`
+       // Name of the protocol.
+       Name string `json:"name"` // "taler-directory"
 
-  // fee for one month of registration
-  MonthlyFee string `json:"monthly_fee"`
+       // Supported registration methods
+       Methods []Method `json:"methods"`
 
+       // 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 {
 
-  // Name of the method, e.g. "email" or "sms".
-  Name string `json:"name"`
-
-  // per challenge fee
-  ChallengeFee string `json:"challenge_fee"`
+       // Name of the method, e.g. "email" or "sms".
+       Name string `json:"name"`
 
+       // per challenge fee
+       ChallengeFee string `json:"challenge_fee"`
 }
 
 // RateLimitedResponse is the JSON response when a rate limit is hit
 type RateLimitedResponse struct {
 
-  // Taler error code, TALER_EC_TALDIR_REGISTER_RATE_LIMITED.
-  Code int `json:"code"`
+       // Taler error code, TALER_EC_TALDIR_REGISTER_RATE_LIMITED.
+       Code int `json:"code"`
 
-  // At what frequency are new registrations allowed. FIXME: In what? 
Currently: In microseconds
-  RequestFrequency int64 `json:"request_frequency"`
+       // At what frequency are new registrations allowed. FIXME: In what? 
Currently: In microseconds
+       RequestFrequency int64 `json:"request_frequency"`
 
-  // The human readable error message.
-  Hint string `json:"hint"`
+       // The human readable error message.
+       Hint string `json:"hint"`
 }
 
 // RegisterMessage is the JSON paylaod when a registration is requested
 type RegisterMessage struct {
 
-  // Address, in method-specific format
-  Address string `json:"address"`
+       // Address, in method-specific format
+       Address string `json:"address"`
 
-  // Public key of the user to register
-  PublicKey string `json:"public_key"`
+       // Public key of the user to register
+       PublicKey string `json:"public_key"`
 
-  // (HTTPS) endpoint URL for the inbox service for this address
-  Inbox string `json:"inbox_url"`
+       // (HTTPS) endpoint URL for the inbox service for this address
+       Inbox string `json:"inbox_url"`
 
-  // For how long should the registration last
-  Duration int64 `json:"duration"`
+       // For how long should the registration last
+       Duration int64 `json:"duration"`
 }
 
 // Entry is a mapping from the identity key hash to a wallet key
@@ -160,20 +154,20 @@ type RegisterMessage struct {
 // one of the identity key types supported (e.g. an email address)
 type entry struct {
 
-  // ORM
-  gorm.Model  `json:"-"`
+       // ORM
+       gorm.Model `json:"-"`
 
-  // The salted hash (SHA512) of the hashed address (h_address)
-  HsAddress string `json:"-"`
+       // The salted hash (SHA512) of the hashed address (h_address)
+       HsAddress string `json:"-"`
 
-  // (HTTPS) endpoint URL for the inbox service for this address
-  Inbox string `json:"inbox_url"`
+       // (HTTPS) endpoint URL for the inbox service for this address
+       Inbox string `json:"inbox_url"`
 
-  // Public key of the user to register in base32
-  PublicKey string `json:"public_key"`
+       // Public key of the user to register in base32
+       PublicKey string `json:"public_key"`
 
-  // How long the registration lasts in microseconds
-  Duration time.Duration `json:"-"`
+       // How long the registration lasts in microseconds
+       Duration time.Duration `json:"-"`
 }
 
 // Validation is the object created when a registration for an entry is 
initiated.
@@ -182,86 +176,85 @@ type entry struct {
 // depending on the out-of-band chennel defined through the identity key type.
 type validation struct {
 
-  // ORM
-  gorm.Model `json:"-"`
+       // ORM
+       gorm.Model `json:"-"`
 
-  // The hash (SHA512) of the address
-  HAddress string `json:"h_address"`
+       // The hash (SHA512) of the address
+       HAddress string `json:"h_address"`
 
-  // For how long should the registration last
-  Duration int64 `json:"duration"`
+       // For how long should the registration last
+       Duration int64 `json:"duration"`
 
-  // (HTTPS) endpoint URL for the inbox service for this address
-  Inbox string `json:"inbox_url"`
+       // (HTTPS) endpoint URL for the inbox service for this address
+       Inbox string `json:"inbox_url"`
 
-  // The activation code sent to the client
-  Challenge string `json:"-"`
+       // The activation code sent to the client
+       Challenge string `json:"-"`
 
-  // The challenge has been sent already
-  ChallengeSent bool `json:"-"`
+       // The challenge has been sent already
+       ChallengeSent bool `json:"-"`
 
-  // Public key of the user to register
-  PublicKey string `json:"public_key"`
+       // Public key of the user to register
+       PublicKey string `json:"public_key"`
 
-  // How often was a solution for this validation tried
-  SolutionAttemptCount int
+       // How often was a solution for this validation tried
+       SolutionAttemptCount int
 
-  // The beginning of the last solution timeframe
-  LastSolutionTimeframeStart time.Time
+       // The beginning of the last solution timeframe
+       LastSolutionTimeframeStart time.Time
 
-  // The order ID associated with this validation
-  OrderID string `json:"-"`
+       // The order ID associated with this validation
+       OrderID string `json:"-"`
 }
 
-
 // ErrorDetail is the detailed error payload returned from Taldir endpoints
 type ErrorDetail struct {
 
-  // Numeric error code unique to the condition.
-  // The other arguments are specific to the error value reported here.
-  Code int `json:"code"`
+       // Numeric error code unique to the condition.
+       // The other arguments are specific to the error value reported here.
+       Code int `json:"code"`
 
-  // Human-readable description of the error, i.e. "missing parameter", 
"commitment violation", ...
-  // Should give a human-readable hint about the error's nature. Optional, may 
change without notice!
-  Hint string `json:"hint,omitempty"`
+       // Human-readable description of the error, i.e. "missing parameter", 
"commitment violation", ...
+       // Should give a human-readable hint about the error's nature. 
Optional, may change without notice!
+       Hint string `json:"hint,omitempty"`
 
-  // Optional detail about the specific input value that failed. May change 
without notice!
-  Detail string `json:"detail,omitempty"`
+       // Optional detail about the specific input value that failed. May 
change without notice!
+       Detail string `json:"detail,omitempty"`
 
-  // Name of the parameter that was bogus (if applicable).
-  Parameter string `json:"parameter,omitempty"`
+       // Name of the parameter that was bogus (if applicable).
+       Parameter string `json:"parameter,omitempty"`
 
-  // Path to the argument that was bogus (if applicable).
-  Path string `json:"path,omitempty"`
+       // Path to the argument that was bogus (if applicable).
+       Path string `json:"path,omitempty"`
 
-  // Offset of the argument that was bogus (if applicable).
-  Offset string `json:"offset,omitempty"`
+       // Offset of the argument that was bogus (if applicable).
+       Offset string `json:"offset,omitempty"`
 
-  // Index of the argument that was bogus (if applicable).
-  Index string `json:"index,omitempty"`
+       // Index of the argument that was bogus (if applicable).
+       Index string `json:"index,omitempty"`
 
-  // Name of the object that was bogus (if applicable).
-  Object string `json:"object,omitempty"`
+       // Name of the object that was bogus (if applicable).
+       Object string `json:"object,omitempty"`
 
-  // Name of the currency than was problematic (if applicable).
-  Currency string `json:"currency,omitempty"`
+       // Name of the currency than was problematic (if applicable).
+       Currency string `json:"currency,omitempty"`
 
-  // Expected type (if applicable).
-  TypeExpected string `json:"type_expected,omitempty"`
+       // Expected type (if applicable).
+       TypeExpected string `json:"type_expected,omitempty"`
 
-  // Type that was provided instead (if applicable).
-  TypeActual string `json:"type_actual,omitempty"`
+       // Type that was provided instead (if applicable).
+       TypeActual string `json:"type_actual,omitempty"`
 }
 
 // ValidationConfirmation is the payload sent by the client t complete a
 // registration.
 type ValidationConfirmation struct {
-  // The solution is the SHA-512 hash of the challenge value
-  // chosen by TalDir (encoded as string just as given in the URL, but
-  // excluding the 0-termination) concatenated with the binary 32-byte
-  // value representing the wallet's EdDSA public key.
-  // The hash is provided as string in Crockford base32 encoding.
-  Solution string `json:"solution"`
+       // The solution is the SHA-512 hash of the challenge value
+       // chosen by TalDir (encoded as string just as given in the URL, but
+       // excluding the 0-termination) concatenated with the binary 32-byte
+       // value representing the wallet's EdDSA public key.
+       // The hash is provided as string in Crockford base32 encoding.
+       Solution string `json:"solution"`
 }
 
 // NOTE: Go stores durations as nanoseconds. TalDir usually operates on 
microseconds
@@ -270,530 +263,518 @@ const monthDurationUs = 2592000000000
 // 1 Month as Go duration
 const monthDuration = time.Duration(monthDurationUs * 1000)
 
-
 // Primary lookup function.
 // Allows the caller to query a wallet key using the hash(!) of the
 // identity, e.g. SHA512(<email address>)
-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
-  if err == nil {
-    w.Header().Set("Content-Type", "application/json")
-    resp, _ := json.Marshal(entry)
-    w.Write(resp)
-    return
-  }
-  w.WriteHeader(http.StatusNotFound)
+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
+       if err == nil {
+               w.Header().Set("Content-Type", "application/json")
+               resp, _ := json.Marshal(entry)
+               w.Write(resp)
+               return
+       }
+       w.WriteHeader(http.StatusNotFound)
 }
 
 // Hashes an identity key (e.g. sha256(<email address>)) with a salt for
 // Lookup and storage.
 func saltHAddress(hAddress string, salt string) string {
-  h := sha512.New()
-  h.Write([]byte(hAddress))
-  h.Write([]byte(salt))
-  return gnunetutil.EncodeBinaryToString(h.Sum(nil))
+       h := sha512.New()
+       h.Write([]byte(hAddress))
+       h.Write([]byte(salt))
+       return gnunetutil.EncodeBinaryToString(h.Sum(nil))
 }
 
 // Called by the registrant to validate the registration request. The 
reference ID was
 // provided "out of band" using a validation method such as email or SMS
-func (t *Taldir) validationRequest(w http.ResponseWriter, r *http.Request){
-  vars := mux.Vars(r)
-  var entry entry
-  var validation validation
-  var confirm ValidationConfirmation
-  var errDetail ErrorDetail
-  if r.Body == nil {
-    http.Error(w, "No request body", 400)
-    return
-  }
-  err := json.NewDecoder(r.Body).Decode(&confirm)
-  if err != nil {
-    errDetail.Code = 1006 //TALER_EC_JSON_INVALID
-    errDetail.Hint = "Unable to parse JSON"
-    resp, _ := json.Marshal(errDetail)
-    w.WriteHeader(400)
-    w.Write(resp)
-    return
-  }
-  err = t.Db.First(&validation, "h_address = ?", vars["h_address"]).Error
-  if err != nil {
-    w.WriteHeader(http.StatusNotFound)
-    return
-  }
-  validation.SolutionAttemptCount++
-  if 
validation.LastSolutionTimeframeStart.Add(t.SolutionTimeframe).After(time.Now())
 {
-    if validation.SolutionAttemptCount > t.SolutionAttemptsMax {
-      w.WriteHeader(429)
-      return
-    }
-  } else {
-    log.Println("New solution timeframe set.")
-    validation.LastSolutionTimeframeStart = time.Now()
-    validation.SolutionAttemptCount = 1
-  }
-  t.Db.Save(&validation)
-  expectedSolution := util.GenerateSolution(validation.PublicKey, 
validation.Challenge)
-  if confirm.Solution != expectedSolution {
-    w.WriteHeader(http.StatusForbidden)
-    return
-  }
-  err = t.Db.Delete(&validation).Error
-  if err != nil {
-    log.Fatalf("Error deleting validation")
-    w.WriteHeader(http.StatusInternalServerError)
-    return
-  }
-  entry.HsAddress = saltHAddress(validation.HAddress, t.Salt)
-  entry.Inbox = validation.Inbox
-  tmpDuration := (entry.Duration.Microseconds() + validation.Duration) * 1000
-  entry.Duration = time.Duration(tmpDuration)
-  entry.PublicKey = validation.PublicKey
-  err = t.Db.First(&entry, "hs_address = ?", entry.HsAddress).Error
-  if err == nil {
-    t.Db.Save(&entry)
-  } else {
-    err = t.Db.Create(&entry).Error
-    if err != nil {
-      w.WriteHeader(http.StatusInternalServerError)
-      return
-    }
-  }
-  w.WriteHeader(http.StatusNoContent)
+func (t *Taldir) validationRequest(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+       var entry entry
+       var validation validation
+       var confirm ValidationConfirmation
+       var errDetail ErrorDetail
+       if r.Body == nil {
+               http.Error(w, "No request body", 400)
+               return
+       }
+       err := json.NewDecoder(r.Body).Decode(&confirm)
+       if err != nil {
+               errDetail.Code = 1006 //TALER_EC_JSON_INVALID
+               errDetail.Hint = "Unable to parse JSON"
+               resp, _ := json.Marshal(errDetail)
+               w.WriteHeader(400)
+               w.Write(resp)
+               return
+       }
+       err = t.Db.First(&validation, "h_address = ?", vars["h_address"]).Error
+       if err != nil {
+               w.WriteHeader(http.StatusNotFound)
+               return
+       }
+       validation.SolutionAttemptCount++
+       if 
validation.LastSolutionTimeframeStart.Add(t.SolutionTimeframe).After(time.Now())
 {
+               if validation.SolutionAttemptCount > t.SolutionAttemptsMax {
+                       w.WriteHeader(429)
+                       return
+               }
+       } else {
+               log.Println("New solution timeframe set.")
+               validation.LastSolutionTimeframeStart = time.Now()
+               validation.SolutionAttemptCount = 1
+       }
+       t.Db.Save(&validation)
+       expectedSolution := util.GenerateSolution(validation.PublicKey, 
validation.Challenge)
+       if confirm.Solution != expectedSolution {
+               w.WriteHeader(http.StatusForbidden)
+               return
+       }
+       err = t.Db.Delete(&validation).Error
+       if err != nil {
+               log.Fatalf("Error deleting validation")
+               w.WriteHeader(http.StatusInternalServerError)
+               return
+       }
+       entry.HsAddress = saltHAddress(validation.HAddress, t.Salt)
+       entry.Inbox = validation.Inbox
+       tmpDuration := (entry.Duration.Microseconds() + validation.Duration) * 
1000
+       entry.Duration = time.Duration(tmpDuration)
+       entry.PublicKey = validation.PublicKey
+       err = t.Db.First(&entry, "hs_address = ?", entry.HsAddress).Error
+       if err == nil {
+               t.Db.Save(&entry)
+       } else {
+               err = t.Db.Create(&entry).Error
+               if err != nil {
+                       w.WriteHeader(http.StatusInternalServerError)
+                       return
+               }
+       }
+       w.WriteHeader(http.StatusNoContent)
 }
 
 func (t *Taldir) isRateLimited(hAddress string) (bool, error) {
-  var validations []validation
-  res := t.Db.Where("h_address = ?", hAddress).Find(&validations)
-  // NOTE: Check rate limit
-  if res.Error == nil {
-    // Limit re-initiation attempts to ValidationInitiationMax times
-    // within the expiration timeframe of a validation.
-    return res.RowsAffected >= t.ValidationInitiationMax, nil
-  }
-  return false, nil
+       var validations []validation
+       res := t.Db.Where("h_address = ?", hAddress).Find(&validations)
+       // NOTE: Check rate limit
+       if res.Error == nil {
+               // Limit re-initiation attempts to ValidationInitiationMax times
+               // within the expiration timeframe of a validation.
+               return res.RowsAffected >= t.ValidationInitiationMax, nil
+       }
+       return false, nil
 }
 
-func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request){
-  vars := mux.Vars(r)
-  var req RegisterMessage
-  var errDetail ErrorDetail
-  var validation validation
-  var entry entry
-  // Check if this validation method is supported or not.
-  if !t.Validators[vars["method"]] {
-    errDetail.Code = gana.TALDIR_METHOD_NOT_SUPPORTED
-    errDetail.Hint = "Unsupported method"
-    errDetail.Detail = "Given method: " + vars["method"]
-    resp, _ := json.Marshal(errDetail)
-    w.WriteHeader(http.StatusNotFound)
-    w.Write(resp)
-    return
-  }
-  if r.Body == nil {
-    http.Error(w, "No request body", 400)
-    return
-  }
-  err := json.NewDecoder(r.Body).Decode(&req)
-  if err != nil {
-    errDetail.Code = gana.GENERIC_JSON_INVALID
-    errDetail.Hint = "Unable to parse JSON"
-    resp, _ := json.Marshal(errDetail)
-    w.WriteHeader(400)
-    w.Write(resp)
-    return
-  }
-
-  // Setup validation object. Retrieve object from DB if it already
-  // exists.
-  h := sha512.New()
-  h.Write([]byte(req.Address))
-  hAddress := gnunetutil.EncodeBinaryToString(h.Sum(nil))
-  validation.HAddress = hAddress
-  hsAddress := saltHAddress(validation.HAddress, t.Salt)
-  err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error
-  // Round to the nearest multiple of a month
-  reqDuration := time.Duration(req.Duration * 1000)
-  reqDuration = reqDuration.Round(monthDuration)
-  if err == nil {
-    // Check if  this entry is to be modified or extended
-    entryModified := (req.Inbox != entry.Inbox) ||
-                     (req.PublicKey != entry.PublicKey)
-    entryValidity := entry.CreatedAt.Add(entry.Duration)
-    // NOTE: The extension must be at least one month
-    if (reqDuration.Microseconds() == 0) && !entryModified {
-      // Nothing changed. Return validity
-      w.WriteHeader(http.StatusOK)
-      w.Header().Set("Content-Type", "application/json")
-      w.Write([]byte(fmt.Sprintf("{\"valid_for\": %d}", 
time.Until(entryValidity).Microseconds())))
-      return
-    }
-  }
-  rateLimited, err := t.isRateLimited(hAddress)
-  if nil != err {
-    log.Printf("Error checking rate limit! %w", err)
-    w.WriteHeader(http.StatusInternalServerError)
-    return
-  } else if rateLimited {
-    w.WriteHeader(http.StatusTooManyRequests)
-    rlResponse := RateLimitedResponse{
-      Code: gana.TALDIR_REGISTER_RATE_LIMITED,
-      RequestFrequency: t.ValidationTimeframe.Microseconds() / 
t.ValidationInitiationMax,
-      Hint: "Registration rate limit reached",
-    }
-    jsonResp, _ := json.Marshal(rlResponse)
-    w.Write(jsonResp)
-    t.Db.Delete(&validation)
-    return
-  }
-  err = t.Db.First(&validation, "h_address = ? AND public_key = ? AND inbox = 
? AND duration = ?",
-                                hAddress, req.PublicKey, req.Inbox, 
reqDuration).Error
-  validationExists := (nil == err)
-  // FIXME: Always set new challenge?
-  validation.Challenge = util.GenerateChallenge(t.ChallengeBytes)
-  if !validationExists {
-    validation.Inbox = req.Inbox
-    validation.PublicKey = req.PublicKey
-    validation.SolutionAttemptCount = 0
-    validation.LastSolutionTimeframeStart = time.Now()
-    validation.Duration = reqDuration.Microseconds()
-  }
-
-  fixedCost := t.Cfg.Section("taldir-" + 
vars["method"]).Key("challenge_fee").MustString("KUDOS:0")
-  sliceDuration := time.Duration(validation.Duration * 1000)
-  cost, err := util.CalculateCost(t.MonthlyFee,
-                                  fixedCost,
-                                  sliceDuration,
-                                  monthDuration)
-  if err != nil {
-    fmt.Println(err)
-    w.WriteHeader(http.StatusInternalServerError)
-    return
-  }
-  if !cost.IsZero() {
-    if len(validation.OrderID) == 0 {
-      // Add new order for new validations
-      orderID, newOrderErr := t.Merchant.AddNewOrder(*cost)
-      if newOrderErr != nil {
-        fmt.Println(newOrderErr)
-        w.WriteHeader(http.StatusInternalServerError)
-        return
-      }
-      validation.OrderID = orderID
-    }
-
-    // Check if order paid.
-    // FIXME: Remember that it was activated and paid
-    payto, paytoErr := t.Merchant.IsOrderPaid(validation.OrderID)
-    if paytoErr != nil {
-      fmt.Println(paytoErr)
-      w.WriteHeader(http.StatusInternalServerError)
-      log.Println(paytoErr)
-      return
-    }
-    if len(payto) != 0 {
-      t.Db.Save(&validation)
-      w.WriteHeader(http.StatusPaymentRequired)
-      w.Header().Set("Taler", payto) // FIXME no idea what to do with this.
-      return
-    }
-    // In this case, this order was paid
-  }
-  if validationExists {
-    err = t.Db.Save(&validation).Error
-  } else {
-    err = t.Db.Create(&validation).Error
-  }
-  if err != nil {
-    log.Println(err)
-    w.WriteHeader(500)
-    return
-  }
-  // Some validation methods are costly
-  // Require explicit whitelisting for a resend.
-  if validation.ChallengeSent &&
-     !t.Cfg.Section("taldir-" + 
vars["method"]).Key("allow_resend").MustBool(false) {
-    w.WriteHeader(202)
-    return
-  }
-  if !t.Cfg.Section("taldir-" + vars["method"]).HasKey("command") {
-    log.Fatal(err)
-    t.Db.Delete(&validation)
-    w.WriteHeader(500)
-    return
-  }
-  command := t.Cfg.Section("taldir-" + vars["method"]).Key("command").String()
-  path, err := exec.LookPath(command)
-  if err != nil {
-    log.Println(err)
-    t.Db.Delete(&validation)
-    w.WriteHeader(500)
-    return
-  }
-  out, err := exec.Command(path, req.Address, validation.Challenge).Output()
-  if err != nil {
-    log.Printf("%s, %w", out, err)
-    t.Db.Delete(&validation)
-    w.WriteHeader(500)
-    return
-  }
-  validation.ChallengeSent = true
-  w.WriteHeader(202)
+func (t *Taldir) registerRequest(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+       var req RegisterMessage
+       var errDetail ErrorDetail
+       var validation validation
+       var entry entry
+       // Check if this validation method is supported or not.
+       if !t.Validators[vars["method"]] {
+               errDetail.Code = gana.TALDIR_METHOD_NOT_SUPPORTED
+               errDetail.Hint = "Unsupported method"
+               errDetail.Detail = "Given method: " + vars["method"]
+               resp, _ := json.Marshal(errDetail)
+               w.WriteHeader(http.StatusNotFound)
+               w.Write(resp)
+               return
+       }
+       if r.Body == nil {
+               http.Error(w, "No request body", 400)
+               return
+       }
+       err := json.NewDecoder(r.Body).Decode(&req)
+       if err != nil {
+               errDetail.Code = gana.GENERIC_JSON_INVALID
+               errDetail.Hint = "Unable to parse JSON"
+               resp, _ := json.Marshal(errDetail)
+               w.WriteHeader(400)
+               w.Write(resp)
+               return
+       }
+
+       // Setup validation object. Retrieve object from DB if it already
+       // exists.
+       h := sha512.New()
+       h.Write([]byte(req.Address))
+       hAddress := gnunetutil.EncodeBinaryToString(h.Sum(nil))
+       validation.HAddress = hAddress
+       hsAddress := saltHAddress(validation.HAddress, t.Salt)
+       err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error
+       // Round to the nearest multiple of a month
+       reqDuration := time.Duration(req.Duration * 1000)
+       reqDuration = reqDuration.Round(monthDuration)
+       if err == nil {
+               // Check if  this entry is to be modified or extended
+               entryModified := (req.Inbox != entry.Inbox) ||
+                       (req.PublicKey != entry.PublicKey)
+               entryValidity := entry.CreatedAt.Add(entry.Duration)
+               // NOTE: The extension must be at least one month
+               if (reqDuration.Microseconds() == 0) && !entryModified {
+                       // Nothing changed. Return validity
+                       w.WriteHeader(http.StatusOK)
+                       w.Header().Set("Content-Type", "application/json")
+                       w.Write([]byte(fmt.Sprintf("{\"valid_for\": %d}", 
time.Until(entryValidity).Microseconds())))
+                       return
+               }
+       }
+       rateLimited, err := t.isRateLimited(hAddress)
+       if nil != err {
+               log.Printf("Error checking rate limit! %w", err)
+               w.WriteHeader(http.StatusInternalServerError)
+               return
+       } else if rateLimited {
+               w.WriteHeader(http.StatusTooManyRequests)
+               rlResponse := RateLimitedResponse{
+                       Code:             gana.TALDIR_REGISTER_RATE_LIMITED,
+                       RequestFrequency: t.ValidationTimeframe.Microseconds() 
/ t.ValidationInitiationMax,
+                       Hint:             "Registration rate limit reached",
+               }
+               jsonResp, _ := json.Marshal(rlResponse)
+               w.Write(jsonResp)
+               t.Db.Delete(&validation)
+               return
+       }
+       err = t.Db.First(&validation, "h_address = ? AND public_key = ? AND 
inbox = ? AND duration = ?",
+               hAddress, req.PublicKey, req.Inbox, reqDuration).Error
+       validationExists := (nil == err)
+       // FIXME: Always set new challenge?
+       validation.Challenge = util.GenerateChallenge(t.ChallengeBytes)
+       if !validationExists {
+               validation.Inbox = req.Inbox
+               validation.PublicKey = req.PublicKey
+               validation.SolutionAttemptCount = 0
+               validation.LastSolutionTimeframeStart = time.Now()
+               validation.Duration = reqDuration.Microseconds()
+       }
+
+       fixedCost := t.Cfg.Section("taldir-" + 
vars["method"]).Key("challenge_fee").MustString("KUDOS:0")
+       sliceDuration := time.Duration(validation.Duration * 1000)
+       cost, err := util.CalculateCost(t.MonthlyFee,
+               fixedCost,
+               sliceDuration,
+               monthDuration)
+       if err != nil {
+               fmt.Println(err)
+               w.WriteHeader(http.StatusInternalServerError)
+               return
+       }
+       if !cost.IsZero() {
+               if len(validation.OrderID) == 0 {
+                       // Add new order for new validations
+                       orderID, newOrderErr := t.Merchant.AddNewOrder(*cost)
+                       if newOrderErr != nil {
+                               fmt.Println(newOrderErr)
+                               w.WriteHeader(http.StatusInternalServerError)
+                               return
+                       }
+                       validation.OrderID = orderID
+               }
+
+               // Check if order paid.
+               // FIXME: Remember that it was activated and paid
+               payto, paytoErr := t.Merchant.IsOrderPaid(validation.OrderID)
+               if paytoErr != nil {
+                       fmt.Println(paytoErr)
+                       w.WriteHeader(http.StatusInternalServerError)
+                       log.Println(paytoErr)
+                       return
+               }
+               if len(payto) != 0 {
+                       t.Db.Save(&validation)
+                       w.WriteHeader(http.StatusPaymentRequired)
+                       w.Header().Set("Taler", payto) // FIXME no idea what to 
do with this.
+                       return
+               }
+               // In this case, this order was paid
+       }
+       if validationExists {
+               err = t.Db.Save(&validation).Error
+       } else {
+               err = t.Db.Create(&validation).Error
+       }
+       if err != nil {
+               log.Println(err)
+               w.WriteHeader(500)
+               return
+       }
+       // Some validation methods are costly
+       // Require explicit whitelisting for a resend.
+       if validation.ChallengeSent &&
+               
!t.Cfg.Section("taldir-"+vars["method"]).Key("allow_resend").MustBool(false) {
+               w.WriteHeader(202)
+               return
+       }
+       if !t.Cfg.Section("taldir-" + vars["method"]).HasKey("command") {
+               log.Fatal(err)
+               t.Db.Delete(&validation)
+               w.WriteHeader(500)
+               return
+       }
+       command := t.Cfg.Section("taldir-" + 
vars["method"]).Key("command").String()
+       path, err := exec.LookPath(command)
+       if err != nil {
+               log.Println(err)
+               t.Db.Delete(&validation)
+               w.WriteHeader(500)
+               return
+       }
+       out, err := exec.Command(path, req.Address, 
validation.Challenge).Output()
+       if err != nil {
+               log.Printf("%s, %w", out, err)
+               t.Db.Delete(&validation)
+               w.WriteHeader(500)
+               return
+       }
+       validation.ChallengeSent = true
+       w.WriteHeader(202)
 }
 
 func (t *Taldir) configResponse(w http.ResponseWriter, r *http.Request) {
-  meths := []Method{}
-  i := 0
-  for key := range t.Validators {
-    var meth Method
-    meth.Name = key
-    meth.ChallengeFee = t.Cfg.Section("taldir-" + 
key).Key("challenge_fee").MustString("KUDOS:1")
-    i++
-    meths = append(meths, meth)
-  }
-  cfg := VersionResponse{
-    Version: "0:0:0",
-    Name: "taler-directory",
-    MonthlyFee: 
t.Cfg.Section("taldir").Key("monthly_fee").MustString("KUDOS:1"),
-    Methods: meths,
-  }
-  w.Header().Set("Content-Type", "application/json")
-  response, _ := json.Marshal(cfg)
-  w.Write(response)
+       meths := []Method{}
+       i := 0
+       for key := range t.Validators {
+               var meth Method
+               meth.Name = key
+               meth.ChallengeFee = t.Cfg.Section("taldir-" + 
key).Key("challenge_fee").MustString("KUDOS:1")
+               i++
+               meths = append(meths, meth)
+       }
+       cfg := VersionResponse{
+               Version:    "0:0:0",
+               Name:       "taler-directory",
+               MonthlyFee: 
t.Cfg.Section("taldir").Key("monthly_fee").MustString("KUDOS:1"),
+               Methods:    meths,
+       }
+       w.Header().Set("Content-Type", "application/json")
+       response, _ := json.Marshal(cfg)
+       w.Write(response)
 }
 
 func (t *Taldir) validationPage(w http.ResponseWriter, r *http.Request) {
-  vars := mux.Vars(r)
-  var walletLink string
-  var png []byte
-  var validation validation
-
-  err := t.Db.First(&validation, "h_address = ?", vars["h_address"]).Error
-  w.Header().Set("Content-Type", "text/html; charset=utf-8")
-  if err != nil {
-    // This validation does not exist.
-    w.WriteHeader(404)
-    return
-  }
-
-  walletLink = "taler://taldir/" + vars["h_address"] + "/" + vars["challenge"] 
+ "-wallet"
-  png, err = qrcode.Encode(walletLink, qrcode.Medium, 256)
-  if err != nil {
-    w.WriteHeader(500)
-    return
-  }
-  encodedPng := base64.StdEncoding.EncodeToString(png)
-
-  fullData := map[string]interface{}{
-    "QRCode": template.URL("data:image/png;base64," + encodedPng),
-    "WalletLink": template.URL(walletLink),
-  }
-  t.ValidationTpl.Execute(w, fullData)
-  return
+       vars := mux.Vars(r)
+       var walletLink string
+       var png []byte
+       var validation validation
+
+       err := t.Db.First(&validation, "h_address = ?", vars["h_address"]).Error
+       w.Header().Set("Content-Type", "text/html; charset=utf-8")
+       if err != nil {
+               // This validation does not exist.
+               w.WriteHeader(404)
+               return
+       }
+
+       walletLink = "taler://taldir/" + vars["h_address"] + "/" + 
vars["challenge"] + "-wallet"
+       png, err = qrcode.Encode(walletLink, qrcode.Medium, 256)
+       if err != nil {
+               w.WriteHeader(500)
+               return
+       }
+       encodedPng := base64.StdEncoding.EncodeToString(png)
+
+       fullData := map[string]interface{}{
+               "QRCode":     template.URL("data:image/png;base64," + 
encodedPng),
+               "WalletLink": template.URL(walletLink),
+       }
+       t.ValidationTpl.Execute(w, fullData)
+       return
 }
 
 // ClearDatabase nukes the database (for tests)
 func (t *Taldir) ClearDatabase() {
-  t.Db.Where("1 = 1").Delete(&entry{})
-  t.Db.Where("1 = 1").Delete(&validation{})
+       t.Db.Where("1 = 1").Delete(&entry{})
+       t.Db.Where("1 = 1").Delete(&validation{})
 }
 
 func (t *Taldir) termsResponse(w http.ResponseWriter, r *http.Request) {
-  fileType := 
t.Cfg.Section("taldir").Key("default_doc_filetype").MustString("text/html")
-  termsLocation := 
t.Cfg.Section("taldir").Key("default_tos_path").MustString("terms/")
-  for _, typ := range r.Header["Accept"] {
-    for _, a := range 
strings.Split(t.Cfg.Section("taldir").Key("supported_doc_filetypes").String(), 
" ") {
-      if typ == a {
-        fileType = a
-      }
-    }
-  }
-
-  if len(r.Header.Get("Accept-Language")) != 0 {
-    acceptLangs, _, _ := 
language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
-    for _, lang := range acceptLangs {
-      extensions, _ := mime.ExtensionsByType(fileType)
-      for _, ext := range extensions {
-        docFile := fmt.Sprintf("%s/%s/0%s", termsLocation, lang.String(), ext)
-        log.Printf("Trying %s\n", docFile)
-        fileBytes, err := ioutil.ReadFile(docFile)
-        if nil == err {
-          w.Header().Set("Content-Type", fileType)
-          w.Write(fileBytes)
-          return
-        }
-      }
-    }
-  }
-  // Default document in expected/default format
-  defaultLanguage := 
t.Cfg.Section("taldir").Key("default_doc_lang").MustString("en")
-  extensions, _ := mime.ExtensionsByType(fileType)
-  for _, ext := range extensions {
-    docFile := fmt.Sprintf("%s/%s/0%s", termsLocation, defaultLanguage, ext)
-    log.Println("Trying " + docFile)
-    fileBytes, err := ioutil.ReadFile(docFile)
-    if nil == err {
-      w.Header().Set("Content-Type", fileType)
-      w.Write(fileBytes)
-      return
-    }
-  }
-  w.WriteHeader(http.StatusNotFound)
+       fileType := 
t.Cfg.Section("taldir").Key("default_doc_filetype").MustString("text/html")
+       termsLocation := 
t.Cfg.Section("taldir").Key("default_tos_path").MustString("terms/")
+       for _, typ := range r.Header["Accept"] {
+               for _, a := range 
strings.Split(t.Cfg.Section("taldir").Key("supported_doc_filetypes").String(), 
" ") {
+                       if typ == a {
+                               fileType = a
+                       }
+               }
+       }
+
+       if len(r.Header.Get("Accept-Language")) != 0 {
+               acceptLangs, _, _ := 
language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
+               for _, lang := range acceptLangs {
+                       extensions, _ := mime.ExtensionsByType(fileType)
+                       for _, ext := range extensions {
+                               docFile := fmt.Sprintf("%s/%s/0%s", 
termsLocation, lang.String(), ext)
+                               log.Printf("Trying %s\n", docFile)
+                               fileBytes, err := ioutil.ReadFile(docFile)
+                               if nil == err {
+                                       w.Header().Set("Content-Type", fileType)
+                                       w.Write(fileBytes)
+                                       return
+                               }
+                       }
+               }
+       }
+       // Default document in expected/default format
+       defaultLanguage := 
t.Cfg.Section("taldir").Key("default_doc_lang").MustString("en")
+       extensions, _ := mime.ExtensionsByType(fileType)
+       for _, ext := range extensions {
+               docFile := fmt.Sprintf("%s/%s/0%s", termsLocation, 
defaultLanguage, ext)
+               log.Println("Trying " + docFile)
+               fileBytes, err := ioutil.ReadFile(docFile)
+               if nil == err {
+                       w.Header().Set("Content-Type", fileType)
+                       w.Write(fileBytes)
+                       return
+               }
+       }
+       w.WriteHeader(http.StatusNotFound)
 }
 
 func (t *Taldir) privacyResponse(w http.ResponseWriter, r *http.Request) {
-  fileType := 
t.Cfg.Section("taldir").Key("default_doc_filetype").MustString("text/html")
-  termsLocation := 
t.Cfg.Section("taldir").Key("default_pp_path").MustString("privacy/")
-  for _, typ := range r.Header["Accept"] {
-    for _, a := range 
strings.Split(t.Cfg.Section("taldir").Key("supported_doc_filetypes").String(), 
" ") {
-      if typ == a {
-        fileType = a
-      }
-    }
-  }
-
-  if len(r.Header.Get("Accept-Language")) != 0 {
-    acceptLangs, _, _ := 
language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
-    for _, lang := range acceptLangs {
-      extensions, _ := mime.ExtensionsByType(fileType)
-      for _, ext := range extensions {
-        docFile := fmt.Sprintf("%s/%s/0%s", termsLocation, lang.String(), ext)
-        log.Printf("Trying %s\n", docFile)
-        fileBytes, err := ioutil.ReadFile(docFile)
-        if nil == err {
-          w.Header().Set("Content-Type", fileType)
-          w.Write(fileBytes)
-          return
-        }
-      }
-    }
-  }
-  // Default document in expected/default format
-  defaultLanguage := 
t.Cfg.Section("taldir").Key("default_doc_lang").MustString("en")
-  extensions, _ := mime.ExtensionsByType(fileType)
-  for _, ext := range extensions {
-    docFile := fmt.Sprintf("%s/%s/0%s", termsLocation, defaultLanguage, ext)
-    fileBytes, err := ioutil.ReadFile(docFile)
-    if nil == err {
-      w.Header().Set("Content-Type", fileType)
-      w.Write(fileBytes)
-      return
-    }
-  }
-  w.WriteHeader(http.StatusNotFound)
+       fileType := 
t.Cfg.Section("taldir").Key("default_doc_filetype").MustString("text/html")
+       termsLocation := 
t.Cfg.Section("taldir").Key("default_pp_path").MustString("privacy/")
+       for _, typ := range r.Header["Accept"] {
+               for _, a := range 
strings.Split(t.Cfg.Section("taldir").Key("supported_doc_filetypes").String(), 
" ") {
+                       if typ == a {
+                               fileType = a
+                       }
+               }
+       }
+
+       if len(r.Header.Get("Accept-Language")) != 0 {
+               acceptLangs, _, _ := 
language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
+               for _, lang := range acceptLangs {
+                       extensions, _ := mime.ExtensionsByType(fileType)
+                       for _, ext := range extensions {
+                               docFile := fmt.Sprintf("%s/%s/0%s", 
termsLocation, lang.String(), ext)
+                               log.Printf("Trying %s\n", docFile)
+                               fileBytes, err := ioutil.ReadFile(docFile)
+                               if nil == err {
+                                       w.Header().Set("Content-Type", fileType)
+                                       w.Write(fileBytes)
+                                       return
+                               }
+                       }
+               }
+       }
+       // Default document in expected/default format
+       defaultLanguage := 
t.Cfg.Section("taldir").Key("default_doc_lang").MustString("en")
+       extensions, _ := mime.ExtensionsByType(fileType)
+       for _, ext := range extensions {
+               docFile := fmt.Sprintf("%s/%s/0%s", termsLocation, 
defaultLanguage, ext)
+               fileBytes, err := ioutil.ReadFile(docFile)
+               if nil == err {
+                       w.Header().Set("Content-Type", fileType)
+                       w.Write(fileBytes)
+                       return
+               }
+       }
+       w.WriteHeader(http.StatusNotFound)
 }
 
-
 func (t *Taldir) setupHandlers() {
-  t.Router = mux.NewRouter().StrictSlash(true)
+       t.Router = mux.NewRouter().StrictSlash(true)
 
-  /* ToS API */
-  t.Router.HandleFunc("/terms", t.termsResponse).Methods("GET")
-  t.Router.HandleFunc("/privacy", t.privacyResponse).Methods("GET")
+       /* ToS API */
+       t.Router.HandleFunc("/terms", t.termsResponse).Methods("GET")
+       t.Router.HandleFunc("/privacy", t.privacyResponse).Methods("GET")
 
-  /* Config API */
-  t.Router.HandleFunc("/config", t.configResponse).Methods("GET")
+       /* Config API */
+       t.Router.HandleFunc("/config", t.configResponse).Methods("GET")
 
-  /* Aissets HTML */
-  t.Router.PathPrefix("/css").Handler(http.StripPrefix("/css", 
http.FileServer(http.Dir("./static/css"))))
+       /* Aissets HTML */
+       t.Router.PathPrefix("/css").Handler(http.StripPrefix("/css", 
http.FileServer(http.Dir("./static/css"))))
 
-  /* Registration API */
-  t.Router.HandleFunc("/{h_address}", t.getSingleEntry).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")
+       /* Registration API */
+       t.Router.HandleFunc("/{h_address}", t.getSingleEntry).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")
 
 }
 
-func (t *Taldir) handleRequests() {
-  
log.Fatal(http.ListenAndServe(t.Cfg.Section("taldir").Key("bind_to").MustString("localhost:11000"),
 t.Router))
-}
-
 // Initialize the Taldir instance with cfgfile
 func (t *Taldir) Initialize(cfgfile string) {
-  _cfg, err := ini.Load(cfgfile)
-  if err != nil {
-    fmt.Printf("Failed to read config: %v", err)
-    os.Exit(1)
-  }
-  t.Cfg = _cfg
-  if t.Cfg.Section("taldir").Key("production").MustBool(false) {
-    fmt.Println("Production mode enabled")
-  }
-
-  t.Validators = make(map[string]bool)
-  for _, a := range 
strings.Split(t.Cfg.Section("taldir").Key("validators").String(), " ") {
-    t.Validators[a] = true
-  }
-  t.ChallengeBytes = t.Cfg.Section("taldir").Key("challenge_bytes").MustInt(16)
-  t.ValidationInitiationMax = 
t.Cfg.Section("taldir").Key("validation_initiation_max").MustInt64(3)
-  t.SolutionAttemptsMax = 
t.Cfg.Section("taldir").Key("solution_attempt_max").MustInt(3)
-
-  validationTTLStr := 
t.Cfg.Section("taldir").Key("validation_timeframe").MustString("5m")
-  t.ValidationTimeframe, err = time.ParseDuration(validationTTLStr)
-  if err != nil {
-    log.Fatal(err)
-  }
-
-  retryTimeframeStr := 
t.Cfg.Section("taldir").Key("solution_attempt_timeframe").MustString("1h")
-  t.SolutionTimeframe, err = time.ParseDuration(retryTimeframeStr)
-  if err != nil {
-    log.Fatal(err)
-  }
-  t.MonthlyFee = 
t.Cfg.Section("taldir").Key("monthly_fee").MustString("KUDOS:0")
-
-  psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s 
sslmode=disable",
-  t.Cfg.Section("taldir-pq").Key("host").MustString("localhost"),
-  t.Cfg.Section("taldir-pq").Key("port").MustInt64(5432),
-  t.Cfg.Section("taldir-pq").Key("user").MustString("taldir"),
-  t.Cfg.Section("taldir-pq").Key("password").MustString("secret"),
-  t.Cfg.Section("taldir-pq").Key("db_name").MustString("taldir"))
-  _db, err := gorm.Open(postgres.Open(psqlconn), &gorm.Config{
-    Logger: logger.Default.LogMode(logger.Silent),
-  })
-  if err != nil {
-    panic(err)
-  }
-  t.Db = _db
-  if err := t.Db.AutoMigrate(&entry{}); err != nil {
-    panic(err)
-  }
-  if err := t.Db.AutoMigrate(&validation{}); err != nil {
-    panic(err)
-  }
-
-  // Clean up validations
-  validationExpStr := 
t.Cfg.Section("taldir").Key("validation_expiration").MustString("24h")
-  validationExp, err := time.ParseDuration(validationExpStr)
-  if err != nil {
-    log.Fatal(err)
-  }
-  go func() {
-    for true {
-      tx := t.Db.Where("created_at < ?", 
time.Now().Add(-validationExp)).Delete(&validation{})
-      log.Printf("Cleaned up %d stale validations.\n", tx.RowsAffected)
-      time.Sleep(validationExp)
-    }
-  }()
-  validationLandingTplFile := 
t.Cfg.Section("taldir").Key("validation_landing").MustString("templates/validation_landing.html")
-  t.ValidationTpl, err = template.ParseFiles(validationLandingTplFile)
-  if err != nil {
-    fmt.Println(err)
-  }
-  t.Salt = os.Getenv("TALDIR_SALT")
-  if "" == t.Salt {
-    t.Salt = t.Cfg.Section("taldir").Key("salt").MustString("ChangeMe")
-  }
-  merchURL := 
t.Cfg.Section("taldir").Key("merchant_baseurl_private").MustString("http://merchant.taldir/instances/myInstance";)
-  merchToken := 
t.Cfg.Section("taldir").Key("merchant_token").MustString("secretAccessToken")
-  t.Merchant = taler.NewMerchant(merchURL, merchToken)
-  t.setupHandlers()
-}
-
-
-// Run the server and listen for requests
-func (t *Taldir) Run() {
-  t.handleRequests()
+       _cfg, err := ini.Load(cfgfile)
+       if err != nil {
+               fmt.Printf("Failed to read config: %v", err)
+               os.Exit(1)
+       }
+       t.Cfg = _cfg
+       if t.Cfg.Section("taldir").Key("production").MustBool(false) {
+               fmt.Println("Production mode enabled")
+       }
+
+       t.Validators = make(map[string]bool)
+       for _, a := range 
strings.Split(t.Cfg.Section("taldir").Key("validators").String(), " ") {
+               t.Validators[a] = true
+       }
+       t.ChallengeBytes = 
t.Cfg.Section("taldir").Key("challenge_bytes").MustInt(16)
+       t.ValidationInitiationMax = 
t.Cfg.Section("taldir").Key("validation_initiation_max").MustInt64(3)
+       t.SolutionAttemptsMax = 
t.Cfg.Section("taldir").Key("solution_attempt_max").MustInt(3)
+
+       validationTTLStr := 
t.Cfg.Section("taldir").Key("validation_timeframe").MustString("5m")
+       t.ValidationTimeframe, err = time.ParseDuration(validationTTLStr)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       retryTimeframeStr := 
t.Cfg.Section("taldir").Key("solution_attempt_timeframe").MustString("1h")
+       t.SolutionTimeframe, err = time.ParseDuration(retryTimeframeStr)
+       if err != nil {
+               log.Fatal(err)
+       }
+       t.MonthlyFee = 
t.Cfg.Section("taldir").Key("monthly_fee").MustString("KUDOS:0")
+
+       psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s 
sslmode=disable",
+               t.Cfg.Section("taldir-pq").Key("host").MustString("localhost"),
+               t.Cfg.Section("taldir-pq").Key("port").MustInt64(5432),
+               t.Cfg.Section("taldir-pq").Key("user").MustString("taldir"),
+               t.Cfg.Section("taldir-pq").Key("password").MustString("secret"),
+               t.Cfg.Section("taldir-pq").Key("db_name").MustString("taldir"))
+       _db, err := gorm.Open(postgres.Open(psqlconn), &gorm.Config{
+               Logger: logger.Default.LogMode(logger.Silent),
+       })
+       if err != nil {
+               panic(err)
+       }
+       t.Db = _db
+       if err := t.Db.AutoMigrate(&entry{}); err != nil {
+               panic(err)
+       }
+       if err := t.Db.AutoMigrate(&validation{}); err != nil {
+               panic(err)
+       }
+
+       // Clean up validations
+       validationExpStr := 
t.Cfg.Section("taldir").Key("validation_expiration").MustString("24h")
+       validationExp, err := time.ParseDuration(validationExpStr)
+       if err != nil {
+               log.Fatal(err)
+       }
+       go func() {
+               for true {
+                       tx := t.Db.Where("created_at < ?", 
time.Now().Add(-validationExp)).Delete(&validation{})
+                       log.Printf("Cleaned up %d stale validations.\n", 
tx.RowsAffected)
+                       time.Sleep(validationExp)
+               }
+       }()
+       validationLandingTplFile := 
t.Cfg.Section("taldir").Key("validation_landing").MustString("templates/validation_landing.html")
+       t.ValidationTpl, err = template.ParseFiles(validationLandingTplFile)
+       if err != nil {
+               fmt.Println(err)
+       }
+       t.Salt = os.Getenv("TALDIR_SALT")
+       if "" == t.Salt {
+               t.Salt = 
t.Cfg.Section("taldir").Key("salt").MustString("ChangeMe")
+       }
+       merchURL := 
t.Cfg.Section("taldir").Key("merchant_baseurl_private").MustString("http://merchant.taldir/instances/myInstance";)
+       merchToken := 
t.Cfg.Section("taldir").Key("merchant_token").MustString("secretAccessToken")
+       t.Merchant = taler.NewMerchant(merchURL, merchToken)
+       t.setupHandlers()
 }
diff --git a/pkg/taler/merchant.go b/pkg/taler/merchant.go
index 1606b3d..862f00c 100644
--- a/pkg/taler/merchant.go
+++ b/pkg/taler/merchant.go
@@ -1,161 +1,156 @@
 package taler
 
 import (
-  "net/http"
-  "encoding/json"
-  "bytes"
-  "fmt"
-  "errors"
-  "io/ioutil"
-  talerutil "taler.net/taler-go.git/pkg/util"
+       "bytes"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "io/ioutil"
+       "net/http"
+       talerutil "taler.net/taler-go.git/pkg/util"
 )
 
 type PostOrderRequest struct {
-  // The order must at least contain the minimal
-  // order detail, but can override all.
-  order MinimalOrderDetail
-
-  // If set, the backend will then set the refund deadline to the current
-  // time plus the specified delay.  If it's not set, refunds will not be
-  // possible.
-  RefundDelay int64 `json:"refund_delay,omitempty"`
-
-  // Specifies the payment target preferred by the client. Can be used
-  // to select among the various (active) wire methods supported by the 
instance.
-  PaymentTarget string `json:"payment_target,omitempty"`
-
-  // Specifies that some products are to be included in the
-  // order from the inventory.  For these inventory management
-  // is performed (so the products must be in stock) and
-  // details are completed from the product data of the backend.
-  // FIXME: Not sure we actually need this for now
-  //InventoryProducts []MinimalInventoryProduct 
`json:"inventory_products,omitempty"`
-
-  // Specifies a lock identifier that was used to
-  // lock a product in the inventory.  Only useful if
-  // inventory_products is set.  Used in case a frontend
-  // reserved quantities of the individual products while
-  // the shopping cart was being built.  Multiple UUIDs can
-  // be used in case different UUIDs were used for different
-  // products (i.e. in case the user started with multiple
-  // shopping sessions that were combined during checkout).
-  LockUuids []string `json:"lock_uuids"`
-
-  // Should a token for claiming the order be generated?
-  // False can make sense if the ORDER_ID is sufficiently
-  // high entropy to prevent adversarial claims (like it is
-  // if the backend auto-generates one). Default is 'true'.
-  CreateToken bool `json:"create_token,omitempty"`
-
+       // The order must at least contain the minimal
+       // order detail, but can override all.
+       order MinimalOrderDetail
+
+       // If set, the backend will then set the refund deadline to the current
+       // time plus the specified delay.  If it's not set, refunds will not be
+       // possible.
+       RefundDelay int64 `json:"refund_delay,omitempty"`
+
+       // Specifies the payment target preferred by the client. Can be used
+       // to select among the various (active) wire methods supported by the 
instance.
+       PaymentTarget string `json:"payment_target,omitempty"`
+
+       // Specifies that some products are to be included in the
+       // order from the inventory.  For these inventory management
+       // is performed (so the products must be in stock) and
+       // details are completed from the product data of the backend.
+       // FIXME: Not sure we actually need this for now
+       //InventoryProducts []MinimalInventoryProduct 
`json:"inventory_products,omitempty"`
+
+       // Specifies a lock identifier that was used to
+       // lock a product in the inventory.  Only useful if
+       // inventory_products is set.  Used in case a frontend
+       // reserved quantities of the individual products while
+       // the shopping cart was being built.  Multiple UUIDs can
+       // be used in case different UUIDs were used for different
+       // products (i.e. in case the user started with multiple
+       // shopping sessions that were combined during checkout).
+       LockUuids []string `json:"lock_uuids"`
+
+       // Should a token for claiming the order be generated?
+       // False can make sense if the ORDER_ID is sufficiently
+       // high entropy to prevent adversarial claims (like it is
+       // if the backend auto-generates one). Default is 'true'.
+       CreateToken bool `json:"create_token,omitempty"`
 }
 
 type MinimalOrderDetail struct {
-  // Amount to be paid by the customer.
-  Amount string
+       // Amount to be paid by the customer.
+       Amount string
 
-  // Short summary of the order.
-  Summary string;
+       // Short summary of the order.
+       Summary string
 }
 
-
 // NOTE: Part of the above but optional
 type FulfillmentMetadata struct {
-  // See documentation of fulfillment_url in ContractTerms.
-  // Either fulfillment_url or fulfillment_message must be specified.
-  FulfillmentUrl string `json:"fulfillment_url,omitempty"`
+       // See documentation of fulfillment_url in ContractTerms.
+       // Either fulfillment_url or fulfillment_message must be specified.
+       FulfillmentUrl string `json:"fulfillment_url,omitempty"`
 
-  // See documentation of fulfillment_message in ContractTerms.
-  // Either fulfillment_url or fulfillment_message must be specified.
-  FulfillmentMessage string `json:"fulfillment_message,omitempty"`
+       // See documentation of fulfillment_message in ContractTerms.
+       // Either fulfillment_url or fulfillment_message must be specified.
+       FulfillmentMessage string `json:"fulfillment_message,omitempty"`
 }
 
 type PostOrderResponse struct {
-  // Order ID of the response that was just created.
-  OrderId string `json:"order_id"`
+       // Order ID of the response that was just created.
+       OrderId string `json:"order_id"`
 }
 
 type PostOrderResponseToken struct {
-  // Token that authorizes the wallet to claim the order.
-  // Provided only if "create_token" was set to 'true'
-  // in the request.
-  Token string
+       // Token that authorizes the wallet to claim the order.
+       // Provided only if "create_token" was set to 'true'
+       // in the request.
+       Token string
 }
 
 type CheckPaymentStatusResponse struct {
-  // Status of the order
-  OrderStatus string `json:"order_status"`
+       // Status of the order
+       OrderStatus string `json:"order_status"`
 }
 
 type CheckPaymentPaytoResponse struct {
-  // Status of the order
-  TalerPayUri string `json:"taler_pay_uri"`
+       // Status of the order
+       TalerPayUri string `json:"taler_pay_uri"`
 }
 
-
-
 type Merchant struct {
 
-  // The host of this merchant
-  BaseUrlPrivate string
-
-  // The access token to use for the private API
-  AccessToken string
+       // The host of this merchant
+       BaseUrlPrivate string
 
+       // The access token to use for the private API
+       AccessToken string
 }
 
 func NewMerchant(merchBaseUrlPrivate string, merchAccessToken string) Merchant 
{
-  return Merchant{
-    BaseUrlPrivate: merchBaseUrlPrivate,
-    AccessToken: merchAccessToken,
-  }
+       return Merchant{
+               BaseUrlPrivate: merchBaseUrlPrivate,
+               AccessToken:    merchAccessToken,
+       }
 }
 
 func (m *Merchant) IsOrderPaid(orderId string) (string, error) {
-  var orderPaidResponse CheckPaymentStatusResponse
-  var paytoResponse CheckPaymentPaytoResponse
-  resp, err := http.Get(m.BaseUrlPrivate + "/private/orders/" + orderId)
-  if nil != err {
-    return "", err
-  }
-  defer resp.Body.Close()
-  if http.StatusOK != resp.StatusCode {
-    message := fmt.Sprintf("Expected response code %d. Got %d", http.StatusOK, 
resp.StatusCode)
-    return "", errors.New(message)
-  }
-  respData, err := ioutil.ReadAll(resp.Body)
-  if err != nil {
-    return "", err
-  }
-  err = json.NewDecoder(bytes.NewReader(respData)).Decode(&orderPaidResponse)
-  if err != nil {
-    return "", err
-  }
-  if orderPaidResponse.OrderStatus != "paid" {
-    err = json.NewDecoder(bytes.NewReader(respData)).Decode(&paytoResponse)
-    return paytoResponse.TalerPayUri, err
-  }
-  return "", nil
+       var orderPaidResponse CheckPaymentStatusResponse
+       var paytoResponse CheckPaymentPaytoResponse
+       resp, err := http.Get(m.BaseUrlPrivate + "/private/orders/" + orderId)
+       if nil != err {
+               return "", err
+       }
+       defer resp.Body.Close()
+       if http.StatusOK != resp.StatusCode {
+               message := fmt.Sprintf("Expected response code %d. Got %d", 
http.StatusOK, resp.StatusCode)
+               return "", errors.New(message)
+       }
+       respData, err := ioutil.ReadAll(resp.Body)
+       if err != nil {
+               return "", err
+       }
+       err = 
json.NewDecoder(bytes.NewReader(respData)).Decode(&orderPaidResponse)
+       if err != nil {
+               return "", err
+       }
+       if orderPaidResponse.OrderStatus != "paid" {
+               err = 
json.NewDecoder(bytes.NewReader(respData)).Decode(&paytoResponse)
+               return paytoResponse.TalerPayUri, err
+       }
+       return "", nil
 }
 
 func (m *Merchant) AddNewOrder(cost talerutil.Amount) (string, error) {
-  var newOrder PostOrderRequest
-  var orderDetail MinimalOrderDetail
-  var orderResponse PostOrderResponse
-  orderDetail.Amount = cost.String()
-  // FIXME get from cfg
-  orderDetail.Summary = "This is an order to a TalDir registration"
-  newOrder.order = orderDetail
-  reqString, _ := json.Marshal(newOrder)
-  resp, err := http.Post(m.BaseUrlPrivate + "/private/orders", 
"application/json", bytes.NewBuffer(reqString))
-
-  if nil != err {
-    return "", err
-  }
-  defer resp.Body.Close()
-  if http.StatusOK != resp.StatusCode {
-    message := fmt.Sprintf("Expected response code %d. Got %d", http.StatusOK, 
resp.StatusCode)
-    return "", errors.New(message)
-  }
-  err = json.NewDecoder(resp.Body).Decode(&orderResponse)
-  return orderResponse.OrderId, err
+       var newOrder PostOrderRequest
+       var orderDetail MinimalOrderDetail
+       var orderResponse PostOrderResponse
+       orderDetail.Amount = cost.String()
+       // FIXME get from cfg
+       orderDetail.Summary = "This is an order to a TalDir registration"
+       newOrder.order = orderDetail
+       reqString, _ := json.Marshal(newOrder)
+       resp, err := http.Post(m.BaseUrlPrivate+"/private/orders", 
"application/json", bytes.NewBuffer(reqString))
+
+       if nil != err {
+               return "", err
+       }
+       defer resp.Body.Close()
+       if http.StatusOK != resp.StatusCode {
+               message := fmt.Sprintf("Expected response code %d. Got %d", 
http.StatusOK, resp.StatusCode)
+               return "", errors.New(message)
+       }
+       err = json.NewDecoder(resp.Body).Decode(&orderResponse)
+       return orderResponse.OrderId, err
 }
diff --git a/pkg/util/helper.go b/pkg/util/helper.go
index 9243c5e..b99d6af 100644
--- a/pkg/util/helper.go
+++ b/pkg/util/helper.go
@@ -16,67 +16,65 @@
 //
 // SPDX-License-Identifier: AGPL3.0-or-later
 
-
 package util
 
 import (
-  "fmt"
-  "crypto/sha512"
-  "math/rand"
-  "time"
-  gnunetutil "git.gnunet.org/gnunet-go.git/pkg/util"
-  talerutil "taler.net/taler-go.git/pkg/util"
+       "crypto/sha512"
+       "fmt"
+       gnunetutil "git.gnunet.org/gnunet-go.git/pkg/util"
+       "math/rand"
+       talerutil "taler.net/taler-go.git/pkg/util"
+       "time"
 )
 
-
 // Generates a solution from a challenge and pubkey
 func GenerateSolution(pubkeyEncoded string, challenge string) string {
-  pubkey, err := gnunetutil.DecodeStringToBinary(pubkeyEncoded, 36)
-  if err != nil {
-    fmt.Println("error decoding pubkey:", err)
-    return ""
-  }
-  h := sha512.New()
-  h.Write([]byte(challenge))
-  h.Write(pubkey)
-  return gnunetutil.EncodeBinaryToString(h.Sum(nil))
+       pubkey, err := gnunetutil.DecodeStringToBinary(pubkeyEncoded, 36)
+       if err != nil {
+               fmt.Println("error decoding pubkey:", err)
+               return ""
+       }
+       h := sha512.New()
+       h.Write([]byte(challenge))
+       h.Write(pubkey)
+       return gnunetutil.EncodeBinaryToString(h.Sum(nil))
 }
 
 // Generates random reference token used in the validation flow.
 func GenerateChallenge(bytes int) string {
-  randBytes := make([]byte, bytes)
-  _, err := rand.Read(randBytes)
-  if err != nil {
-    panic(err)
-  }
-  return gnunetutil.EncodeBinaryToString(randBytes)
+       randBytes := make([]byte, bytes)
+       _, err := rand.Read(randBytes)
+       if err != nil {
+               panic(err)
+       }
+       return gnunetutil.EncodeBinaryToString(randBytes)
 }
 
 // Check if this is a non-zero, positive amount
 func CalculateCost(sliceCostAmount string, fixedCostAmount string, howLong 
time.Duration, sliceDuration time.Duration) (*talerutil.Amount, error) {
-  sliceCount := int(float64(howLong.Microseconds()) / 
float64(sliceDuration.Microseconds()))
-  sliceCost, err := talerutil.ParseAmount(sliceCostAmount)
-  if nil != err {
-    return nil, err
-  }
-  fixedCost, err := talerutil.ParseAmount(fixedCostAmount)
-  if nil != err {
-    return nil, err
-  }
-  sum := &talerutil.Amount{
-    Currency: sliceCost.Currency,
-    Value: 0,
-    Fraction: 0,
-  }
-  for i := 0; i < sliceCount; i++ {
-    sum, err = sum.Add(*sliceCost)
-    if nil != err {
-      return nil, err
-    }
-  }
-  sum, err = sum.Add(*fixedCost)
-  if nil != err {
-    return nil, err
-  }
-  return sum, nil
+       sliceCount := int(float64(howLong.Microseconds()) / 
float64(sliceDuration.Microseconds()))
+       sliceCost, err := talerutil.ParseAmount(sliceCostAmount)
+       if nil != err {
+               return nil, err
+       }
+       fixedCost, err := talerutil.ParseAmount(fixedCostAmount)
+       if nil != err {
+               return nil, err
+       }
+       sum := &talerutil.Amount{
+               Currency: sliceCost.Currency,
+               Value:    0,
+               Fraction: 0,
+       }
+       for i := 0; i < sliceCount; i++ {
+               sum, err = sum.Add(*sliceCost)
+               if nil != err {
+                       return nil, err
+               }
+       }
+       sum, err = sum.Add(*fixedCost)
+       if nil != err {
+               return nil, err
+       }
+       return sum, nil
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]