diff --git a/admin.go b/admin.go index fdbb82f..3b05bd4 100644 --- a/admin.go +++ b/admin.go @@ -16,12 +16,14 @@ import ( "net/http" "runtime" "strconv" + "strings" "time" "github.com/gorilla/mux" "github.com/writeas/impart" "github.com/writeas/web-core/auth" "github.com/writeas/web-core/log" + "github.com/writeas/web-core/passgen" "github.com/writeas/writefreely/appstats" "github.com/writeas/writefreely/config" ) @@ -170,11 +172,12 @@ func handleViewAdminUser(app *App, u *User, w http.ResponseWriter, r *http.Reque Config config.AppCfg Message string - User *User - Colls []inspectedCollection - LastPost string - - TotalPosts int64 + User *User + Colls []inspectedCollection + LastPost string + NewPassword string + TotalPosts int64 + ClearEmail string }{ Config: app.cfg.App, Message: r.FormValue("m"), @@ -186,6 +189,14 @@ func handleViewAdminUser(app *App, u *User, w http.ResponseWriter, r *http.Reque if err != nil { return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not get user: %v", err)} } + + flashes, _ := getSessionFlashes(app, w, r, nil) + for _, flash := range flashes { + if strings.HasPrefix(flash, "SUCCESS: ") { + p.NewPassword = strings.TrimPrefix(flash, "SUCCESS: ") + p.ClearEmail = p.User.EmailClear(app.keys) + } + } p.UserPage = NewUserPage(app, r, u, p.User.Username, nil) p.TotalPosts = app.db.GetUserPostsCount(p.User.ID) lp, err := app.db.GetUserLastPostTime(p.User.ID) @@ -230,6 +241,37 @@ func handleViewAdminUser(app *App, u *User, w http.ResponseWriter, r *http.Reque return nil } +func handleAdminResetUserPass(app *App, u *User, w http.ResponseWriter, r *http.Request) error { + vars := mux.Vars(r) + username := vars["username"] + if username == "" { + return impart.HTTPError{http.StatusFound, "/admin/users"} + } + // Generate new random password since none supplied + pass := passgen.NewWordish() + hashedPass, err := auth.HashPass([]byte(pass)) + if err != nil { + return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not create password hash: %v", err)} + } + + userIDVal := r.FormValue("user") + log.Info("ADMIN: Changing user %s password", userIDVal) + id, err := strconv.Atoi(userIDVal) + if err != nil { + return impart.HTTPError{http.StatusBadRequest, fmt.Sprintf("Invalid user ID: %v", err)} + } + + err = app.db.ChangePassphrase(int64(id), true, "", hashedPass) + if err != nil { + return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not update passphrase: %v", err)} + } + log.Info("ADMIN: Successfully changed.") + + addSessionFlash(app, w, r, fmt.Sprintf("SUCCESS: %s", pass), nil) + + return impart.HTTPError{http.StatusFound, fmt.Sprintf("/admin/user/%s", username)} +} + func handleViewAdminPages(app *App, u *User, w http.ResponseWriter, r *http.Request) error { p := struct { *UserPage diff --git a/go.mod b/go.mod index 9c67aeb..88af8c9 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/writeas/openssl-go v1.0.0 // indirect github.com/writeas/saturday v1.7.1 github.com/writeas/slug v1.2.0 - github.com/writeas/web-core v1.0.0 + github.com/writeas/web-core v1.2.0 github.com/writefreely/go-nodeinfo v1.2.0 golang.org/x/crypto v0.0.0-20190208162236-193df9c0f06f golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 // indirect diff --git a/go.sum b/go.sum index ec1e19d..b256223 100644 --- a/go.sum +++ b/go.sum @@ -135,6 +135,8 @@ github.com/writeas/slug v1.2.0 h1:EMQ+cwLiOcA6EtFwUgyw3Ge18x9uflUnOnR6bp/J+/g= github.com/writeas/slug v1.2.0/go.mod h1:RE8shOqQP3YhsfsQe0L3RnuejfQ4Mk+JjY5YJQFubfQ= github.com/writeas/web-core v1.0.0 h1:5VKkCakQgdKZcbfVKJXtRpc5VHrkflusCl/KRCPzpQ0= github.com/writeas/web-core v1.0.0/go.mod h1:Si3chV7VWgY8CsV+3gRolMXSO2Vx1ZFAQ/mkrpvmyEE= +github.com/writeas/web-core v1.2.0 h1:CYqvBd+byi1cK4mCr1NZ6CjILuMOFmiFecv+OACcmG0= +github.com/writeas/web-core v1.2.0/go.mod h1:vTYajviuNBAxjctPp2NUYdgjofywVkxUGpeaERF3SfI= github.com/writefreely/go-nodeinfo v1.2.0 h1:La+YbTCvmpTwFhBSlebWDDL81N88Qf/SCAvRLR7F8ss= github.com/writefreely/go-nodeinfo v1.2.0/go.mod h1:UTvE78KpcjYOlRHupZIiSEFcXHioTXuacCbHU+CAcPg= golang.org/x/crypto v0.0.0-20180527072434-ab813273cd59 h1:hk3yo72LXLapY9EXVttc3Z1rLOxT9IuAPPX3GpY2+jo= diff --git a/routes.go b/routes.go index 0113e93..de19ff2 100644 --- a/routes.go +++ b/routes.go @@ -144,6 +144,7 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router { write.HandleFunc("/admin", handler.Admin(handleViewAdminDash)).Methods("GET") write.HandleFunc("/admin/users", handler.Admin(handleViewAdminUsers)).Methods("GET") write.HandleFunc("/admin/user/{username}", handler.Admin(handleViewAdminUser)).Methods("GET") + write.HandleFunc("/admin/user/{username}/passphrase", handler.Admin(handleAdminResetUserPass)).Methods("POST") write.HandleFunc("/admin/pages", handler.Admin(handleViewAdminPages)).Methods("GET") write.HandleFunc("/admin/page/{slug}", handler.Admin(handleViewAdminPage)).Methods("GET") write.HandleFunc("/admin/update/config", handler.AdminApper(handleAdminUpdateConfig)).Methods("POST") diff --git a/templates/user/admin/view-user.tmpl b/templates/user/admin/view-user.tmpl index 2a74e5b..4157fca 100644 --- a/templates/user/admin/view-user.tmpl +++ b/templates/user/admin/view-user.tmpl @@ -7,12 +7,25 @@ table.classy th { h3 { font-weight: normal; } +input.copy-text { + text-align: center; + font-size: 1.2em; + color: #555; + width: 100%; + box-sizing: border-box; +}
{{template "admin-header" .}}

{{.User.Username}}

- + {{if .NewPassword}}
+

This user's password has been reset to:

+

+

They can use this new password to log in to their account. This will only be shown once, so be sure to copy it and send it to them now.

+ {{if .ClearEmail}}

Their email address is: {{.ClearEmail}}

{{end}} +
+ {{end}} @@ -38,6 +51,19 @@ h3 { + + + +
No.Last Post {{if .LastPost}}{{.LastPost}}{{else}}Never{{end}}
Password + {{if ne .Username .User.Username}} +
+ + +
+ {{else}} + Change your password + {{end}} +

Blogs

@@ -83,5 +109,15 @@ h3 { {{end}}
+ {{template "footer" .}} {{end}}