⚡️ Implemented login management

This commit is contained in:
2020-10-28 19:59:29 +01:00
parent 99bce4d1fc
commit 6993a9f58b
5 changed files with 421 additions and 183 deletions
+195 -46
View File
@@ -42,15 +42,18 @@ import (
)
type webAdminHandler struct {
router chi.Router
tplError *template.Template
tplConfirm *template.Template
tplLogin *template.Template
tplIndex *template.Template
tplUsers *template.Template
tplShares *template.Template
tplShareAddUser *template.Template
tplCreateShare *template.Template
router chi.Router
shareStore ShareStore
tplError *template.Template
tplConfirm *template.Template
tplLogin *template.Template
tplIndex *template.Template
tplUsers *template.Template
tplShares *template.Template
tplMyShares *template.Template
tplShareAddUser *template.Template
tplShareAddLogin *template.Template
tplCreateShare *template.Template
}
type sessionContext struct {
@@ -93,14 +96,17 @@ func newWebAdminHandler(app *app) *webAdminHandler {
}
h := &webAdminHandler{
tplError: loadTemplate("error"),
tplConfirm: loadTemplate("confirm"),
tplLogin: loadSingleTemplate("login"),
tplIndex: loadTemplate("index"),
tplUsers: loadTemplate("users"),
tplShares: loadTemplate("shares"),
tplShareAddUser: loadTemplate("share-add-user"),
tplCreateShare: loadTemplate("create-share"),
shareStore: app.shareStore,
tplError: loadTemplate("error"),
tplConfirm: loadTemplate("confirm"),
tplLogin: loadSingleTemplate("login"),
tplIndex: loadTemplate("index"),
tplUsers: loadTemplate("users"),
tplShares: loadTemplate("shares"),
tplMyShares: loadTemplate("my-shares"),
tplShareAddUser: loadTemplate("share-add-user"),
tplShareAddLogin: loadTemplate("share-add-login"),
tplCreateShare: loadTemplate("create-share"),
}
r := chi.NewRouter()
@@ -231,6 +237,54 @@ func newWebAdminHandler(app *app) *webAdminHandler {
"ShareInfos": shareInfos,
})
})
ar.Get("/my-shares", func(w http.ResponseWriter, r *http.Request) {
sessionContext := h.buildSessionContext(w, r)
shares, err := app.shareStore.FindSharesByUser(sessionContext.user.Username)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
type shareInfo struct {
Share
IsAdmin bool
Logins []Login
Users []ShareUser
}
shareInfos := make([]shareInfo, len(shares))
for i := range shares {
shareInfos[i].Share = shares[i].Share
shareRole, err := app.shareStore.GetShareAccess(shares[i].Share, sessionContext.user.Username)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
shareInfos[i].IsAdmin = sessionContext.user.Role == GlobalRoleAdmin ||
shareRole == ShareRoleAdmin
if shareInfos[i].IsAdmin {
users, err := app.shareStore.GetShareUsers(shares[i].Share)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
shareInfos[i].Users = users
}
logins, err := app.shareStore.GetShareLogins(shares[i].Share, sessionContext.user.Username)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
shareInfos[i].Logins = logins
}
sessionContext.RenderPage(h.tplMyShares, map[string]interface{}{
"ShareInfos": shareInfos,
})
})
ar.Route("/share-add-user", func(r chi.Router) {
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
sessionContext := h.buildSessionContext(w, r)
@@ -241,12 +295,9 @@ func newWebAdminHandler(app *app) *webAdminHandler {
return
}
if sessionContext.user.Role != GlobalRoleAdmin {
shareRole, err := app.shareStore.GetShareAccess(share, sessionContext.user.Username)
if err != nil || shareRole != ShareRoleAdmin {
sessionContext.Unauthorized()
return
}
if !sessionContext.IsAdmin(share) {
sessionContext.Unauthorized()
return
}
users, err := app.userStore.GetUsers()
@@ -271,12 +322,9 @@ func newWebAdminHandler(app *app) *webAdminHandler {
return
}
if sessionContext.user.Role != GlobalRoleAdmin {
shareRole, err := app.shareStore.GetShareAccess(share, sessionContext.user.Username)
if err != nil || shareRole != ShareRoleAdmin {
sessionContext.Unauthorized()
return
}
if !sessionContext.IsAdmin(share) {
sessionContext.Unauthorized()
return
}
user, err := app.userStore.GetUser(r.FormValue("user"))
@@ -300,6 +348,94 @@ func newWebAdminHandler(app *app) *webAdminHandler {
ar.Post("/share-delete-user", func(w http.ResponseWriter, r *http.Request) {
sessionContext := h.buildSessionContext(w, r)
returnURL := r.FormValue("source")
share, err := app.shareStore.GetShare(r.FormValue("share"))
if err != nil {
sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), "")
return
}
if !sessionContext.IsAdmin(share) {
sessionContext.Unauthorized()
return
}
username := r.FormValue("user")
message := fmt.Sprintf(`You are about to delete the user &quot;%s&quot; from the share %s.<br/>
This will irrevocably also remove all logins of that user.<br/><br/>
Are you sure you want to continue?`, username, share.Name)
if confirmStatus := sessionContext.RequestConfirmation(template.HTML(message), "share-delete-user"); confirmStatus == confirmRequested {
// We have already rendered. Nothing to do.
return
} else if confirmStatus == confirmAccepted {
err = app.shareStore.RemoveUserFromShare(share, username)
if err != nil {
sessionContext.RenderError(template.HTML("Cannot remove user from share: "+err.Error()), returnURL)
return
}
}
http.Redirect(w, r, returnURL, http.StatusFound)
})
ar.Route("/share-add-login", func(r chi.Router) {
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
sessionContext := h.buildSessionContext(w, r)
share, err := app.shareStore.GetShare(r.URL.Query().Get("share"))
if err != nil {
sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), "")
return
}
if !sessionContext.IsAdmin(share) {
sessionContext.Unauthorized()
return
}
sessionContext.RenderPage(h.tplShareAddLogin, map[string]interface{}{
"ShareId": share.UUID,
})
})
r.Post("/", func(w http.ResponseWriter, r *http.Request) {
sessionContext := h.buildSessionContext(w, r)
returnURL := "share-add-login?share=" + r.FormValue("share")
share, err := app.shareStore.GetShare(r.FormValue("share"))
if err != nil {
sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), returnURL)
return
}
if !sessionContext.IsAdmin(share) {
sessionContext.Unauthorized()
return
}
pwHash, err := bcrypt.GenerateFromPassword([]byte(r.FormValue("password")), bcrypt.DefaultCost)
if err != nil {
sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), returnURL)
return
}
err = app.shareStore.AddLogin(share, sessionContext.user.Username, Login{
LoginName: r.FormValue("login"),
Password: string(pwHash),
ReadOnly: r.FormValue("readonly") == "on",
})
if err != nil {
sessionContext.RenderError(template.HTML("Cannot add login: "+err.Error()), returnURL)
return
}
sessionContext.Redirect("my-shares")
})
})
ar.Post("/share-delete-login", func(w http.ResponseWriter, r *http.Request) {
sessionContext := h.buildSessionContext(w, r)
returnURL := "shares"
share, err := app.shareStore.GetShare(r.FormValue("share"))
@@ -308,21 +444,27 @@ func newWebAdminHandler(app *app) *webAdminHandler {
return
}
if sessionContext.user.Role != GlobalRoleAdmin {
shareRole, err := app.shareStore.GetShareAccess(share, sessionContext.user.Username)
if err != nil || shareRole != ShareRoleAdmin {
sessionContext.Unauthorized()
if !sessionContext.IsAdmin(share) {
sessionContext.Unauthorized()
return
}
loginName := r.FormValue("login")
message := fmt.Sprintf(`You are about to delete the login &quot;%s&quot;.<br/><br/>
Are you sure you want to continue?`, loginName)
if confirmStatus := sessionContext.RequestConfirmation(template.HTML(message), "share-delete-login"); confirmStatus == confirmRequested {
// We have already rendered. Nothing to do.
return
} else if confirmStatus == confirmAccepted {
err = app.shareStore.RemoveLogin(share, sessionContext.user.Username, loginName)
if err != nil {
sessionContext.RenderError(template.HTML("Cannot remove login from share: "+err.Error()), returnURL)
return
}
}
err = app.shareStore.RemoveUserFromShare(share, r.FormValue("user"))
if err != nil {
sessionContext.RenderError(template.HTML("Cannot remove user from share: "+err.Error()), returnURL)
return
}
http.Redirect(w, r, "shares", http.StatusFound)
http.Redirect(w, r, "my-shares", http.StatusFound)
})
ar.Route("/create-share", func(r chi.Router) {
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
@@ -358,12 +500,9 @@ func newWebAdminHandler(app *app) *webAdminHandler {
return
}
if sessionContext.user.Role != GlobalRoleAdmin {
shareRole, err := app.shareStore.GetShareAccess(share, sessionContext.user.Username)
if err != nil || shareRole != ShareRoleAdmin {
sessionContext.Unauthorized()
return
}
if !sessionContext.IsAdmin(share) {
sessionContext.Unauthorized()
return
}
message := fmt.Sprintf(`You are about to delete the share %s (%s).<br/>
@@ -429,6 +568,16 @@ func (s *sessionContext) RenderError(msg template.HTML, returnURL string) {
s.RenderPage(s.h.tplError, model)
}
func (s *sessionContext) IsAdmin(share Share) bool {
if s.user.Role != GlobalRoleAdmin {
shareRole, err := s.h.shareStore.GetShareAccess(share, s.user.Username)
if err != nil || shareRole != ShareRoleAdmin {
return false
}
}
return true
}
func (s *sessionContext) Unauthorized() {
http.Error(s.w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
}