From dcb254618dc5541bb50c488c96b5e02c36951c06 Mon Sep 17 00:00:00 2001 From: Benjamin Morrison Date: Tue, 19 Oct 2021 01:26:27 -0400 Subject: config for admin password, store bcrypt hash in confObj --- .gitignore | 1 + getwtxt.yml | 3 +++ go.mod | 3 ++- go.sum | 7 +++++++ svc/common.go | 16 ++++++++++++++++ svc/common_test.go | 34 ++++++++++++++++++++++++++++++++++ svc/conf.go | 13 +++++++++++++ 7 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 svc/common.go create mode 100644 svc/common_test.go diff --git a/.gitignore b/.gitignore index 90b4945..f009869 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ logs/ local/ *.db/ *.db +/.idea diff --git a/getwtxt.yml b/getwtxt.yml index 8945993..5127e77 100644 --- a/getwtxt.yml +++ b/getwtxt.yml @@ -40,6 +40,9 @@ DatabasePath: "getwtxt.db" ## changes are detected. ## ############################################################# +# Administrator password for certain destructive actions +AdminPassword: "please_change_me" + # The path to the assets directory, which contains: # style.css # tmpl/index.html diff --git a/go.mod b/go.mod index 2013e93..dfa6f22 100644 --- a/go.mod +++ b/go.mod @@ -10,5 +10,6 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.0 github.com/syndtr/goleveldb v1.0.0 - golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 ) diff --git a/go.sum b/go.sum index fdd4551..1d2a295 100644 --- a/go.sum +++ b/go.sum @@ -203,6 +203,8 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -237,6 +239,7 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -262,10 +265,14 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/svc/common.go b/svc/common.go new file mode 100644 index 0000000..5f169af --- /dev/null +++ b/svc/common.go @@ -0,0 +1,16 @@ +package svc + +import "golang.org/x/crypto/bcrypt" + +// HashPass returns the bcrypt hash of the provided string. +// If an empty string is provided, return an empty string. +func HashPass(s string) (string, error) { + if s == "" { + return "", nil + } + h, err := bcrypt.GenerateFromPassword([]byte(s), 14) + if err != nil { + return "", err + } + return string(h), nil +} diff --git a/svc/common_test.go b/svc/common_test.go new file mode 100644 index 0000000..d9a08b3 --- /dev/null +++ b/svc/common_test.go @@ -0,0 +1,34 @@ +package svc + +import ( + "testing" +) + +func TestHashPass(t *testing.T) { + cases := []struct { + in, name string + shouldFail bool + }{ + { + in: "foo", + name: "non-empty password", + shouldFail: false, + }, + { + in: "", + name: "empty password", + shouldFail: true, + }, + } + for _, v := range cases { + t.Run(v.name, func(t *testing.T) { + out, err := HashPass(v.in) + if err != nil && !v.shouldFail { + t.Errorf("Shouldn't have failed: Case %s, Error: %s", v.name, err) + } + if out == "" && v.in != "" { + t.Errorf("Got empty out for case %s input %s", v.name, v.in) + } + }) + } +} diff --git a/svc/conf.go b/svc/conf.go index 7365b2b..5f826fb 100644 --- a/svc/conf.go +++ b/svc/conf.go @@ -20,6 +20,7 @@ along with Getwtxt. If not, see . package svc // import "git.sr.ht/~gbmor/getwtxt/svc" import ( + "fmt" "log" "os" "path/filepath" @@ -43,6 +44,7 @@ type Configuration struct { DBPath string `yaml:"DatabasePath"` AssetsDir string `yaml:"AssetsDirectory"` StaticDir string `yaml:"StaticFilesDirectory"` + AdminPassHash string `yaml:"-"` StdoutLogging bool `yaml:"StdoutLogging"` CacheInterval time.Duration `yaml:"StatusFetchInterval"` DBInterval time.Duration `yaml:"DatabasePushInterval"` @@ -126,6 +128,7 @@ func setConfigDefaults() { viper.SetDefault("StdoutLogging", false) viper.SetDefault("ReCacheInterval", "1h") viper.SetDefault("DatabasePushInterval", "5m") + viper.SetDefault("AdminPassword", "please_change_me") viper.SetDefault("Instance.SiteName", "getwtxt") viper.SetDefault("Instance.OwnerName", "Anonymous Microblogger") @@ -173,6 +176,16 @@ func bindConfig() { confObj.StdoutLogging = viper.GetBool("StdoutLogging") confObj.CacheInterval = viper.GetDuration("StatusFetchInterval") confObj.DBInterval = viper.GetDuration("DatabasePushInterval") + txtPass := viper.GetString("AdminPassword") + if txtPass == "please_change_me" { + fmt.Println("Please set AdminPassword in getwtxt.yml") + os.Exit(1) + } + passHash, err := HashPass(txtPass) + if err != nil { + errFatal("Failed to hash administrator password: ", err) + } + confObj.AdminPassHash = passHash confObj.Instance.Vers = Vers confObj.Instance.Name = viper.GetString("Instance.SiteName") -- cgit 1.4.1-2-gfad0