mirror of
https://github.com/ergochat/ergo.git
synced 2025-12-08 17:07:36 +01:00
implement FAIL METADATA RATE_LIMITED
This commit is contained in:
parent
96aa018352
commit
0119bbc36f
@ -1111,6 +1111,11 @@ metadata:
|
|||||||
max-subs: 100
|
max-subs: 100
|
||||||
# how many keys can be stored per entity?
|
# how many keys can be stored per entity?
|
||||||
max-keys: 100
|
max-keys: 100
|
||||||
|
# rate limiting for client metadata updates, which are expensive to process
|
||||||
|
client-throttle:
|
||||||
|
enabled: true
|
||||||
|
duration: 2m
|
||||||
|
max-attempts: 10
|
||||||
|
|
||||||
# experimental support for mobile push notifications
|
# experimental support for mobile push notifications
|
||||||
# see the manual for potential security, privacy, and performance implications.
|
# see the manual for potential security, privacy, and performance implications.
|
||||||
|
|||||||
@ -130,6 +130,7 @@ type Client struct {
|
|||||||
pushSubscriptionsExist atomic.Uint32 // this is a cache on len(pushSubscriptions) != 0
|
pushSubscriptionsExist atomic.Uint32 // this is a cache on len(pushSubscriptions) != 0
|
||||||
pushQueue pushQueue
|
pushQueue pushQueue
|
||||||
metadata map[string]string
|
metadata map[string]string
|
||||||
|
metadataThrottle connection_limits.ThrottleDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
type saslStatus struct {
|
type saslStatus struct {
|
||||||
|
|||||||
@ -738,6 +738,7 @@ type Config struct {
|
|||||||
MaxSubs int `yaml:"max-subs"`
|
MaxSubs int `yaml:"max-subs"`
|
||||||
MaxKeys int `yaml:"max-keys"`
|
MaxKeys int `yaml:"max-keys"`
|
||||||
MaxValueBytes int `yaml:"max-value-length"`
|
MaxValueBytes int `yaml:"max-value-length"`
|
||||||
|
ClientThrottle ThrottleConfig `yaml:"client-throttle"`
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPush struct {
|
WebPush struct {
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ergochat/ergo/irc/caps"
|
"github.com/ergochat/ergo/irc/caps"
|
||||||
|
"github.com/ergochat/ergo/irc/connection_limits"
|
||||||
"github.com/ergochat/ergo/irc/languages"
|
"github.com/ergochat/ergo/irc/languages"
|
||||||
"github.com/ergochat/ergo/irc/modes"
|
"github.com/ergochat/ergo/irc/modes"
|
||||||
"github.com/ergochat/ergo/irc/utils"
|
"github.com/ergochat/ergo/irc/utils"
|
||||||
@ -1039,3 +1040,22 @@ func (client *Client) CountMetadata() int {
|
|||||||
|
|
||||||
return len(client.metadata)
|
return len(client.metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *Client) checkMetadataThrottle() (throttled bool, remainingTime time.Duration) {
|
||||||
|
config := client.server.Config()
|
||||||
|
if !config.Metadata.ClientThrottle.Enabled {
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
client.stateMutex.Lock()
|
||||||
|
defer client.stateMutex.Unlock()
|
||||||
|
|
||||||
|
// copy client.metadataThrottle locally and then back for processing
|
||||||
|
var throttle connection_limits.GenericThrottle
|
||||||
|
throttle.ThrottleDetails = client.metadataThrottle
|
||||||
|
throttle.Duration = config.Metadata.ClientThrottle.Duration
|
||||||
|
throttle.Limit = config.Metadata.ClientThrottle.MaxAttempts
|
||||||
|
throttled, remainingTime = throttle.Touch()
|
||||||
|
client.metadataThrottle = throttle.ThrottleDetails
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@ -3197,6 +3197,18 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only rate limit clients changing their own metadata:
|
||||||
|
// channel metadata updates are not any more costly than a PRIVMSG
|
||||||
|
if client == targetClient {
|
||||||
|
if throttled, remainingTime := client.checkMetadataThrottle(); throttled {
|
||||||
|
retryAfter := strconv.Itoa(int(remainingTime.Seconds()) + 1)
|
||||||
|
rb.Add(nil, server.name, "FAIL", "METADATA", "RATE_LIMITED",
|
||||||
|
target, utils.SafeErrorParam(key), retryAfter,
|
||||||
|
fmt.Sprintf(client.t("Please wait at least %v and try again"), remainingTime.Round(time.Millisecond)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(params) > 3 {
|
if len(params) > 3 {
|
||||||
value := params[3]
|
value := params[3]
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ var (
|
|||||||
errMetadataNotFound = errors.New("key not found")
|
errMetadataNotFound = errors.New("key not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
type MetadataHaver = interface {
|
type MetadataHaver interface {
|
||||||
SetMetadata(key string, value string, limit int) (updated bool, err error)
|
SetMetadata(key string, value string, limit int) (updated bool, err error)
|
||||||
GetMetadata(key string) (string, bool)
|
GetMetadata(key string) (string, bool)
|
||||||
DeleteMetadata(key string) (updated bool)
|
DeleteMetadata(key string) (updated bool)
|
||||||
|
|||||||
@ -183,12 +183,13 @@ const (
|
|||||||
RPL_MONLIST = "732"
|
RPL_MONLIST = "732"
|
||||||
RPL_ENDOFMONLIST = "733"
|
RPL_ENDOFMONLIST = "733"
|
||||||
ERR_MONLISTFULL = "734"
|
ERR_MONLISTFULL = "734"
|
||||||
RPL_KEYVALUE = "761" // metadata numerics
|
RPL_WHOISKEYVALUE = "760" // metadata numerics
|
||||||
|
RPL_KEYVALUE = "761"
|
||||||
RPL_KEYNOTSET = "766"
|
RPL_KEYNOTSET = "766"
|
||||||
RPL_METADATASUBOK = "770"
|
RPL_METADATASUBOK = "770"
|
||||||
RPL_METADATAUNSUBOK = "771"
|
RPL_METADATAUNSUBOK = "771"
|
||||||
RPL_METADATASUBS = "772"
|
RPL_METADATASUBS = "772"
|
||||||
RPL_METADATASYNCLATER = "774"
|
RPL_METADATASYNCLATER = "774" // end metadata numerics
|
||||||
RPL_LOGGEDIN = "900"
|
RPL_LOGGEDIN = "900"
|
||||||
RPL_LOGGEDOUT = "901"
|
RPL_LOGGEDOUT = "901"
|
||||||
ERR_NICKLOCKED = "902"
|
ERR_NICKLOCKED = "902"
|
||||||
|
|||||||
@ -1082,6 +1082,11 @@ metadata:
|
|||||||
max-subs: 100
|
max-subs: 100
|
||||||
# how many keys can be stored per entity?
|
# how many keys can be stored per entity?
|
||||||
max-keys: 100
|
max-keys: 100
|
||||||
|
# rate limiting for client metadata updates, which are expensive to process
|
||||||
|
client-throttle:
|
||||||
|
enabled: true
|
||||||
|
duration: 2m
|
||||||
|
max-attempts: 10
|
||||||
|
|
||||||
# experimental support for mobile push notifications
|
# experimental support for mobile push notifications
|
||||||
# see the manual for potential security, privacy, and performance implications.
|
# see the manual for potential security, privacy, and performance implications.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user