123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package server
- import (
- "errors"
- "heckel.io/ntfy/v2/user"
- "net/http"
- )
- func (s *Server) handleUsersGet(w http.ResponseWriter, r *http.Request, v *visitor) error {
- users, err := s.userManager.Users()
- if err != nil {
- return err
- }
- grants, err := s.userManager.AllGrants()
- if err != nil {
- return err
- }
- usersResponse := make([]*apiUserResponse, len(users))
- for i, u := range users {
- tier := ""
- if u.Tier != nil {
- tier = u.Tier.Code
- }
- userGrants := make([]*apiUserGrantResponse, len(grants[u.ID]))
- for i, g := range grants[u.ID] {
- userGrants[i] = &apiUserGrantResponse{
- Topic: g.TopicPattern,
- Permission: g.Allow.String(),
- }
- }
- usersResponse[i] = &apiUserResponse{
- Username: u.Name,
- Role: string(u.Role),
- Tier: tier,
- Grants: userGrants,
- }
- }
- return s.writeJSON(w, usersResponse)
- }
- func (s *Server) handleUsersAdd(w http.ResponseWriter, r *http.Request, v *visitor) error {
- req, err := readJSONWithLimit[apiUserAddRequest](r.Body, jsonBodyBytesLimit, false)
- if err != nil {
- return err
- } else if !user.AllowedUsername(req.Username) || req.Password == "" {
- return errHTTPBadRequest.Wrap("username invalid, or password missing")
- }
- u, err := s.userManager.User(req.Username)
- if err != nil && !errors.Is(err, user.ErrUserNotFound) {
- return err
- } else if u != nil {
- return errHTTPConflictUserExists
- }
- var tier *user.Tier
- if req.Tier != "" {
- tier, err = s.userManager.Tier(req.Tier)
- if errors.Is(err, user.ErrTierNotFound) {
- return errHTTPBadRequestTierInvalid
- } else if err != nil {
- return err
- }
- }
- if err := s.userManager.AddUser(req.Username, req.Password, user.RoleUser); err != nil {
- return err
- }
- if tier != nil {
- if err := s.userManager.ChangeTier(req.Username, req.Tier); err != nil {
- return err
- }
- }
- return s.writeJSON(w, newSuccessResponse())
- }
- func (s *Server) handleUsersDelete(w http.ResponseWriter, r *http.Request, v *visitor) error {
- req, err := readJSONWithLimit[apiUserDeleteRequest](r.Body, jsonBodyBytesLimit, false)
- if err != nil {
- return err
- }
- u, err := s.userManager.User(req.Username)
- if errors.Is(err, user.ErrUserNotFound) {
- return errHTTPBadRequestUserNotFound
- } else if err != nil {
- return err
- } else if !u.IsUser() {
- return errHTTPUnauthorized.Wrap("can only remove regular users from API")
- }
- if err := s.userManager.RemoveUser(req.Username); err != nil {
- return err
- }
- if err := s.killUserSubscriber(u, "*"); err != nil { // FIXME super inefficient
- return err
- }
- return s.writeJSON(w, newSuccessResponse())
- }
- func (s *Server) handleAccessAllow(w http.ResponseWriter, r *http.Request, v *visitor) error {
- req, err := readJSONWithLimit[apiAccessAllowRequest](r.Body, jsonBodyBytesLimit, false)
- if err != nil {
- return err
- }
- _, err = s.userManager.User(req.Username)
- if errors.Is(err, user.ErrUserNotFound) {
- return errHTTPBadRequestUserNotFound
- } else if err != nil {
- return err
- }
- permission, err := user.ParsePermission(req.Permission)
- if err != nil {
- return errHTTPBadRequestPermissionInvalid
- }
- if err := s.userManager.AllowAccess(req.Username, req.Topic, permission); err != nil {
- return err
- }
- return s.writeJSON(w, newSuccessResponse())
- }
- func (s *Server) handleAccessReset(w http.ResponseWriter, r *http.Request, v *visitor) error {
- req, err := readJSONWithLimit[apiAccessResetRequest](r.Body, jsonBodyBytesLimit, false)
- if err != nil {
- return err
- }
- u, err := s.userManager.User(req.Username)
- if err != nil {
- return err
- }
- if err := s.userManager.ResetAccess(req.Username, req.Topic); err != nil {
- return err
- }
- if err := s.killUserSubscriber(u, req.Topic); err != nil { // This may be a pattern
- return err
- }
- return s.writeJSON(w, newSuccessResponse())
- }
- func (s *Server) killUserSubscriber(u *user.User, topicPattern string) error {
- topics, err := s.topicsFromPattern(topicPattern)
- if err != nil {
- return err
- }
- for _, t := range topics {
- t.CancelSubscriberUser(u.ID)
- }
- return nil
- }
|