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
|
package internal
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
)
// Authenticated wrappers on top of HTTP
func (server *Server) apiAuthenticated(method string, endpoint string, opts *HTTPOptionalParams) (http.Header, []byte, error) {
// Ensure optional is not nil as we will fill it with headers
if opts == nil {
opts = &HTTPOptionalParams{}
}
url := server.Endpoints.API.V3.API + endpoint
// Ensure we have valid tokens
oauthErr := server.EnsureTokens()
if oauthErr != nil {
return nil, nil, oauthErr
}
headerKey := "Authorization"
headerValue := fmt.Sprintf("Bearer %s", server.OAuth.Token.Access)
if opts.Headers != nil {
opts.Headers.Add(headerKey, headerValue)
} else {
opts.Headers = http.Header{headerKey: {headerValue}}
}
return HTTPMethodWithOpts(method, url, opts)
}
func (server *Server) apiAuthenticatedRetry(method string, endpoint string, opts *HTTPOptionalParams) (http.Header, []byte, error) {
header, body, bodyErr := server.apiAuthenticated(method, endpoint, opts)
if bodyErr != nil {
var error *HTTPStatusError
// Only retry authenticated if we get a HTTP 401
if errors.As(bodyErr, &error) && error.Status == 401 {
server.Logger.Log(LOG_INFO, fmt.Sprintf("API: Got HTTP error %v, retrying authenticated", error))
// Tell the method that the token is expired
server.OAuth.Token.ExpiredTimestamp = GenerateTimeSeconds()
return server.apiAuthenticated(method, endpoint, opts)
}
return header, nil, bodyErr
}
return header, body, bodyErr
}
func (server *Server) APIInfo() error {
_, body, bodyErr := server.apiAuthenticatedRetry(http.MethodGet, "/info", nil)
if bodyErr != nil {
return bodyErr
}
structure := ServerProfileInfo{}
jsonErr := json.Unmarshal(body, &structure)
if jsonErr != nil {
return jsonErr
}
server.Profiles = structure
server.ProfilesRaw = string(body)
return nil
}
func (server *Server) APIConnectWireguard(profile_id string, pubkey string) (string, string, error) {
headers := http.Header{
"content-type": {"application/x-www-form-urlencoded"},
"accept": {"application/x-wireguard-profile"},
}
urlForm := url.Values{
"profile_id": {profile_id},
"public_key": {pubkey},
}
header, connectBody, connectErr := server.apiAuthenticatedRetry(http.MethodPost, "/connect", &HTTPOptionalParams{Headers: headers, Body: urlForm})
if connectErr != nil {
return "", "", connectErr
}
expires := header.Get("expires")
return string(connectBody), expires, nil
}
func (server *Server) APIConnectOpenVPN(profile_id string) (string, string, error) {
headers := http.Header{
"content-type": {"application/x-www-form-urlencoded"},
"accept": {"application/x-openvpn-profile"},
}
urlForm := url.Values{
"profile_id": {profile_id},
}
header, connectBody, connectErr := server.apiAuthenticatedRetry(http.MethodPost, "/connect", &HTTPOptionalParams{Headers: headers, Body: urlForm})
if connectErr != nil {
return "", "", connectErr
}
expires := header.Get("expires")
return string(connectBody), expires, nil
}
// This needs no further return value as it's best effort
func (server *Server) APIDisconnect() {
server.apiAuthenticatedRetry(http.MethodPost, "/disconnect", nil)
}
|