Introduce Reservation
This commit is contained in:
parent
1256ba0429
commit
1733323132
11 changed files with 194 additions and 109 deletions
|
@ -1308,7 +1308,7 @@ func (s *Server) runFirebaseKeepaliver() {
|
|||
if s.firebaseClient == nil {
|
||||
return
|
||||
}
|
||||
v := newVisitor(s.config, s.messageCache, netip.IPv4Unspecified(), nil) // Background process, not a real visitor, uses IP 0.0.0.0
|
||||
v := newVisitor(s.config, s.messageCache, s.userManager, netip.IPv4Unspecified(), nil) // Background process, not a real visitor, uses IP 0.0.0.0
|
||||
for {
|
||||
select {
|
||||
case <-time.After(s.config.FirebaseKeepaliveInterval):
|
||||
|
@ -1579,7 +1579,7 @@ func (s *Server) visitorFromID(visitorID string, ip netip.Addr, user *user.User)
|
|||
defer s.mu.Unlock()
|
||||
v, exists := s.visitors[visitorID]
|
||||
if !exists {
|
||||
s.visitors[visitorID] = newVisitor(s.config, s.messageCache, ip, user)
|
||||
s.visitors[visitorID] = newVisitor(s.config, s.messageCache, s.userManager, ip, user)
|
||||
return s.visitors[visitorID]
|
||||
}
|
||||
v.Keepalive()
|
||||
|
|
|
@ -94,16 +94,27 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, _ *http.Request, v *vis
|
|||
Upgradable: true,
|
||||
}
|
||||
}
|
||||
if len(v.user.Grants) > 0 {
|
||||
response.Access = make([]*apiAccountGrant, 0)
|
||||
for _, grant := range v.user.Grants {
|
||||
if grant.Owner {
|
||||
response.Access = append(response.Access, &apiAccountGrant{
|
||||
Topic: grant.TopicPattern,
|
||||
Read: grant.AllowRead,
|
||||
Write: grant.AllowWrite,
|
||||
})
|
||||
reservations, err := s.userManager.Reservations(v.user.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(reservations) > 0 {
|
||||
response.Reservations = make([]*apiAccountReservation, 0)
|
||||
for _, r := range reservations {
|
||||
var everyone string
|
||||
if r.AllowEveryoneRead && r.AllowEveryoneWrite {
|
||||
everyone = "read-write"
|
||||
} else if r.AllowEveryoneRead && !r.AllowEveryoneWrite {
|
||||
everyone = "read-only"
|
||||
} else if !r.AllowEveryoneRead && r.AllowEveryoneWrite {
|
||||
everyone = "write-only"
|
||||
} else {
|
||||
everyone = "deny-all"
|
||||
}
|
||||
response.Reservations = append(response.Reservations, &apiAccountReservation{
|
||||
Topic: r.TopicPattern,
|
||||
Everyone: everyone,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -356,9 +367,13 @@ func (s *Server) handleAccountAccessDelete(w http.ResponseWriter, r *http.Reques
|
|||
if !topicRegex.MatchString(topic) {
|
||||
return errHTTPBadRequestTopicInvalid
|
||||
}
|
||||
reservations, err := s.userManager.Reservations(v.user.Name) // FIXME replace with HasReservation
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authorized := false
|
||||
for _, grant := range v.user.Grants {
|
||||
if grant.TopicPattern == topic && grant.Owner {
|
||||
for _, r := range reservations {
|
||||
if r.TopicPattern == topic {
|
||||
authorized = true
|
||||
break
|
||||
}
|
||||
|
|
|
@ -326,7 +326,7 @@ func TestMaybeTruncateFCMMessage_NotTooLong(t *testing.T) {
|
|||
func TestToFirebaseSender_Abuse(t *testing.T) {
|
||||
sender := &testFirebaseSender{allowed: 2}
|
||||
client := newFirebaseClient(sender, &testAuther{})
|
||||
visitor := newVisitor(newTestConfig(t), newMemTestCache(t), netip.MustParseAddr("1.2.3.4"), nil)
|
||||
visitor := newVisitor(newTestConfig(t), newMemTestCache(t), nil, netip.MustParseAddr("1.2.3.4"), nil)
|
||||
|
||||
require.Nil(t, client.Send(visitor, &message{Topic: "mytopic"}))
|
||||
require.Equal(t, 1, len(sender.Messages()))
|
||||
|
|
|
@ -72,7 +72,7 @@ func TestMatrix_WriteMatrixDiscoveryResponse(t *testing.T) {
|
|||
func TestMatrix_WriteMatrixError(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("POST", "http://ntfy.example.com/_matrix/push/v1/notify", nil)
|
||||
v := newVisitor(newTestConfig(t), nil, netip.MustParseAddr("1.2.3.4"), nil)
|
||||
v := newVisitor(newTestConfig(t), nil, nil, netip.MustParseAddr("1.2.3.4"), nil)
|
||||
require.Nil(t, writeMatrixError(w, r, v, &errMatrix{"https://ntfy.example.com/upABCDEFGHI?up=1", errHTTPBadRequestMatrixPushkeyBaseURLMismatch}))
|
||||
require.Equal(t, 200, w.Result().StatusCode)
|
||||
require.Equal(t, `{"rejected":["https://ntfy.example.com/upABCDEFGHI?up=1"]}`+"\n", w.Body.String())
|
||||
|
|
|
@ -259,22 +259,21 @@ type apiAccountStats struct {
|
|||
AttachmentTotalSizeRemaining int64 `json:"attachment_total_size_remaining"`
|
||||
}
|
||||
|
||||
type apiAccountGrant struct {
|
||||
Topic string `json:"topic"`
|
||||
Read bool `json:"read"`
|
||||
Write bool `json:"write"`
|
||||
type apiAccountReservation struct {
|
||||
Topic string `json:"topic"`
|
||||
Everyone string `json:"everyone"`
|
||||
}
|
||||
|
||||
type apiAccountResponse struct {
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Language string `json:"language,omitempty"`
|
||||
Notification *user.NotificationPrefs `json:"notification,omitempty"`
|
||||
Subscriptions []*user.Subscription `json:"subscriptions,omitempty"`
|
||||
Access []*apiAccountGrant `json:"access,omitempty"`
|
||||
Plan *apiAccountPlan `json:"plan,omitempty"`
|
||||
Limits *apiAccountLimits `json:"limits,omitempty"`
|
||||
Stats *apiAccountStats `json:"stats,omitempty"`
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Language string `json:"language,omitempty"`
|
||||
Notification *user.NotificationPrefs `json:"notification,omitempty"`
|
||||
Subscriptions []*user.Subscription `json:"subscriptions,omitempty"`
|
||||
Reservations []*apiAccountReservation `json:"reservations,omitempty"`
|
||||
Plan *apiAccountPlan `json:"plan,omitempty"`
|
||||
Limits *apiAccountLimits `json:"limits,omitempty"`
|
||||
Stats *apiAccountStats `json:"stats,omitempty"`
|
||||
}
|
||||
|
||||
type apiAccountAccessRequest struct {
|
||||
|
|
|
@ -26,6 +26,7 @@ var (
|
|||
type visitor struct {
|
||||
config *Config
|
||||
messageCache *messageCache
|
||||
userManager *user.Manager // May be nil!
|
||||
ip netip.Addr
|
||||
user *user.User
|
||||
messages int64 // Number of messages sent
|
||||
|
@ -57,7 +58,7 @@ type visitorInfo struct {
|
|||
AttachmentFileSizeLimit int64
|
||||
}
|
||||
|
||||
func newVisitor(conf *Config, messageCache *messageCache, ip netip.Addr, user *user.User) *visitor {
|
||||
func newVisitor(conf *Config, messageCache *messageCache, userManager *user.Manager, ip netip.Addr, user *user.User) *visitor {
|
||||
var requestLimiter, emailsLimiter, accountLimiter *rate.Limiter
|
||||
var messages, emails int64
|
||||
if user != nil {
|
||||
|
@ -76,6 +77,7 @@ func newVisitor(conf *Config, messageCache *messageCache, ip netip.Addr, user *u
|
|||
return &visitor{
|
||||
config: conf,
|
||||
messageCache: messageCache,
|
||||
userManager: userManager, // May be nil!
|
||||
ip: ip,
|
||||
user: user,
|
||||
messages: messages,
|
||||
|
@ -192,7 +194,7 @@ func (v *visitor) Info() (*visitorInfo, error) {
|
|||
info.AttachmentTotalSizeLimit = v.config.VisitorAttachmentTotalSizeLimit
|
||||
info.AttachmentFileSizeLimit = v.config.AttachmentFileSizeLimit
|
||||
}
|
||||
var attachmentsBytesUsed int64
|
||||
var attachmentsBytesUsed int64 // FIXME Maybe move this to endpoint?
|
||||
var err error
|
||||
if v.user != nil {
|
||||
attachmentsBytesUsed, err = v.messageCache.AttachmentBytesUsedByUser(v.user.Name)
|
||||
|
@ -203,12 +205,12 @@ func (v *visitor) Info() (*visitorInfo, error) {
|
|||
return nil, err
|
||||
}
|
||||
var topics int64
|
||||
if v.user != nil {
|
||||
for _, grant := range v.user.Grants {
|
||||
if grant.Owner {
|
||||
topics++
|
||||
}
|
||||
if v.user != nil && v.userManager != nil {
|
||||
reservations, err := v.userManager.Reservations(v.user.Name) // FIXME dup call, move this to endpoint?
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
topics = int64(len(reservations))
|
||||
}
|
||||
info.Messages = messages
|
||||
info.MessagesRemaining = zeroIfNegative(info.MessagesLimit - info.Messages)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue