diff --git a/cmd/owl/reset_password.go b/cmd/owl/reset_password.go new file mode 100644 index 0000000..6c9506c --- /dev/null +++ b/cmd/owl/reset_password.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "h4kor/owl-blogs" + "math/rand" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(resetPasswordCmd) +} + +var resetPasswordCmd = &cobra.Command{ + Use: "reset-password", + Short: "Reset the password for a user", + Long: `Reset the password for a user`, + Run: func(cmd *cobra.Command, args []string) { + if user == "" { + println("Username is required") + return + } + + repo, err := owl.OpenRepository(repoPath) + if err != nil { + println("Error opening repository: ", err.Error()) + return + } + + user, err := repo.GetUser(user) + if err != nil { + println("Error getting user: ", err.Error()) + return + } + + // generate a random password and print it + const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + b := make([]byte, 16) + for i := range b { + b[i] = chars[rand.Intn(len(chars))] + } + password := string(b) + + user.ResetPassword(password) + + fmt.Println("User: ", user.Name()) + fmt.Println("New Password: ", password) + + }, +} diff --git a/go.mod b/go.mod index 910f421..b6e1a3e 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,12 @@ require ( github.com/julienschmidt/httprouter v1.3.0 github.com/spf13/cobra v1.5.0 github.com/yuin/goldmark v1.4.13 - golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b + golang.org/x/net v0.1.0 gopkg.in/yaml.v2 v2.4.0 ) require ( github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/crypto v0.1.0 // indirect ) diff --git a/go.sum b/go.sum index 1783953..910f1b6 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,12 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/renderer_test.go b/renderer_test.go index 34f70b1..a5e9302 100644 --- a/renderer_test.go +++ b/renderer_test.go @@ -21,7 +21,7 @@ func TestCanRenderPost(t *testing.T) { func TestRenderOneMe(t *testing.T) { user := getTestUser() - config, _ := user.Config() + config := user.Config() config.Me = append(config.Me, owl.UserMe{ Name: "Twitter", Url: "https://twitter.com/testhandle", @@ -38,7 +38,7 @@ func TestRenderOneMe(t *testing.T) { func TestRenderTwoMe(t *testing.T) { user := getTestUser() - config, _ := user.Config() + config := user.Config() config.Me = append(config.Me, owl.UserMe{ Name: "Twitter", Url: "https://twitter.com/testhandle", diff --git a/rss.go b/rss.go index 87002f4..8a4c95e 100644 --- a/rss.go +++ b/rss.go @@ -29,7 +29,7 @@ type RSSItem struct { func RenderRSSFeed(user User) (string, error) { - config, _ := user.Config() + config := user.Config() rss := RSS{ Version: "2.0", diff --git a/user.go b/user.go index fb7d4f0..4b202ef 100644 --- a/user.go +++ b/user.go @@ -8,6 +8,7 @@ import ( "sort" "time" + "golang.org/x/crypto/bcrypt" "gopkg.in/yaml.v2" ) @@ -22,6 +23,7 @@ type UserConfig struct { HeaderColor string `yaml:"header_color"` AuthorName string `yaml:"author_name"` Me []UserMe `yaml:"me"` + PassworHash string `yaml:"password_hash"` } type UserMe struct { @@ -207,10 +209,10 @@ func (user User) Template() (string, error) { return string(base_html), nil } -func (user User) Config() (UserConfig, error) { +func (user User) Config() UserConfig { meta := UserConfig{} - err := loadFromYaml(user.ConfigFile(), &meta) - return meta, err + loadFromYaml(user.ConfigFile(), &meta) + return meta } func (user User) SetConfig(new_config UserConfig) error { @@ -233,3 +235,13 @@ func (user User) PostAliases() (map[string]*Post, error) { } return post_aliases, nil } + +func (user User) ResetPassword(password string) error { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10) + if err != nil { + return err + } + config := user.Config() + config.PassworHash = string(bytes) + return user.SetConfig(config) +} diff --git a/user_test.go b/user_test.go index 5f42c41..d1ca83c 100644 --- a/user_test.go +++ b/user_test.go @@ -295,3 +295,10 @@ func TestFaviconSetIfFileExist(t *testing.T) { os.WriteFile(path.Join(user.MediaDir(), "favicon.ico"), []byte("test"), 0644) assertions.Assert(t, user.FaviconUrl() != "", "Favicon should not be empty") } + +func TestResetUserPassword(t *testing.T) { + user := getTestUser() + user.ResetPassword("test") + assertions.Assert(t, user.Config().PassworHash != "", "Password Hash should not be empty") + assertions.Assert(t, user.Config().PassworHash != "test", "Password Hash should not be test") +}