Modifications to rate limiting settings. (#4091)

Этот коммит содержится в:
Christopher Speller
2016-09-26 12:56:12 -04:00
коммит произвёл Corey Hulen
родитель dff985a924
Коммит 7fcc004beb
7 изменённых файлов: 65 добавлений и 21 удалений

Просмотреть файл

@@ -33,7 +33,7 @@ func SetupEnterprise() *TestHelper {
utils.LoadConfig("config.json") utils.LoadConfig("config.json")
utils.InitTranslations(utils.Cfg.LocalizationSettings) utils.InitTranslations(utils.Cfg.LocalizationSettings)
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50 utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
utils.Cfg.RateLimitSettings.EnableRateLimiter = false *utils.Cfg.RateLimitSettings.Enable = false
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
utils.License.Features.SetDefaults() utils.License.Features.SetDefaults()
NewServer() NewServer()
@@ -55,7 +55,7 @@ func Setup() *TestHelper {
utils.LoadConfig("config.json") utils.LoadConfig("config.json")
utils.InitTranslations(utils.Cfg.LocalizationSettings) utils.InitTranslations(utils.Cfg.LocalizationSettings)
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50 utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
utils.Cfg.RateLimitSettings.EnableRateLimiter = false *utils.Cfg.RateLimitSettings.Enable = false
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
NewServer() NewServer()
StartServer() StartServer()

Просмотреть файл

@@ -4,6 +4,10 @@
package api package api
import ( import (
"net/http"
"strings"
"time"
l4g "github.com/alecthomas/log4go" l4g "github.com/alecthomas/log4go"
"github.com/braintree/manners" "github.com/braintree/manners"
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
@@ -12,9 +16,6 @@ import (
"github.com/mattermost/platform/utils" "github.com/mattermost/platform/utils"
"gopkg.in/throttled/throttled.v2" "gopkg.in/throttled/throttled.v2"
"gopkg.in/throttled/throttled.v2/store/memstore" "gopkg.in/throttled/throttled.v2/store/memstore"
"net/http"
"strings"
"time"
) )
type Server struct { type Server struct {
@@ -70,7 +71,7 @@ func StartServer() {
var handler http.Handler = &CorsWrapper{Srv.Router} var handler http.Handler = &CorsWrapper{Srv.Router}
if utils.Cfg.RateLimitSettings.EnableRateLimiter { if *utils.Cfg.RateLimitSettings.Enable {
l4g.Info(utils.T("api.server.start_server.rate.info")) l4g.Info(utils.T("api.server.start_server.rate.info"))
store, err := memstore.New(utils.Cfg.RateLimitSettings.MemoryStoreSize) store, err := memstore.New(utils.Cfg.RateLimitSettings.MemoryStoreSize)
@@ -81,7 +82,7 @@ func StartServer() {
quota := throttled.RateQuota{ quota := throttled.RateQuota{
MaxRate: throttled.PerSec(utils.Cfg.RateLimitSettings.PerSec), MaxRate: throttled.PerSec(utils.Cfg.RateLimitSettings.PerSec),
MaxBurst: 100, MaxBurst: *utils.Cfg.RateLimitSettings.MaxBurst,
} }
rateLimiter, err := throttled.NewGCRARateLimiter(store, quota) rateLimiter, err := throttled.NewGCRARateLimiter(store, quota)

Просмотреть файл

@@ -3043,6 +3043,10 @@
"id": "model.config.is_valid.email_security.app_error", "id": "model.config.is_valid.email_security.app_error",
"translation": "Invalid connection security for email settings. Must be '', 'TLS', or 'STARTTLS'" "translation": "Invalid connection security for email settings. Must be '', 'TLS', or 'STARTTLS'"
}, },
{
"id": "model.config.is_valid.max_burst.app_error",
"translation": "Max burst must be greater than zero."
},
{ {
"id": "model.config.is_valid.encrypt_sql.app_error", "id": "model.config.is_valid.encrypt_sql.app_error",
"translation": "Invalid at rest encrypt key for SQL settings. Must be 32 chars or more." "translation": "Invalid at rest encrypt key for SQL settings. Must be 32 chars or more."

Просмотреть файл

@@ -177,11 +177,12 @@ type EmailSettings struct {
} }
type RateLimitSettings struct { type RateLimitSettings struct {
EnableRateLimiter bool Enable *bool
PerSec int PerSec int
MemoryStoreSize int MaxBurst *int
VaryByRemoteAddr bool MemoryStoreSize int
VaryByHeader string VaryByRemoteAddr bool
VaryByHeader string
} }
type PrivacySettings struct { type PrivacySettings struct {
@@ -894,6 +895,16 @@ func (o *Config) SetDefaults() {
*o.NativeAppSettings.IosAppDownloadLink = "https://about.mattermost.com/mattermost-ios-app/" *o.NativeAppSettings.IosAppDownloadLink = "https://about.mattermost.com/mattermost-ios-app/"
} }
if o.RateLimitSettings.Enable == nil {
o.RateLimitSettings.Enable = new(bool)
*o.RateLimitSettings.Enable = false
}
if o.RateLimitSettings.MaxBurst == nil {
o.RateLimitSettings.MaxBurst = new(int)
*o.RateLimitSettings.MaxBurst = 100
}
o.defaultWebrtcSettings() o.defaultWebrtcSettings()
} }
@@ -1097,6 +1108,10 @@ func (o *Config) IsValid() *AppError {
return NewLocAppError("Config.IsValid", "model.config.is_valid.sitename_length.app_error", map[string]interface{}{"MaxLength": SITENAME_MAX_LENGTH}, "") return NewLocAppError("Config.IsValid", "model.config.is_valid.sitename_length.app_error", map[string]interface{}{"MaxLength": SITENAME_MAX_LENGTH}, "")
} }
if *o.RateLimitSettings.MaxBurst <= 0 {
return NewLocAppError("Config.IsValid", "model.config.is_valid.max_burst.app_error", nil, "")
}
if err := o.isValidWebrtcSettings(); err != nil { if err := o.isValidWebrtcSettings(); err != nil {
return err return err
} }

Просмотреть файл

@@ -112,7 +112,7 @@ func trackConfig() {
}) })
SendDiagnostic(TRACK_CONFIG_RATE, map[string]interface{}{ SendDiagnostic(TRACK_CONFIG_RATE, map[string]interface{}{
"enable_rate_limiter": Cfg.RateLimitSettings.EnableRateLimiter, "enable_rate_limiter": *Cfg.RateLimitSettings.Enable,
"vary_by_remote_address": Cfg.RateLimitSettings.VaryByRemoteAddr, "vary_by_remote_address": Cfg.RateLimitSettings.VaryByRemoteAddr,
}) })

Просмотреть файл

@@ -21,8 +21,9 @@ export default class RateSettings extends AdminSettings {
} }
getConfigFromState(config) { getConfigFromState(config) {
config.RateLimitSettings.EnableRateLimiter = this.state.enableRateLimiter; config.RateLimitSettings.Enable = this.state.enable;
config.RateLimitSettings.PerSec = this.parseIntNonZero(this.state.perSec); config.RateLimitSettings.PerSec = this.parseIntNonZero(this.state.perSec);
config.RateLimitSettings.MaxBurst = this.parseIntNonZero(this.state.maxBurst);
config.RateLimitSettings.MemoryStoreSize = this.parseIntNonZero(this.state.memoryStoreSize); config.RateLimitSettings.MemoryStoreSize = this.parseIntNonZero(this.state.memoryStoreSize);
config.RateLimitSettings.VaryByRemoteAddr = this.state.varyByRemoteAddr; config.RateLimitSettings.VaryByRemoteAddr = this.state.varyByRemoteAddr;
config.RateLimitSettings.VaryByHeader = this.state.varyByHeader; config.RateLimitSettings.VaryByHeader = this.state.varyByHeader;
@@ -32,8 +33,9 @@ export default class RateSettings extends AdminSettings {
getStateFromConfig(config) { getStateFromConfig(config) {
return { return {
enableRateLimiter: config.RateLimitSettings.EnableRateLimiter, enable: config.RateLimitSettings.Enable,
perSec: config.RateLimitSettings.PerSec, perSec: config.RateLimitSettings.PerSec,
maxBurst: config.RateLimitSettings.MaxBurst,
memoryStoreSize: config.RateLimitSettings.MemoryStoreSize, memoryStoreSize: config.RateLimitSettings.MemoryStoreSize,
varyByRemoteAddr: config.RateLimitSettings.VaryByRemoteAddr, varyByRemoteAddr: config.RateLimitSettings.VaryByRemoteAddr,
varyByHeader: config.RateLimitSettings.VaryByHeader varyByHeader: config.RateLimitSettings.VaryByHeader
@@ -63,7 +65,7 @@ export default class RateSettings extends AdminSettings {
</div> </div>
</div> </div>
<BooleanSetting <BooleanSetting
id='enableRateLimiter' id='enable'
label={ label={
<FormattedMessage <FormattedMessage
id='admin.rate.enableLimiterTitle' id='admin.rate.enableLimiterTitle'
@@ -76,7 +78,7 @@ export default class RateSettings extends AdminSettings {
defaultMessage='When true, APIs are throttled at rates specified below.' defaultMessage='When true, APIs are throttled at rates specified below.'
/> />
} }
value={this.state.enableRateLimiter} value={this.state.enable}
onChange={this.handleChange} onChange={this.handleChange}
/> />
<TextSetting <TextSetting
@@ -96,7 +98,26 @@ export default class RateSettings extends AdminSettings {
} }
value={this.state.perSec} value={this.state.perSec}
onChange={this.handleChange} onChange={this.handleChange}
disabled={!this.state.enableRateLimiter} disabled={!this.state.enable}
/>
<TextSetting
id='maxBurst'
label={
<FormattedMessage
id='admin.rate.maxBurst'
defaultMessage='Max Burst:'
/>
}
placeholder={Utils.localizeMessage('admin.rate.maxBurstExample', 'Ex "100"')}
helpText={
<FormattedMessage
id='admin.rate.maxBurstDescription'
defaultMessage='Maxumum number of requests allowed beyond the per second query limit.'
/>
}
value={this.state.maxBurst}
onChange={this.handleChange}
disabled={!this.state.enable}
/> />
<TextSetting <TextSetting
id='memoryStoreSize' id='memoryStoreSize'
@@ -115,7 +136,7 @@ export default class RateSettings extends AdminSettings {
} }
value={this.state.memoryStoreSize} value={this.state.memoryStoreSize}
onChange={this.handleChange} onChange={this.handleChange}
disabled={!this.state.enableRateLimiter} disabled={!this.state.enable}
/> />
<BooleanSetting <BooleanSetting
id='varyByRemoteAddr' id='varyByRemoteAddr'
@@ -133,7 +154,7 @@ export default class RateSettings extends AdminSettings {
} }
value={this.state.varyByRemoteAddr} value={this.state.varyByRemoteAddr}
onChange={this.handleChange} onChange={this.handleChange}
disabled={!this.state.enableRateLimiter} disabled={!this.state.enable}
/> />
<TextSetting <TextSetting
id='varyByHeader' id='varyByHeader'
@@ -152,7 +173,7 @@ export default class RateSettings extends AdminSettings {
} }
value={this.state.varyByHeader} value={this.state.varyByHeader}
onChange={this.handleChange} onChange={this.handleChange}
disabled={!this.state.enableRateLimiter || this.state.varyByRemoteAddr} disabled={!this.state.enable || this.state.varyByRemoteAddr}
/> />
</SettingsGroup> </SettingsGroup>
); );

Просмотреть файл

@@ -543,6 +543,9 @@
"admin.rate.remoteDescription": "When true, rate limit API access by IP address.", "admin.rate.remoteDescription": "When true, rate limit API access by IP address.",
"admin.rate.remoteTitle": "Vary rate limit by remote address: ", "admin.rate.remoteTitle": "Vary rate limit by remote address: ",
"admin.rate.title": "Rate Limit Settings", "admin.rate.title": "Rate Limit Settings",
"admin.rate.maxBurst": "Max Burst:",
"admin.rate.maxBurstExample": "Ex \"100\"",
"admin.rate.maxBurstDescription": "Maxumum number of requests allowed beyond the per second query limit.",
"admin.recycle.button": "Recycle Database Connections", "admin.recycle.button": "Recycle Database Connections",
"admin.recycle.loading": " Recycling...", "admin.recycle.loading": " Recycling...",
"admin.recycle.recycleDescription": "Deployments using multiple databases can switch from one master database to another without restarting the Mattermost server by updating \"config.json\" to the new desired configuration and using the <a href=\"../general/configuration\"><b>Configuration > Reload Configuration from Disk</b></a> feature to load the new settings while the server is running. The administrator should then use <b>Recycle Database Connections</b> feature to recycle the database connections based on the new settings.", "admin.recycle.recycleDescription": "Deployments using multiple databases can switch from one master database to another without restarting the Mattermost server by updating \"config.json\" to the new desired configuration and using the <a href=\"../general/configuration\"><b>Configuration > Reload Configuration from Disk</b></a> feature to load the new settings while the server is running. The administrator should then use <b>Recycle Database Connections</b> feature to recycle the database connections based on the new settings.",