mirror of
https://github.com/binwiederhier/ntfy.git
synced 2025-06-12 07:33:23 +02:00
No more v.user races
This commit is contained in:
parent
e596834096
commit
92d563371c
5 changed files with 87 additions and 77 deletions
server
|
@ -19,11 +19,12 @@ const (
|
|||
)
|
||||
|
||||
func (s *Server) handleAccountCreate(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
||||
admin := v.user != nil && v.user.Role == user.RoleAdmin
|
||||
u := v.User()
|
||||
admin := u != nil && u.Role == user.RoleAdmin
|
||||
if !admin {
|
||||
if !s.config.EnableSignup {
|
||||
return errHTTPBadRequestSignupNotEnabled
|
||||
} else if v.user != nil {
|
||||
} else if u != nil {
|
||||
return errHTTPUnauthorized // Cannot create account from user context
|
||||
}
|
||||
if !v.AccountCreationAllowed() {
|
||||
|
@ -150,20 +151,21 @@ func (s *Server) handleAccountDelete(w http.ResponseWriter, r *http.Request, v *
|
|||
} else if req.Password == "" {
|
||||
return errHTTPBadRequest
|
||||
}
|
||||
if _, err := s.userManager.Authenticate(v.user.Name, req.Password); err != nil {
|
||||
u := v.User()
|
||||
if _, err := s.userManager.Authenticate(u.Name, req.Password); err != nil {
|
||||
return errHTTPBadRequestIncorrectPasswordConfirmation
|
||||
}
|
||||
if v.user.Billing.StripeSubscriptionID != "" {
|
||||
log.Info("%s Canceling billing subscription %s", logHTTPPrefix(v, r), v.user.Billing.StripeSubscriptionID)
|
||||
if _, err := s.stripe.CancelSubscription(v.user.Billing.StripeSubscriptionID); err != nil {
|
||||
if u.Billing.StripeSubscriptionID != "" {
|
||||
log.Info("%s Canceling billing subscription %s", logHTTPPrefix(v, r), u.Billing.StripeSubscriptionID)
|
||||
if _, err := s.stripe.CancelSubscription(u.Billing.StripeSubscriptionID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := s.maybeRemoveMessagesAndExcessReservations(logHTTPPrefix(v, r), v.user, 0); err != nil {
|
||||
if err := s.maybeRemoveMessagesAndExcessReservations(logHTTPPrefix(v, r), u, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("%s Marking user %s as deleted", logHTTPPrefix(v, r), v.user.Name)
|
||||
if err := s.userManager.MarkUserRemoved(v.user); err != nil {
|
||||
log.Info("%s Marking user %s as deleted", logHTTPPrefix(v, r), u.Name)
|
||||
if err := s.userManager.MarkUserRemoved(u); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.writeJSON(w, newSuccessResponse())
|
||||
|
@ -176,10 +178,11 @@ func (s *Server) handleAccountPasswordChange(w http.ResponseWriter, r *http.Requ
|
|||
} else if req.Password == "" || req.NewPassword == "" {
|
||||
return errHTTPBadRequest
|
||||
}
|
||||
if _, err := s.userManager.Authenticate(v.user.Name, req.Password); err != nil {
|
||||
u := v.User()
|
||||
if _, err := s.userManager.Authenticate(u.Name, req.Password); err != nil {
|
||||
return errHTTPBadRequestIncorrectPasswordConfirmation
|
||||
}
|
||||
if err := s.userManager.ChangePassword(v.user.Name, req.NewPassword); err != nil {
|
||||
if err := s.userManager.ChangePassword(u.Name, req.NewPassword); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.writeJSON(w, newSuccessResponse())
|
||||
|
@ -267,10 +270,11 @@ func (s *Server) handleAccountSettingsChange(w http.ResponseWriter, r *http.Requ
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.user.Prefs == nil {
|
||||
v.user.Prefs = &user.Prefs{}
|
||||
u := v.User()
|
||||
if u.Prefs == nil {
|
||||
u.Prefs = &user.Prefs{}
|
||||
}
|
||||
prefs := v.user.Prefs
|
||||
prefs := u.Prefs
|
||||
if newPrefs.Language != nil {
|
||||
prefs.Language = newPrefs.Language
|
||||
}
|
||||
|
@ -288,7 +292,7 @@ func (s *Server) handleAccountSettingsChange(w http.ResponseWriter, r *http.Requ
|
|||
prefs.Notification.MinPriority = newPrefs.Notification.MinPriority
|
||||
}
|
||||
}
|
||||
if err := s.userManager.ChangeSettings(v.user); err != nil {
|
||||
if err := s.userManager.ChangeSettings(u); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.writeJSON(w, newSuccessResponse())
|
||||
|
@ -299,11 +303,12 @@ func (s *Server) handleAccountSubscriptionAdd(w http.ResponseWriter, r *http.Req
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.user.Prefs == nil {
|
||||
v.user.Prefs = &user.Prefs{}
|
||||
u := v.User()
|
||||
if u.Prefs == nil {
|
||||
u.Prefs = &user.Prefs{}
|
||||
}
|
||||
newSubscription.ID = "" // Client cannot set ID
|
||||
for _, subscription := range v.user.Prefs.Subscriptions {
|
||||
for _, subscription := range u.Prefs.Subscriptions {
|
||||
if newSubscription.BaseURL == subscription.BaseURL && newSubscription.Topic == subscription.Topic {
|
||||
newSubscription = subscription
|
||||
break
|
||||
|
@ -311,8 +316,8 @@ func (s *Server) handleAccountSubscriptionAdd(w http.ResponseWriter, r *http.Req
|
|||
}
|
||||
if newSubscription.ID == "" {
|
||||
newSubscription.ID = util.RandomStringPrefix(subscriptionIDPrefix, subscriptionIDLength)
|
||||
v.user.Prefs.Subscriptions = append(v.user.Prefs.Subscriptions, newSubscription)
|
||||
if err := s.userManager.ChangeSettings(v.user); err != nil {
|
||||
u.Prefs.Subscriptions = append(u.Prefs.Subscriptions, newSubscription)
|
||||
if err := s.userManager.ChangeSettings(u); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -329,11 +334,12 @@ func (s *Server) handleAccountSubscriptionChange(w http.ResponseWriter, r *http.
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.user.Prefs == nil || v.user.Prefs.Subscriptions == nil {
|
||||
u := v.User()
|
||||
if u.Prefs == nil || u.Prefs.Subscriptions == nil {
|
||||
return errHTTPNotFound
|
||||
}
|
||||
var subscription *user.Subscription
|
||||
for _, sub := range v.user.Prefs.Subscriptions {
|
||||
for _, sub := range u.Prefs.Subscriptions {
|
||||
if sub.ID == subscriptionID {
|
||||
sub.DisplayName = updatedSubscription.DisplayName
|
||||
subscription = sub
|
||||
|
@ -343,7 +349,7 @@ func (s *Server) handleAccountSubscriptionChange(w http.ResponseWriter, r *http.
|
|||
if subscription == nil {
|
||||
return errHTTPNotFound
|
||||
}
|
||||
if err := s.userManager.ChangeSettings(v.user); err != nil {
|
||||
if err := s.userManager.ChangeSettings(u); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.writeJSON(w, subscription)
|
||||
|
@ -355,18 +361,19 @@ func (s *Server) handleAccountSubscriptionDelete(w http.ResponseWriter, r *http.
|
|||
return errHTTPInternalErrorInvalidPath
|
||||
}
|
||||
subscriptionID := matches[1]
|
||||
if v.user.Prefs == nil || v.user.Prefs.Subscriptions == nil {
|
||||
u := v.User()
|
||||
if u.Prefs == nil || u.Prefs.Subscriptions == nil {
|
||||
return nil
|
||||
}
|
||||
newSubscriptions := make([]*user.Subscription, 0)
|
||||
for _, subscription := range v.user.Prefs.Subscriptions {
|
||||
for _, subscription := range u.Prefs.Subscriptions {
|
||||
if subscription.ID != subscriptionID {
|
||||
newSubscriptions = append(newSubscriptions, subscription)
|
||||
}
|
||||
}
|
||||
if len(newSubscriptions) < len(v.user.Prefs.Subscriptions) {
|
||||
v.user.Prefs.Subscriptions = newSubscriptions
|
||||
if err := s.userManager.ChangeSettings(v.user); err != nil {
|
||||
if len(newSubscriptions) < len(u.Prefs.Subscriptions) {
|
||||
u.Prefs.Subscriptions = newSubscriptions
|
||||
if err := s.userManager.ChangeSettings(u); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +381,8 @@ func (s *Server) handleAccountSubscriptionDelete(w http.ResponseWriter, r *http.
|
|||
}
|
||||
|
||||
func (s *Server) handleAccountReservationAdd(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
||||
if v.user != nil && v.user.Role == user.RoleAdmin {
|
||||
u := v.User()
|
||||
if u != nil && u.Role == user.RoleAdmin {
|
||||
return errHTTPBadRequestMakesNoSenseForAdmin
|
||||
}
|
||||
req, err := readJSONWithLimit[apiAccountReservationRequest](r.Body, jsonBodyBytesLimit, false)
|
||||
|
@ -388,27 +396,27 @@ func (s *Server) handleAccountReservationAdd(w http.ResponseWriter, r *http.Requ
|
|||
if err != nil {
|
||||
return errHTTPBadRequestPermissionInvalid
|
||||
}
|
||||
if v.user.Tier == nil {
|
||||
if u.Tier == nil {
|
||||
return errHTTPUnauthorized
|
||||
}
|
||||
// CHeck if we are allowed to reserve this topic
|
||||
if err := s.userManager.CheckAllowAccess(v.user.Name, req.Topic); err != nil {
|
||||
if err := s.userManager.CheckAllowAccess(u.Name, req.Topic); err != nil {
|
||||
return errHTTPConflictTopicReserved
|
||||
}
|
||||
hasReservation, err := s.userManager.HasReservation(v.user.Name, req.Topic)
|
||||
hasReservation, err := s.userManager.HasReservation(u.Name, req.Topic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !hasReservation {
|
||||
reservations, err := s.userManager.ReservationsCount(v.user.Name)
|
||||
reservations, err := s.userManager.ReservationsCount(u.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if reservations >= v.user.Tier.ReservationLimit {
|
||||
} else if reservations >= u.Tier.ReservationLimit {
|
||||
return errHTTPTooManyRequestsLimitReservations
|
||||
}
|
||||
}
|
||||
// Actually add the reservation
|
||||
if err := s.userManager.AddReservation(v.user.Name, req.Topic, everyone); err != nil {
|
||||
if err := s.userManager.AddReservation(u.Name, req.Topic, everyone); err != nil {
|
||||
return err
|
||||
}
|
||||
// Kill existing subscribers
|
||||
|
@ -416,7 +424,7 @@ func (s *Server) handleAccountReservationAdd(w http.ResponseWriter, r *http.Requ
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.CancelSubscribers(v.user.ID)
|
||||
t.CancelSubscribers(u.ID)
|
||||
return s.writeJSON(w, newSuccessResponse())
|
||||
}
|
||||
|
||||
|
@ -429,13 +437,14 @@ func (s *Server) handleAccountReservationDelete(w http.ResponseWriter, r *http.R
|
|||
if !topicRegex.MatchString(topic) {
|
||||
return errHTTPBadRequestTopicInvalid
|
||||
}
|
||||
authorized, err := s.userManager.HasReservation(v.user.Name, topic)
|
||||
u := v.User()
|
||||
authorized, err := s.userManager.HasReservation(u.Name, topic)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !authorized {
|
||||
return errHTTPUnauthorized
|
||||
}
|
||||
if err := s.userManager.RemoveReservations(v.user.Name, topic); err != nil {
|
||||
if err := s.userManager.RemoveReservations(u.Name, topic); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.writeJSON(w, newSuccessResponse())
|
||||
|
@ -465,12 +474,23 @@ func (s *Server) maybeRemoveMessagesAndExcessReservations(logPrefix string, u *u
|
|||
return nil
|
||||
}
|
||||
|
||||
// publishSyncEventAsync kicks of a Go routine to publish a sync message to the user's sync topic
|
||||
func (s *Server) publishSyncEventAsync(v *visitor) {
|
||||
go func() {
|
||||
if err := s.publishSyncEvent(v); err != nil {
|
||||
log.Trace("%s Error publishing to user's sync topic: %s", v.String(), err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// publishSyncEvent publishes a sync message to the user's sync topic
|
||||
func (s *Server) publishSyncEvent(v *visitor) error {
|
||||
if v.user == nil || v.user.SyncTopic == "" {
|
||||
u := v.User()
|
||||
if u == nil || u.SyncTopic == "" {
|
||||
return nil
|
||||
}
|
||||
log.Trace("Publishing sync event to user %s's sync topic %s", v.user.Name, v.user.SyncTopic)
|
||||
syncTopic, err := s.topicFromID(v.user.SyncTopic)
|
||||
log.Trace("Publishing sync event to user %s's sync topic %s", u.Name, u.SyncTopic)
|
||||
syncTopic, err := s.topicFromID(u.SyncTopic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -484,15 +504,3 @@ func (s *Server) publishSyncEvent(v *visitor) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) publishSyncEventAsync(v *visitor) {
|
||||
go func() {
|
||||
u := v.User()
|
||||
if u == nil || u.SyncTopic == "" {
|
||||
return
|
||||
}
|
||||
if err := s.publishSyncEvent(v); err != nil {
|
||||
log.Trace("Error publishing to user %s's sync topic %s: %s", u.Name, u.SyncTopic, err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue