commit cd47ac4772a7739a21da47890775e5e469fad360
parent 3fc03097ac091b8bef4a1a05af885c2cb1ddf455
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date: Thu, 23 Jan 2025 13:56:18 +0100
more error handling
Diffstat:
4 files changed, 271 insertions(+), 261 deletions(-)
diff --git a/locales/de-DE/taldir.yml b/locales/de-DE/taldir.yml
@@ -10,6 +10,7 @@ notYetLinked: "`%s` ist noch nicht mit einer Bezahlsystemadresse verlinkt. Du ka
isLinked: "`%s` ist bereits mit einer Bezahlsystemadresse verlinkt"
paymentSystemAddress: "Bezahlsystemadresse"
linkIt: "Verlinken"
+aliasInvalid: "Alias '%s´ ist ungültig."
lookup: "Suchen"
lookupEmail: "E-Mail-Adresse nachschlagen"
lookupEmailDescription: "Gib eine E-Mail-Adresse (z.B. `jdoe@example.com`) ein um die dazugehörige Bezahlsystemadresse nachzuschlagen. Wenn diese noch nicht verlinkt ist, und das Alias unter Dir gehört, hast du dann die Chance dieses mit einer Bazahlsystemadresse zu verlinken."
diff --git a/locales/en-US/taldir.yml b/locales/en-US/taldir.yml
@@ -10,6 +10,7 @@ notYetLinked: "`%s` is not yet linked with any Payment System Address. You may u
isLinked: "`%s` is linked with a Payment System Address"
paymentSystemAddress: "Payment System Address"
linkIt: "Link it"
+aliasInvalid: "Alias '%s´ is invalid."
lookup: "Lookup"
lookupEmail: "Lookup Email address"
lookupEmailDescription: "Enter an email address (e.g. `jdoe@example.com`) to look up the associated Payment System Address. If it is still unlinked and under your control you will be given the option to link it with a Payment System Address after lookup."
diff --git a/pkg/rest/taldir.go b/pkg/rest/taldir.go
@@ -671,302 +671,310 @@ func (t *Taldir) validationPage(w http.ResponseWriter, r *http.Request) {
"version": t.Version,
"QRCode": template.URL("data:image/png;base64," + encodedPng),
"WalletLink": template.URL(walletLink),
- }
- t.ValidationTpl.Execute(w, fullData)
- } else {
- expectedSolution := util.GenerateSolution(validation.TargetUri, validation.Challenge)
- fullData := map[string]interface{}{
- "version": t.Version,
- "error": r.URL.Query().Get("error"),
- "target_uri": template.URL(validation.TargetUri),
- "address": template.URL(address),
- "haddress": template.URL(validation.HAddress),
- "solution": template.URL(expectedSolution),
- "tr": t.I18n.GetLocale(r).GetMessage,
- }
- t.ValidationTpl.Execute(w, fullData)
- }
- return
+ "productDisclaimer": template.HTML(t.I18n.GetLocale(r).GetMessage("productDisclaimer")),
+ }
+ t.ValidationTpl.Execute(w, fullData)
+ } else {
+ expectedSolution := util.GenerateSolution(validation.TargetUri, validation.Challenge)
+ fullData := map[string]interface{}{
+ "version": t.Version,
+ "error": r.URL.Query().Get("error"),
+ "target_uri": template.URL(validation.TargetUri),
+ "address": template.URL(address),
+ "haddress": template.URL(validation.HAddress),
+ "solution": template.URL(expectedSolution),
+ "productDisclaimer": template.HTML(t.I18n.GetLocale(r).GetMessage("productDisclaimer")),
+ "tr": t.I18n.GetLocale(r).GetMessage,
+ }
+ 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) {
- tos.ServiceTermsResponse(t.Cfg.Section("taldir"), w, r)
+ tos.ServiceTermsResponse(t.Cfg.Section("taldir"), w, r)
}
func (t *Taldir) privacyResponse(w http.ResponseWriter, r *http.Request) {
- tos.PrivacyPolicyResponse(t.Cfg.Section("taldir"), w, r)
+ tos.PrivacyPolicyResponse(t.Cfg.Section("taldir"), w, r)
}
func (t *Taldir) landingPage(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- translateFunc := t.I18n.GetLocale(r).GetMessage
- fullData := map[string]interface{}{
- "validators": t.Validators,
- "version": t.Version,
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ translateFunc := t.I18n.GetLocale(r).GetMessage
+ fullData := map[string]interface{}{
+ "validators": t.Validators,
+ "version": t.Version,
"lookupOrRegisterCardTitle": template.HTML(translateFunc("lookupOrRegister")),
"selectAliasToLookupOrLinkCardText": template.HTML(translateFunc("selectAliasToLookupOrLink")),
"productDisclaimer": template.HTML(translateFunc("productDisclaimer")),
- "error": r.URL.Query().Get("error"),
- "tr": translateFunc,
- }
- err := t.LandingPageTpl.Execute(w, fullData)
- if err != nil {
- fmt.Println(err)
- }
- return
+ "error": translateFunc(r.URL.Query().Get("error")),
+ "tr": translateFunc,
+ }
+ err := t.LandingPageTpl.Execute(w, fullData)
+ if err != nil {
+ fmt.Println(err)
+ }
+ return
}
func (t *Taldir) methodLookupResultPage(w http.ResponseWriter, r *http.Request) {
- var entry entry
- vars := mux.Vars(r)
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
-
- // Check if this validation method is supported or not.
- val, ok := t.Validators[vars["method"]]
- if !ok {
- w.WriteHeader(404)
- return
- }
-
- // Check if alias is valid
- alias := r.URL.Query().Get("address")
- err := val.isAliasValid(alias)
- if nil != err {
- http.Redirect(w, r, fmt.Sprintf("/?error=%s", err), http.StatusSeeOther)
- return
- }
- hAddressBin := sha512.Sum512([]byte(r.URL.Query().Get("address")))
- hAddress := gnunetutil.EncodeBinaryToString(hAddressBin[:])
- hsAddress := saltHAddress(hAddress, t.Salt)
- found := false
- err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error
- if err != nil {
- log.Printf("`%s` not found.\n", hAddress)
- } else {
- found = true
- }
- fullData := map[string]interface{}{
- "version": t.Version,
- "available": !found,
- "method": val.Name,
- "address": r.URL.Query().Get("address"),
- "result": entry.TargetUri,
- "error": r.URL.Query().Get("error"),
- "tr": t.I18n.GetLocale(r).GetMessage,
- }
- err = t.LookupResultPageTpl.Execute(w, fullData)
- if err != nil {
- fmt.Println(err)
- }
- return
+ var entry entry
+ vars := mux.Vars(r)
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+
+ // Check if this validation method is supported or not.
+ val, ok := t.Validators[vars["method"]]
+ if !ok {
+ w.WriteHeader(404)
+ return
+ }
+
+ // Check if alias is valid
+ alias := r.URL.Query().Get("address")
+ err := val.isAliasValid(alias)
+ emsg := ""
+ found := false
+ if nil != err {
+ log.Printf("Not a valid alias\n")
+ emsg = t.I18n.GetLocale(r).GetMessage("aliasInvalid", alias)
+ http.Redirect(w, r, fmt.Sprintf("/landing/" + val.Name + "?error=%s", emsg), http.StatusSeeOther)
+ return
+ } else {
+ hAddressBin := sha512.Sum512([]byte(r.URL.Query().Get("address")))
+ hAddress := gnunetutil.EncodeBinaryToString(hAddressBin[:])
+ hsAddress := saltHAddress(hAddress, t.Salt)
+ err = t.Db.First(&entry, "hs_address = ?", hsAddress).Error
+ if err != nil {
+ log.Printf("`%s` not found.\n", hAddress)
+ } else {
+ found = true
+ }
+ }
+ fullData := map[string]interface{}{
+ "version": t.Version,
+ "available": !found,
+ "method": val.Name,
+ "address": r.URL.Query().Get("address"),
+ "result": entry.TargetUri,
+ "error": emsg,
+ "productDisclaimer": template.HTML(t.I18n.GetLocale(r).GetMessage("productDisclaimer")),
+ "tr": t.I18n.GetLocale(r).GetMessage,
+ }
+ err = t.LookupResultPageTpl.Execute(w, fullData)
+ if err != nil {
+ fmt.Println(err)
+ }
+ return
}
func (t *Taldir) methodLandingPage(w http.ResponseWriter, r *http.Request) {
- vars := mux.Vars(r)
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
-
- // Check if this validation method is supported or not.
- val, ok := t.Validators[vars["method"]]
- if !ok {
- w.WriteHeader(404)
- return
- }
- fullData := map[string]interface{}{
- "version": t.Version,
- "error": r.URL.Query().Get("error"),
- "tr": t.I18n.GetLocale(r).GetMessage,
- }
- err := val.LandingPageTpl.Execute(w, fullData)
- if err != nil {
- fmt.Println(err)
- }
- return
+ vars := mux.Vars(r)
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+
+ // Check if this validation method is supported or not.
+ val, ok := t.Validators[vars["method"]]
+ if !ok {
+ w.WriteHeader(404)
+ return
+ }
+ fullData := map[string]interface{}{
+ "version": t.Version,
+ "error": r.URL.Query().Get("error"),
+ "productDisclaimer": template.HTML(t.I18n.GetLocale(r).GetMessage("productDisclaimer")),
+ "tr": t.I18n.GetLocale(r).GetMessage,
+ }
+ err := val.LandingPageTpl.Execute(w, fullData)
+ if err != nil {
+ fmt.Println(err)
+ }
+ return
}
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")
- /* Assets HTML */
- t.Router.PathPrefix("/css").Handler(http.StripPrefix("/css", http.FileServer(http.Dir("./static/css"))))
- t.Router.PathPrefix("/fontawesome").Handler(http.StripPrefix("/fontawesome", http.FileServer(http.Dir("./static/fontawesome"))))
+ /* Assets HTML */
+ t.Router.PathPrefix("/css").Handler(http.StripPrefix("/css", http.FileServer(http.Dir("./static/css"))))
+ t.Router.PathPrefix("/fontawesome").Handler(http.StripPrefix("/fontawesome", http.FileServer(http.Dir("./static/fontawesome"))))
- /* Registration API */
- t.Router.HandleFunc("/", t.landingPage).Methods("GET")
- t.Router.HandleFunc("/{h_address}", t.getSingleEntry).Methods("GET")
- t.Router.HandleFunc("/lookup/{method}", t.methodLookupResultPage).Methods("GET")
- t.Router.HandleFunc("/landing/{method}", t.methodLandingPage).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("/", t.landingPage).Methods("GET")
+ t.Router.HandleFunc("/{h_address}", t.getSingleEntry).Methods("GET")
+ t.Router.HandleFunc("/lookup/{method}", t.methodLookupResultPage).Methods("GET")
+ t.Router.HandleFunc("/landing/{method}", t.methodLandingPage).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")
}
var pluralizeClient = pluralize.NewClient()
func getFuncs(current *i18n.Locale) template.FuncMap {
- return template.FuncMap{
- "plural": func(word string, count int) string {
- return pluralizeClient.Pluralize(word, count, true)
- },
- }
+ return template.FuncMap{
+ "plural": func(word string, count int) string {
+ return pluralizeClient.Pluralize(word, count, true)
+ },
+ }
}
// Initialize the Taldir instance with cfgfile
func (t *Taldir) Initialize(cfgfile string, version string) {
- _cfg, err := ini.LooseLoad(cfgfile)
- if err != nil {
- log.Fatalf("Failed to read config: %v", err)
- os.Exit(1)
- }
- t.Cfg = _cfg
- t.I18n, err = i18n.New(i18n.Glob("./locales/*/*", i18n.LoaderConfig{
- // Set custom functions per locale!
- Funcs: getFuncs,
- }), "en-US", "de-DE")
- if err != nil {
- panic(err)
- }
- if t.Cfg.Section("taldir").Key("production").MustBool(false) {
- fmt.Println("Production mode enabled")
- }
-
- navTplFile := t.Cfg.Section("taldir").Key("navigation").MustString("web/templates/nav.html")
- footerTplFile := t.Cfg.Section("taldir").Key("footer").MustString("web/templates/footer.html")
- t.Version = version
- t.BaseUrl = t.Cfg.Section("taldir").Key("base_url").MustString("http://localhost:11000")
- t.Validators = make(map[string]Validator)
- for _, sec := range t.Cfg.Sections() {
- if !strings.HasPrefix(sec.Name(), "taldir-validator-") {
- continue
- }
- if !sec.HasKey("type") {
- log.Printf("`type` key in section `[%s]` not found, disabling validator.\n", sec.Name())
- continue
- }
- vname := strings.TrimPrefix(sec.Name(), "taldir-validator-")
- vlandingPageTplFile := sec.Key("registration_page").MustString("web/templates/landing_" + vname + ".html")
- vlandingPageTpl, err := template.ParseFiles(vlandingPageTplFile, navTplFile, footerTplFile)
- if err != nil {
- log.Printf("`%s` template not found, disabling validator `%s`.\n", vlandingPageTplFile, vname)
- continue
- }
- t.Validators[vname] = Validator{
- Name: vname,
- LandingPageTpl: vlandingPageTpl,
- ChallengeFee: sec.Key("challenge_fee").MustString("KUDOS:0"),
- PaymentRequired: sec.Key("enabled").MustBool(false),
- Command: sec.Key("command").MustString(""),
- Type: ValidatorType(sec.Key("type").MustString("")),
- ValidAliasRegex: sec.Key("valid_alias_regex").MustString(""),
- }
- }
- 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.ValidPMSRegex = t.Cfg.Section("taldir").Key("valid_payment_system_address_regex").MustString("[A-Z]+")
- t.ValidationTimeframe, err = time.ParseDuration(validationTTLStr)
- if err != nil {
- log.Fatal(err)
- os.Exit(1)
- }
-
- retryTimeframeStr := t.Cfg.Section("taldir").Key("solution_attempt_timeframe").MustString("1h")
- t.SolutionTimeframe, err = time.ParseDuration(retryTimeframeStr)
- if err != nil {
- log.Fatal(err)
- os.Exit(1)
- }
- 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)
- }
- if t.Cfg.Section("taldir").Key("purge_mappings_on_startup_dangerous").MustBool(false) {
- log.Println("DANGER Purging mappings!")
- tx := t.Db.Where("1 = 1").Delete(&entry{})
- log.Printf("Deleted %d entries.\n", tx.RowsAffected)
- }
- // Clean up validations
- validationExpStr := t.Cfg.Section("taldir").Key("validation_expiration").MustString("24h")
- validationExp, err := time.ParseDuration(validationExpStr)
- if err != nil {
- log.Fatal(err)
- os.Exit(1)
- }
- 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("web/templates/validation_landing.html")
- t.ValidationTpl, err = template.ParseFiles(validationLandingTplFile, navTplFile, footerTplFile)
- if err != nil {
- log.Fatal(err)
- os.Exit(1)
- }
- landingTplFile := t.Cfg.Section("taldir").Key("landing_page").MustString("web/templates/landing.html")
- t.LandingPageTpl, err = template.ParseFiles(landingTplFile, navTplFile, footerTplFile)
- if err != nil {
- log.Fatal(err)
- os.Exit(1)
- }
- lookupResultTplFile := t.Cfg.Section("taldir").Key("lookup_result_page").MustString("web/templates/lookup_result.html")
- t.LookupResultPageTpl, err = template.ParseFiles(lookupResultTplFile, navTplFile, footerTplFile)
- if err != nil {
- log.Fatal(err)
- os.Exit(1)
- }
- 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_base_url").MustString("http://merchant.taldir/")
- //merchToken := t.Cfg.Section("taldir").Key("merchant_token").MustString("secretAccessToken")
- //t.Merchant = merchant.NewMerchant(merchURL, merchToken)
- //merchConfig, err := t.Merchant.GetConfig()
- //if nil != err {
- // log.Fatal("Failed to get merchant config")
- // os.Exit(1)
- //}
- //registrationCost, _ := talerutil.ParseAmount(t.MonthlyFee)
- //currencySpec, currencySupported := merchConfig.Currencies[registrationCost.Currency]
- //for !currencySupported {
- // log.Fatalf("Currency `%s' not supported by merchant!\n", registrationCost.Currency)
- // os.Exit(1)
- //}
- //t.CurrencySpec = currencySpec
- t.setupHandlers()
+ _cfg, err := ini.LooseLoad(cfgfile)
+ if err != nil {
+ log.Fatalf("Failed to read config: %v", err)
+ os.Exit(1)
+ }
+ t.Cfg = _cfg
+ t.I18n, err = i18n.New(i18n.Glob("./locales/*/*", i18n.LoaderConfig{
+ // Set custom functions per locale!
+ Funcs: getFuncs,
+ }), "en-US", "de-DE")
+ if err != nil {
+ panic(err)
+ }
+ if t.Cfg.Section("taldir").Key("production").MustBool(false) {
+ fmt.Println("Production mode enabled")
+ }
+
+ navTplFile := t.Cfg.Section("taldir").Key("navigation").MustString("web/templates/nav.html")
+ footerTplFile := t.Cfg.Section("taldir").Key("footer").MustString("web/templates/footer.html")
+ t.Version = version
+ t.BaseUrl = t.Cfg.Section("taldir").Key("base_url").MustString("http://localhost:11000")
+ t.Validators = make(map[string]Validator)
+ for _, sec := range t.Cfg.Sections() {
+ if !strings.HasPrefix(sec.Name(), "taldir-validator-") {
+ continue
+ }
+ if !sec.HasKey("type") {
+ log.Printf("`type` key in section `[%s]` not found, disabling validator.\n", sec.Name())
+ continue
+ }
+ vname := strings.TrimPrefix(sec.Name(), "taldir-validator-")
+ vlandingPageTplFile := sec.Key("registration_page").MustString("web/templates/landing_" + vname + ".html")
+ vlandingPageTpl, err := template.ParseFiles(vlandingPageTplFile, navTplFile, footerTplFile)
+ if err != nil {
+ log.Printf("`%s` template not found, disabling validator `%s`.\n", vlandingPageTplFile, vname)
+ continue
+ }
+ t.Validators[vname] = Validator{
+ Name: vname,
+ LandingPageTpl: vlandingPageTpl,
+ ChallengeFee: sec.Key("challenge_fee").MustString("KUDOS:0"),
+ PaymentRequired: sec.Key("enabled").MustBool(false),
+ Command: sec.Key("command").MustString(""),
+ Type: ValidatorType(sec.Key("type").MustString("")),
+ ValidAliasRegex: sec.Key("valid_alias_regex").MustString(""),
+ }
+ }
+ 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.ValidPMSRegex = t.Cfg.Section("taldir").Key("valid_payment_system_address_regex").MustString("[A-Z]+")
+ t.ValidationTimeframe, err = time.ParseDuration(validationTTLStr)
+ if err != nil {
+ log.Fatal(err)
+ os.Exit(1)
+ }
+
+ retryTimeframeStr := t.Cfg.Section("taldir").Key("solution_attempt_timeframe").MustString("1h")
+ t.SolutionTimeframe, err = time.ParseDuration(retryTimeframeStr)
+ if err != nil {
+ log.Fatal(err)
+ os.Exit(1)
+ }
+ 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)
+ }
+ if t.Cfg.Section("taldir").Key("purge_mappings_on_startup_dangerous").MustBool(false) {
+ log.Println("DANGER Purging mappings!")
+ tx := t.Db.Where("1 = 1").Delete(&entry{})
+ log.Printf("Deleted %d entries.\n", tx.RowsAffected)
+ }
+ // Clean up validations
+ validationExpStr := t.Cfg.Section("taldir").Key("validation_expiration").MustString("24h")
+ validationExp, err := time.ParseDuration(validationExpStr)
+ if err != nil {
+ log.Fatal(err)
+ os.Exit(1)
+ }
+ 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("web/templates/validation_landing.html")
+ t.ValidationTpl, err = template.ParseFiles(validationLandingTplFile, navTplFile, footerTplFile)
+ if err != nil {
+ log.Fatal(err)
+ os.Exit(1)
+ }
+ landingTplFile := t.Cfg.Section("taldir").Key("landing_page").MustString("web/templates/landing.html")
+ t.LandingPageTpl, err = template.ParseFiles(landingTplFile, navTplFile, footerTplFile)
+ if err != nil {
+ log.Fatal(err)
+ os.Exit(1)
+ }
+ lookupResultTplFile := t.Cfg.Section("taldir").Key("lookup_result_page").MustString("web/templates/lookup_result.html")
+ t.LookupResultPageTpl, err = template.ParseFiles(lookupResultTplFile, navTplFile, footerTplFile)
+ if err != nil {
+ log.Fatal(err)
+ os.Exit(1)
+ }
+ 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_base_url").MustString("http://merchant.taldir/")
+ //merchToken := t.Cfg.Section("taldir").Key("merchant_token").MustString("secretAccessToken")
+ //t.Merchant = merchant.NewMerchant(merchURL, merchToken)
+ //merchConfig, err := t.Merchant.GetConfig()
+ //if nil != err {
+ // log.Fatal("Failed to get merchant config")
+ // os.Exit(1)
+ //}
+ //registrationCost, _ := talerutil.ParseAmount(t.MonthlyFee)
+ //currencySpec, currencySupported := merchConfig.Currencies[registrationCost.Currency]
+ //for !currencySupported {
+ // log.Fatalf("Currency `%s' not supported by merchant!\n", registrationCost.Currency)
+ // os.Exit(1)
+ //}
+ //t.CurrencySpec = currencySpec
+ t.setupHandlers()
}
diff --git a/web/templates/landing_email.html b/web/templates/landing_email.html
@@ -15,9 +15,9 @@
{{if .error}}
<div class="container pt-5">
<div id="ebanner" class="alert alert-danger" role="alert">
- <h4 class="alert-heading">An error occured!</h4>
+ <h4 class="alert-heading">Error</h4>
<hr>
- <p class="mb-0">{{.error}}.</p>
+ <p class="mb-0">{{.error}}</p>
</div>
</div>
{{end}}