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

mendersoftware / mender-server / 1686000914

24 Feb 2025 01:34PM UTC coverage: 76.203%. Remained the same
1686000914

Pull #416

gitlab-ci

mzedel
test: added e2e tests for webhook functionality

Ticket: MEN-7926
Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #416: MEN-7926

4 of 8 new or added lines in 2 files covered. (50.0%)

4 existing lines in 2 files now uncovered.

36860 of 48371 relevant lines covered (76.2%)

1.49 hits per line

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

97.67
/backend/services/iot-manager/client/client.go
1
// Copyright 2022 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 client
16

17
import (
18
        "bytes"
19
        "context"
20
        "crypto/hmac"
21
        "crypto/sha256"
22
        "crypto/tls"
23
        "encoding/hex"
24
        "encoding/json"
25
        "errors"
26
        "net"
27
        "net/http"
28
        "syscall"
29
        "time"
30

31
        "github.com/mendersoftware/mender-server/pkg/config"
32
        dconfig "github.com/mendersoftware/mender-server/services/iot-manager/config"
33
        inet "github.com/mendersoftware/mender-server/services/iot-manager/internal/net"
34
        "github.com/mendersoftware/mender-server/services/iot-manager/model"
35
)
36

37
const (
38
        ParamAlgorithmType = "X-Men-Algorithm"
39
        ParamSignature     = "X-Men-Signature"
40

41
        HdrKeyContentType    = "Content-Type"
42
        AlgorithmTypeHMAC256 = "MEN-HMAC-SHA256-Payload"
43
)
44

45
func New() *http.Client {
3✔
46
        return &http.Client{
3✔
47
                Transport: NewTransport(),
3✔
48
                CheckRedirect: func(req *http.Request, via []*http.Request) error {
4✔
49
                        return http.ErrUseLastResponse
1✔
50
                },
1✔
51
        }
52
}
53

54
func addrIsGlobalUnicast(network, address string, _ syscall.RawConn) error {
3✔
55
        c := config.Config
3✔
56
        if c.GetBool(dconfig.SettingDomainSkipVerify) {
3✔
NEW
UNCOV
57
                return nil
×
NEW
UNCOV
58
        }
×
59
        ipAddr, _, err := net.SplitHostPort(address)
3✔
60
        if err != nil {
4✔
61
                ipAddr = address
1✔
62
        }
1✔
63
        ip := net.ParseIP(ipAddr)
3✔
64
        if ip == nil {
4✔
65
                return &net.ParseError{
1✔
66
                        Type: "IP address",
1✔
67
                        Text: address,
1✔
68
                }
1✔
69
        } else if !inet.IsGlobalUnicast(ip) {
5✔
70
                return net.InvalidAddrError("destination address is in reserved address range")
1✔
71
        }
1✔
72
        return nil
3✔
73
}
74

75
func NewTransport() http.RoundTripper {
3✔
76
        dialer := &net.Dialer{
3✔
77
                Control: addrIsGlobalUnicast,
3✔
78
        }
3✔
79
        tlsDialer := &tls.Dialer{
3✔
80
                NetDialer: dialer,
3✔
81
        }
3✔
82
        return &http.Transport{
3✔
83
                Proxy:                 nil,
3✔
84
                DialContext:           dialer.DialContext,
3✔
85
                DialTLSContext:        tlsDialer.DialContext,
3✔
86
                ForceAttemptHTTP2:     true,
3✔
87
                MaxIdleConns:          100,
3✔
88
                IdleConnTimeout:       90 * time.Second,
3✔
89
                TLSHandshakeTimeout:   10 * time.Second,
3✔
90
                ExpectContinueTimeout: 1 * time.Second,
3✔
91
        }
3✔
92
}
3✔
93

94
// NewSignedRequest appends header X-Men-Signature with value:
95
// HMAC256(Request.Body, secret)
96
func NewSignedRequest(
97
        ctx context.Context,
98
        secret []byte,
99
        method string,
100
        url string,
101
        body []byte,
102
) (*http.Request, error) {
2✔
103
        req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(body))
2✔
104
        if err != nil {
3✔
105
                return nil, err
1✔
106
        }
1✔
107
        req.Header.Set(ParamAlgorithmType, AlgorithmTypeHMAC256)
2✔
108

2✔
109
        sign := hmac.New(sha256.New, secret)
2✔
110
        _, _ = sign.Write(body) // Writer cannot error
2✔
111

2✔
112
        req.Header.Set(ParamSignature, hex.EncodeToString(sign.Sum(nil)))
2✔
113

2✔
114
        return req, nil
2✔
115
}
116

117
func NewWebhookRequest(
118
        ctx context.Context,
119
        creds *model.Credentials,
120
        event model.WebhookEvent,
121
) (*http.Request, error) {
3✔
122
        err := creds.Validate()
3✔
123
        if err != nil {
4✔
124
                return nil, err
1✔
125
        } else if creds.Type != model.CredentialTypeHTTP {
5✔
126
                return nil, errors.New("invalid credentials for webhooks")
1✔
127
        }
1✔
128

129
        b, err := json.Marshal(event)
3✔
130
        if err != nil {
4✔
131
                return nil, err
1✔
132
        }
1✔
133
        var req *http.Request
3✔
134
        if creds.HTTP.Secret != nil {
5✔
135
                req, err = NewSignedRequest(
2✔
136
                        ctx,
2✔
137
                        []byte(*creds.HTTP.Secret),
2✔
138
                        http.MethodPost,
2✔
139
                        creds.HTTP.URL,
2✔
140
                        b,
2✔
141
                )
2✔
142
        } else {
4✔
143
                req, err = http.NewRequestWithContext(
2✔
144
                        ctx, http.MethodPost,
2✔
145
                        creds.HTTP.URL, bytes.NewReader(b),
2✔
146
                )
2✔
147
        }
2✔
148
        if err == nil {
6✔
149
                req.Header.Set(HdrKeyContentType, "application/json")
3✔
150
        }
3✔
151
        return req, err
3✔
152
}
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