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

mendersoftware / mender-server / 1943731786

23 Jul 2025 12:52PM UTC coverage: 65.476% (-0.005%) from 65.481%
1943731786

Pull #805

gitlab-ci

alfrunes
test: Fix tests making invalid assertions for request body

Signed-off-by: Alf-Rune Siqveland <alf.rune@northern.tech>
Pull Request #805: Revert to absolute API paths and group router by middleware

87 of 97 new or added lines in 3 files covered. (89.69%)

1099 existing lines in 18 files now uncovered.

32143 of 49091 relevant lines covered (65.48%)

1.39 hits per line

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

98.95
/backend/services/deviceauth/api/http/routing.go
1
// Copyright 2023 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
package http
15

16
import (
17
        "net/http"
18
        "strings"
19

20
        "github.com/gin-gonic/gin"
21

22
        "github.com/mendersoftware/mender-server/pkg/contenttype"
23
        "github.com/mendersoftware/mender-server/pkg/identity"
24
        "github.com/mendersoftware/mender-server/pkg/requestsize"
25
        "github.com/mendersoftware/mender-server/pkg/routing"
26
        dconfig "github.com/mendersoftware/mender-server/services/deviceauth/config"
27
        "github.com/mendersoftware/mender-server/services/deviceauth/devauth"
28
        "github.com/mendersoftware/mender-server/services/deviceauth/store"
29
        "github.com/mendersoftware/mender-server/services/deviceauth/utils"
30
)
31

32
const (
33
        apiUrlDevicesV1 = "/api/devices/v1/authentication"
34
        uriAuthReqs     = "/auth_requests"
35

36
        // internal API
37
        apiUrlInternalV1      = "/api/internal/v1/devauth"
38
        uriAlive              = "/alive"
39
        uriHealth             = "/health"
40
        uriTokenVerify        = "/tokens/verify"
41
        uriTenantLimit        = "/tenant/:id/limits/:name"
42
        uriTokens             = "/tokens"
43
        uriTenants            = "/tenants"
44
        uriTenantDevice       = "/tenants/:tid/devices/:did"
45
        uriTenantDeviceStatus = "/tenants/:tid/devices/:did/status"
46
        uriTenantDevices      = "/tenants/:tid/devices"
47
        uriTenantDevicesCount = "/tenants/:tid/devices/count"
48

49
        // management API v2
50
        apiUrlManagementV2       = "/api/management/v2/devauth"
51
        v2uriDevices             = "/devices"
52
        v2uriDevicesCount        = "/devices/count"
53
        v2uriDevicesSearch       = "/devices/search"
54
        v2uriDevice              = "/devices/:id"
55
        v2uriDeviceAuthSet       = "/devices/:id/auth/:aid"
56
        v2uriDeviceAuthSetStatus = "/devices/:id/auth/:aid/status"
57
        v2uriToken               = "/tokens/:id"
58
        v2uriDevicesLimit        = "/limits/:name"
59

60
        HdrAuthReqSign = "X-MEN-Signature"
61
)
62

63
type HttpOptionsGenerator func(methods []string) gin.HandlerFunc
64

65
func AllowHeaderOptionsGenerator(methods []string) gin.HandlerFunc {
3✔
66
        // return a dummy handler for now
3✔
67
        return func(c *gin.Context) {
4✔
68
                for _, m := range methods {
2✔
69
                        c.Writer.Header().Add("Allow", m)
1✔
70
                }
1✔
71
        }
72
}
73

74
func supportsMethod(method string, methods []string) bool {
3✔
75
        return utils.ContainsString(method, methods)
3✔
76
}
3✔
77

78
// Automatically add OPTIONS method support for each defined route,
79
// only if there's no OPTIONS handler for that route yet
80
func AutogenOptionsRoutes(router *gin.Engine, gen HttpOptionsGenerator) {
3✔
81

3✔
82
        routes := router.Routes()
3✔
83
        methodGroups := make(map[string][]string, len(routes))
3✔
84

3✔
85
        for _, route := range routes {
6✔
86
                if strings.HasPrefix(route.Path, "/api/internal") {
3✔
UNCOV
87
                        continue
×
88
                }
89
                methods, ok := methodGroups[route.Path]
3✔
90
                if !ok {
6✔
91
                        methods = make([]string, 0)
3✔
92
                }
3✔
93

94
                methodGroups[route.Path] = append(methods, route.Method)
3✔
95
        }
96

97
        for route, methods := range methodGroups {
6✔
98
                // skip if there's a handler for OPTIONS already
3✔
99
                if !supportsMethod(http.MethodOptions, methods) {
6✔
100
                        router.OPTIONS(route, gen(methods))
3✔
101
                }
3✔
102
        }
103

104
}
105

106
type Config struct {
107
        MaxRequestSize int64
108
}
109

110
func NewConfig() *Config {
3✔
111
        return &Config{
3✔
112
                MaxRequestSize: dconfig.SettingMaxRequestSizeDefault,
3✔
113
        }
3✔
114
}
3✔
115

116
type Option func(c *Config)
117

118
func SetMaxRequestSize(size int64) Option {
2✔
119
        return func(c *Config) {
4✔
120
                c.MaxRequestSize = size
2✔
121
        }
2✔
122
}
123

124
func NewRouter(app devauth.App, db store.DataStore, options ...Option) http.Handler {
3✔
125
        config := NewConfig()
3✔
126
        for _, option := range options {
5✔
127
                if option != nil {
4✔
128
                        option(config)
2✔
129
                }
2✔
130
        }
131

132
        router := routing.NewGinRouter()
3✔
133
        router.Use(requestsize.Middleware(config.MaxRequestSize))
3✔
134

3✔
135
        d := NewDevAuthApiHandlers(app, db)
3✔
136

3✔
137
        publicAPIs := router.Group(".")
3✔
138
        publicAPIs.Use(identity.Middleware())
3✔
139

3✔
140
        mgmtAPIV2 := publicAPIs.Group(apiUrlManagementV2)
3✔
141
        devicesAPIs := router.Group(apiUrlDevicesV1)
3✔
142

3✔
143
        // Devices API
3✔
144
        devicesAPIs.Group(".").Use(contenttype.CheckJSON()).
3✔
145
                POST(uriAuthReqs, d.SubmitAuthRequestHandler)
3✔
146

3✔
147
        // API v2
3✔
148
        mgmtAPIV2.GET(v2uriDevicesCount, d.GetDevicesCountHandler)
3✔
149
        mgmtAPIV2.GET(v2uriDevices, d.GetDevicesV2Handler)
3✔
150
        mgmtAPIV2.GET(v2uriDevice, d.GetDeviceV2Handler)
3✔
151
        mgmtAPIV2.GET(v2uriDeviceAuthSetStatus, d.GetAuthSetStatusHandler)
3✔
152
        mgmtAPIV2.GET(v2uriDevicesLimit, d.GetLimitHandler)
3✔
153
        mgmtAPIV2.DELETE(v2uriDevice, d.DecommissionDeviceHandler)
3✔
154
        mgmtAPIV2.DELETE(v2uriDeviceAuthSet, d.DeleteDeviceAuthSetHandler)
3✔
155
        mgmtAPIV2.DELETE(v2uriToken, d.DeleteTokenHandler)
3✔
156
        mgmtAPIV2.Group(".").Use(contenttype.CheckJSON()).
3✔
157
                POST(v2uriDevices, d.PostDevicesV2Handler).
3✔
158
                PUT(v2uriDeviceAuthSetStatus, d.UpdateDeviceStatusHandler).
3✔
159
                POST(v2uriDevicesSearch, d.SearchDevicesV2Handler)
3✔
160

3✔
161
        // automatically add Option routes for public endpoints
3✔
162
        AutogenOptionsRoutes(router, AllowHeaderOptionsGenerator)
3✔
163

3✔
164
        intrnlAPIV1 := router.Group(apiUrlInternalV1)
3✔
165

3✔
166
        intrnlAPIV1.GET(uriAlive, d.AliveHandler)
3✔
167
        intrnlAPIV1.GET(uriHealth, d.HealthCheckHandler)
3✔
168
        intrnlAPIV1.GET(uriTokenVerify,
3✔
169
                identity.Middleware(),
3✔
170
                d.VerifyTokenHandler)
3✔
171
        intrnlAPIV1.POST(uriTokenVerify,
3✔
172
                identity.Middleware(),
3✔
173
                d.VerifyTokenHandler)
3✔
174
        intrnlAPIV1.DELETE(uriTokens, d.DeleteTokensHandler)
3✔
175
        intrnlAPIV1.PUT(uriTenantLimit, d.PutTenantLimitHandler)
3✔
176
        intrnlAPIV1.GET(uriTenantLimit, d.GetTenantLimitHandler)
3✔
177
        intrnlAPIV1.DELETE(uriTenantLimit, d.DeleteTenantLimitHandler)
3✔
178
        intrnlAPIV1.POST(uriTenants, d.ProvisionTenantHandler)
3✔
179
        intrnlAPIV1.GET(uriTenantDeviceStatus, d.GetTenantDeviceStatus)
3✔
180
        intrnlAPIV1.GET(uriTenantDevices, d.GetTenantDevicesHandler)
3✔
181
        intrnlAPIV1.GET(uriTenantDevicesCount, d.GetTenantDevicesCountHandler)
3✔
182
        intrnlAPIV1.DELETE(uriTenantDevice, d.DeleteDeviceHandler)
3✔
183

3✔
184
        return router
3✔
185
}
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

© 2026 Coveralls, Inc