🔒 Check permissions
This commit is contained in:
		
							parent
							
								
									5961b33ba0
								
							
						
					
					
						commit
						99bce4d1fc
					
				
							
								
								
									
										25
									
								
								store.go
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								store.go
									
									
									
									
									
								
							| @ -56,6 +56,7 @@ type ShareStore interface { | |||||||
| 	GetShares() ([]Share, error) | 	GetShares() ([]Share, error) | ||||||
| 	GetShareUsers(share Share) ([]ShareUser, error) | 	GetShareUsers(share Share) ([]ShareUser, error) | ||||||
| 	GetShareLogins(share Share, username string) ([]Login, error) | 	GetShareLogins(share Share, username string) ([]Login, error) | ||||||
|  | 	GetShareAccess(share Share, username string) (ShareRole, error) | ||||||
| 
 | 
 | ||||||
| 	FindShareByLogin(username, loginName string) (LoginShare, error) | 	FindShareByLogin(username, loginName string) (LoginShare, error) | ||||||
| 	FindSharesByUser(username string) ([]UserShare, error) | 	FindSharesByUser(username string) ([]UserShare, error) | ||||||
| @ -384,6 +385,30 @@ func (store *DBStore) AddUserToShare(share Share, username string, role ShareRol | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (store *DBStore) GetShareAccess(share Share, username string) (ShareRole, error) { | ||||||
|  | 	if strings.Contains(username, ":") { | ||||||
|  | 		return "", ErrInvalidUsername | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var shareRole ShareRole | ||||||
|  | 
 | ||||||
|  | 	err := store.db.View(func(tx *buntdb.Tx) error { | ||||||
|  | 		if _, err := tx.Get(share.key()); err != nil { | ||||||
|  | 			return ErrShareNotFound | ||||||
|  | 		} | ||||||
|  | 		if val, err := tx.Get(share.userKey(username)); err == buntdb.ErrNotFound { | ||||||
|  | 			return ErrUserNotFound | ||||||
|  | 		} else if err != nil { | ||||||
|  | 			return fmt.Errorf("cannot get user: %w", err) | ||||||
|  | 		} else { | ||||||
|  | 			shareRole = ShareRole(val) | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	return shareRole, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (store *DBStore) removeUserFromShare(tx *buntdb.Tx, share Share, username string) error { | func (store *DBStore) removeUserFromShare(tx *buntdb.Tx, share Share, username string) error { | ||||||
| 	var logins []string | 	var logins []string | ||||||
| 	loginsPrefix := share.loginKey(username, "") | 	loginsPrefix := share.loginKey(username, "") | ||||||
|  | |||||||
| @ -244,6 +244,23 @@ func TestStoreShareHandling(t *testing.T) { | |||||||
| 				} | 				} | ||||||
| 			}) | 			}) | ||||||
| 
 | 
 | ||||||
|  | 			t.Run("can get share access", func(t *testing.T) { | ||||||
|  | 				shareRole, err := store.GetShareAccess(share1, user1.Username) | ||||||
|  | 				if err != nil { | ||||||
|  | 					t.Errorf("unexpected error: %v", err) | ||||||
|  | 				} | ||||||
|  | 				if shareRole != ShareRoleAdmin { | ||||||
|  | 					t.Errorf("unexpected role: %s", shareRole) | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 
 | ||||||
|  | 			t.Run("cannot get share access if user has none", func(t *testing.T) { | ||||||
|  | 				_, err := store.GetShareAccess(share2, user1.Username) | ||||||
|  | 				if err != ErrUserNotFound { | ||||||
|  | 					t.Errorf("unexpected error: %v", err) | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 
 | ||||||
| 			t.Run("can list users", func(t *testing.T) { | 			t.Run("can list users", func(t *testing.T) { | ||||||
| 				users, err := store.GetShareUsers(share1) | 				users, err := store.GetShareUsers(share1) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
|  | |||||||
							
								
								
									
										62
									
								
								webadmin.go
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								webadmin.go
									
									
									
									
									
								
							| @ -57,6 +57,7 @@ type sessionContext struct { | |||||||
| 	h         *webAdminHandler | 	h         *webAdminHandler | ||||||
| 	w         http.ResponseWriter | 	w         http.ResponseWriter | ||||||
| 	r         *http.Request | 	r         *http.Request | ||||||
|  | 	user      User | ||||||
| 	baseModel map[string]interface{} | 	baseModel map[string]interface{} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -181,6 +182,11 @@ func newWebAdminHandler(app *app) *webAdminHandler { | |||||||
| 	ar.Get("/users", func(w http.ResponseWriter, r *http.Request) { | 	ar.Get("/users", func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		sessionContext := h.buildSessionContext(w, r) | 		sessionContext := h.buildSessionContext(w, r) | ||||||
| 
 | 
 | ||||||
|  | 		if sessionContext.user.Role != GlobalRoleAdmin { | ||||||
|  | 			sessionContext.Unauthorized() | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		users, err := app.userStore.GetUsers() | 		users, err := app.userStore.GetUsers() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
| @ -194,6 +200,11 @@ func newWebAdminHandler(app *app) *webAdminHandler { | |||||||
| 	ar.Get("/shares", func(w http.ResponseWriter, r *http.Request) { | 	ar.Get("/shares", func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		sessionContext := h.buildSessionContext(w, r) | 		sessionContext := h.buildSessionContext(w, r) | ||||||
| 
 | 
 | ||||||
|  | 		if sessionContext.user.Role != GlobalRoleAdmin { | ||||||
|  | 			sessionContext.Unauthorized() | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		shares, err := app.shareStore.GetShares() | 		shares, err := app.shareStore.GetShares() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
| @ -224,12 +235,20 @@ func newWebAdminHandler(app *app) *webAdminHandler { | |||||||
| 		r.Get("/", func(w http.ResponseWriter, r *http.Request) { | 		r.Get("/", func(w http.ResponseWriter, r *http.Request) { | ||||||
| 			sessionContext := h.buildSessionContext(w, r) | 			sessionContext := h.buildSessionContext(w, r) | ||||||
| 
 | 
 | ||||||
| 			shareId := r.URL.Query().Get("share") | 			share, err := app.shareStore.GetShare(r.URL.Query().Get("share")) | ||||||
| 			if shareId == "" { | 			if err != nil { | ||||||
| 				http.Error(w, "invalid share id", http.StatusBadRequest) | 				sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), "") | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			if sessionContext.user.Role != GlobalRoleAdmin { | ||||||
|  | 				shareRole, err := app.shareStore.GetShareAccess(share, sessionContext.user.Username) | ||||||
|  | 				if err != nil || shareRole != ShareRoleAdmin { | ||||||
|  | 					sessionContext.Unauthorized() | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			users, err := app.userStore.GetUsers() | 			users, err := app.userStore.GetUsers() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				http.Error(w, err.Error(), http.StatusInternalServerError) | 				http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
| @ -237,7 +256,7 @@ func newWebAdminHandler(app *app) *webAdminHandler { | |||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			sessionContext.RenderPage(h.tplShareAddUser, map[string]interface{}{ | 			sessionContext.RenderPage(h.tplShareAddUser, map[string]interface{}{ | ||||||
| 				"ShareId": shareId, | 				"ShareId": share.UUID, | ||||||
| 				"Users":   users, | 				"Users":   users, | ||||||
| 			}) | 			}) | ||||||
| 		}) | 		}) | ||||||
| @ -246,12 +265,19 @@ func newWebAdminHandler(app *app) *webAdminHandler { | |||||||
| 
 | 
 | ||||||
| 			returnURL := "share-add-user?share=" + r.FormValue("share") | 			returnURL := "share-add-user?share=" + r.FormValue("share") | ||||||
| 
 | 
 | ||||||
| 			shareId, err := uuid.FromString(r.FormValue("share")) | 			share, err := app.shareStore.GetShare(r.FormValue("share")) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), "") | 				sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), "") | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 			share := Share{UUID: shareId} | 
 | ||||||
|  | 			if sessionContext.user.Role != GlobalRoleAdmin { | ||||||
|  | 				shareRole, err := app.shareStore.GetShareAccess(share, sessionContext.user.Username) | ||||||
|  | 				if err != nil || shareRole != ShareRoleAdmin { | ||||||
|  | 					sessionContext.Unauthorized() | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			user, err := app.userStore.GetUser(r.FormValue("user")) | 			user, err := app.userStore.GetUser(r.FormValue("user")) | ||||||
| 			if err == ErrUserNotFound { | 			if err == ErrUserNotFound { | ||||||
| @ -276,12 +302,19 @@ func newWebAdminHandler(app *app) *webAdminHandler { | |||||||
| 
 | 
 | ||||||
| 		returnURL := "shares" | 		returnURL := "shares" | ||||||
| 
 | 
 | ||||||
| 		shareId, err := uuid.FromString(r.FormValue("share")) | 		share, err := app.shareStore.GetShare(r.FormValue("share")) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), "") | 			sessionContext.RenderError(template.HTML("Internal error: "+err.Error()), "") | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		share := Share{UUID: shareId} | 
 | ||||||
|  | 		if sessionContext.user.Role != GlobalRoleAdmin { | ||||||
|  | 			shareRole, err := app.shareStore.GetShareAccess(share, sessionContext.user.Username) | ||||||
|  | 			if err != nil || shareRole != ShareRoleAdmin { | ||||||
|  | 				sessionContext.Unauthorized() | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		err = app.shareStore.RemoveUserFromShare(share, r.FormValue("user")) | 		err = app.shareStore.RemoveUserFromShare(share, r.FormValue("user")) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -325,6 +358,14 @@ func newWebAdminHandler(app *app) *webAdminHandler { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if sessionContext.user.Role != GlobalRoleAdmin { | ||||||
|  | 			shareRole, err := app.shareStore.GetShareAccess(share, sessionContext.user.Username) | ||||||
|  | 			if err != nil || shareRole != ShareRoleAdmin { | ||||||
|  | 				sessionContext.Unauthorized() | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		message := fmt.Sprintf(`You are about to delete the share %s (%s).<br/> | 		message := fmt.Sprintf(`You are about to delete the share %s (%s).<br/> | ||||||
| This will delete all data permanently.<br/><br/> | This will delete all data permanently.<br/><br/> | ||||||
| Are you sure you want to continue?`, share.UUID, share.Name) | Are you sure you want to continue?`, share.UUID, share.Name) | ||||||
| @ -357,6 +398,7 @@ func (h *webAdminHandler) buildSessionContext(w http.ResponseWriter, r *http.Req | |||||||
| 	} | 	} | ||||||
| 	sessionUser := userFromContext(r) | 	sessionUser := userFromContext(r) | ||||||
| 	if sessionUser != nil { | 	if sessionUser != nil { | ||||||
|  | 		sessionContext.user = *sessionUser | ||||||
| 		sessionContext.baseModel["SessionUser"] = sessionUser | 		sessionContext.baseModel["SessionUser"] = sessionUser | ||||||
| 	} | 	} | ||||||
| 	return sessionContext | 	return sessionContext | ||||||
| @ -387,6 +429,10 @@ func (s *sessionContext) RenderError(msg template.HTML, returnURL string) { | |||||||
| 	s.RenderPage(s.h.tplError, model) | 	s.RenderPage(s.h.tplError, model) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (s *sessionContext) Unauthorized() { | ||||||
|  | 	http.Error(s.w, http.StatusText(http.StatusForbidden), http.StatusForbidden) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (s *sessionContext) RequestConfirmation(msg template.HTML, returnURL string) int { | func (s *sessionContext) RequestConfirmation(msg template.HTML, returnURL string) int { | ||||||
| 	if s.r.FormValue("_yes") != "" { | 	if s.r.FormValue("_yes") != "" { | ||||||
| 		return confirmAccepted | 		return confirmAccepted | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user