• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-server / 1897784243

30 Jun 2025 11:50AM UTC coverage: 65.64% (-0.09%) from 65.731%
1897784243

Pull #769

gitlab-ci

alfrunes
chore(deviceauth): Add missing config env key replacer

The replacer did not exist because there were no prior configuration
settings with a period or dash in the key name.

Signed-off-by: Alf-Rune Siqveland <alf.rune@northern.tech>
Pull Request #769: MEN-7744: Rate limits for authenticated requests

181 of 332 new or added lines in 9 files covered. (54.52%)

1 existing line in 1 file now uncovered.

32539 of 49572 relevant lines covered (65.64%)

1.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.82
/backend/pkg/config/ratelimits/setup.go
1
// Copyright 2025 Northern.tech AS
2
//
3
//        Licensed under the Apache License, Version 2.0 (the "License");
4
//        you may not use this file except in compliance with the License.
5
//        You may obtain a copy of the License at
6
//
7
//            http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//        Unless required by applicable law or agreed to in writing, software
10
//        distributed under the License is distributed on an "AS IS" BASIS,
11
//        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//        See the License for the specific language governing permissions and
13
//        limitations under the License.
14

15
package ratelimits
16

17
import (
18
        "fmt"
19
        "time"
20

21
        "github.com/mendersoftware/mender-server/pkg/config"
22
        "github.com/mendersoftware/mender-server/pkg/log"
23
        "github.com/mendersoftware/mender-server/pkg/rate"
24
        "github.com/mendersoftware/mender-server/pkg/redis"
25
)
26

27
func init() {
2✔
28
        config.Config.SetDefault(SettingRatelimitsDefaultInterval, "1m")
2✔
29
        config.Config.SetDefault(SettingRatelimitsDefaultQuota, "120")
2✔
30
        config.Config.SetDefault(SettingRatelimitsDefaultEventExpression,
2✔
31
                "{{with .Identity}}{{.Subject}}{{end}}")
2✔
32
}
2✔
33

34
const (
35
        SettingRatelimits                       = "ratelimits"
36
        SettingRatelimitsEnable                 = SettingRatelimits + ".enable"
37
        SettingRatelimitsDefault                = SettingRatelimits + ".default"
38
        SettingRatelimitsDefaultQuota           = SettingRatelimitsDefault + ".quota"
39
        SettingRatelimitsDefaultInterval        = SettingRatelimitsDefault + ".interval"
40
        SettingRatelimitsDefaultEventExpression = SettingRatelimitsDefault + ".event_expression"
41
        SettingRatelimitsGroups                 = SettingRatelimits + ".groups"
42
        SettingRatelimitsMatch                  = SettingRatelimits + ".match"
43
)
44

NEW
45
func LoadRatelimits(c config.Reader) (*RatelimitConfig, error) {
×
NEW
46
        if !c.GetBool(SettingRatelimitsEnable) {
×
NEW
47
                return nil, nil
×
NEW
48
        }
×
NEW
49
        ratelimitConfig := RatelimitConfig{
×
NEW
50
                DefaultGroup: RatelimitParams{
×
NEW
51
                        Quota:           int64(c.GetInt(SettingRatelimitsDefaultQuota)),
×
NEW
52
                        Interval:        config.Duration(c.GetDuration(SettingRatelimitsDefaultInterval)),
×
NEW
53
                        EventExpression: c.GetString(SettingRatelimitsDefaultEventExpression),
×
NEW
54
                },
×
NEW
55
        }
×
NEW
56
        err := config.UnmarshalSliceSetting(c,
×
NEW
57
                SettingRatelimitsGroups,
×
NEW
58
                &ratelimitConfig.RatelimitGroups,
×
NEW
59
        )
×
NEW
60
        if err != nil {
×
NEW
61
                return nil, fmt.Errorf("error loading rate limit groups: %w", err)
×
NEW
62
        }
×
63

NEW
64
        err = config.UnmarshalSliceSetting(c,
×
NEW
65
                SettingRatelimitsMatch,
×
NEW
66
                &ratelimitConfig.MatchExpressions,
×
NEW
67
        )
×
NEW
68
        if err != nil {
×
NEW
69
                return nil, fmt.Errorf("error loading rate limit match expressions: %w", err)
×
NEW
70
        }
×
NEW
71
        return &ratelimitConfig, nil
×
72
}
73

74
func SetupRedisRateLimits(
75
        redisClient redis.Client,
76
        keyPrefix string,
77
        c config.Reader,
NEW
78
) (*rate.HTTPLimiter, error) {
×
NEW
79
        if !c.GetBool(SettingRatelimitsEnable) {
×
NEW
80
                return nil, nil
×
NEW
81
        }
×
NEW
82
        lims, err := LoadRatelimits(c)
×
NEW
83
        if err != nil {
×
NEW
84
                return nil, err
×
NEW
85
        }
×
NEW
86
        log.NewEmpty().Debugf("loaded rate limit configuration: %v", lims)
×
NEW
87
        defaultPrefix := fmt.Sprintf("%s:rate:default", keyPrefix)
×
NEW
88
        defaultLimiter := redis.NewFixedWindowRateLimiter(
×
NEW
89
                redisClient, defaultPrefix,
×
NEW
90
                time.Duration(lims.DefaultGroup.Interval), lims.DefaultGroup.Quota,
×
NEW
91
        )
×
NEW
92
        mux, err := rate.NewHTTPLimiter(
×
NEW
93
                defaultLimiter,
×
NEW
94
                c.GetString(SettingRatelimitsDefaultEventExpression),
×
NEW
95
        )
×
NEW
96
        if err != nil {
×
NEW
97
                return nil, fmt.Errorf("error setting up rate limits: %w", err)
×
NEW
98
        }
×
NEW
99
        for _, group := range lims.RatelimitGroups {
×
NEW
100
                groupPrefix := fmt.Sprintf("%s:rate:g:%s", keyPrefix, group.Name)
×
NEW
101
                limiter := redis.NewFixedWindowRateLimiter(
×
NEW
102
                        redisClient, groupPrefix, time.Duration(group.Interval), group.Quota,
×
NEW
103
                )
×
NEW
104
                err = mux.AddRateLimitGroup(limiter, group.Name, group.EventExpression)
×
NEW
105
                if err != nil {
×
NEW
106
                        return nil, fmt.Errorf("error setting up rate limit group %s: %w", group.Name, err)
×
NEW
107
                }
×
108
        }
NEW
109
        for _, expr := range lims.MatchExpressions {
×
NEW
110
                err = mux.MatchHTTPPattern(expr.APIPattern, expr.GroupExpression)
×
NEW
111
                if err != nil {
×
NEW
112
                        return nil, fmt.Errorf("error setting up match patterns: %w", err)
×
NEW
113
                }
×
114
        }
NEW
115
        return mux, nil
×
116
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc