taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

commit cd47ac4772a7739a21da47890775e5e469fad360
parent 3fc03097ac091b8bef4a1a05af885c2cb1ddf455
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Thu, 23 Jan 2025 13:56:18 +0100

more error handling

Diffstat:
Mlocales/de-DE/taldir.yml | 1+
Mlocales/en-US/taldir.yml | 1+
Mpkg/rest/taldir.go | 526++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mweb/templates/landing_email.html | 4++--
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}}