-
-
Notifications
You must be signed in to change notification settings - Fork 545
/
client.go
134 lines (109 loc) · 3.31 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package joinserver
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/brocaar/lorawan/backend"
)
// Client defines the join-server client interface.
type Client interface {
JoinReq(pl backend.JoinReqPayload) (backend.JoinAnsPayload, error)
RejoinReq(pl backend.RejoinReqPayload) (backend.RejoinAnsPayload, error)
}
type client struct {
server string
httpClient *http.Client
}
// JoinReq issues a join-request.
func (c *client) JoinReq(pl backend.JoinReqPayload) (backend.JoinAnsPayload, error) {
var ans backend.JoinAnsPayload
b, err := json.Marshal(pl)
if err != nil {
return ans, errors.Wrap(err, "marshal request error")
}
resp, err := c.httpClient.Post(c.server, "application/json", bytes.NewReader(b))
if err != nil {
return ans, errors.Wrap(err, "http post error")
}
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&ans)
if err != nil {
return ans, errors.Wrap(err, "unmarshal response error")
}
if ans.Result.ResultCode != backend.Success {
return ans, fmt.Errorf("response error, code: %s, description: %s", ans.Result.ResultCode, ans.Result.Description)
}
return ans, nil
}
// RejoinReq issues a rejoin-request.
func (c *client) RejoinReq(pl backend.RejoinReqPayload) (backend.RejoinAnsPayload, error) {
var ans backend.RejoinAnsPayload
b, err := json.Marshal(pl)
if err != nil {
return ans, errors.Wrap(err, "marshal request error")
}
resp, err := c.httpClient.Post(c.server, "application/json", bytes.NewReader(b))
if err != nil {
return ans, errors.Wrap(err, "http post error")
}
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&ans)
if err != nil {
return ans, errors.Wrap(err, "unmarshal response error")
}
if ans.Result.ResultCode != backend.Success {
return ans, fmt.Errorf("response error, code: %s, description: %s", ans.Result.ResultCode, ans.Result.Description)
}
return ans, nil
}
// NewClient creates a new join-server client.
// If the caCert is set, it will configure the CA certificate to validate the
// join-server server certificate. When the tlsCert and tlsKey are set, then
// these will be configured as client-certificates for authentication.
func NewClient(server, caCert, tlsCert, tlsKey string) (Client, error) {
log.WithFields(log.Fields{
"server": server,
"ca_cert": caCert,
"tls_cert": tlsCert,
"tls_key": tlsKey,
}).Info("configuring join-server client")
if caCert == "" && tlsCert == "" && tlsKey == "" {
return &client{
server: server,
httpClient: http.DefaultClient,
}, nil
}
tlsConfig := &tls.Config{}
if caCert != "" {
rawCACert, err := ioutil.ReadFile(caCert)
if err != nil {
return nil, errors.Wrap(err, "load ca cert error")
}
caCertPool := x509.NewCertPool()
if !caCertPool.AppendCertsFromPEM(rawCACert) {
return nil, errors.New("append ca cert to pool error")
}
tlsConfig.RootCAs = caCertPool
}
if tlsCert != "" || tlsKey != "" {
cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey)
if err != nil {
return nil, errors.Wrap(err, "load x509 keypair error")
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
return &client{
httpClient: &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
},
server: server,
}, nil
}