diff options
Diffstat (limited to 'internal/api.go')
| -rw-r--r-- | internal/api.go | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/internal/api.go b/internal/api.go new file mode 100644 index 0000000..718702b --- /dev/null +++ b/internal/api.go @@ -0,0 +1,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) +} |
