diff options
| author | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-03-23 18:15:13 +0100 |
|---|---|---|
| committer | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-03-23 18:15:13 +0100 |
| commit | 40053552852cf8c27fe7658b64df001d65b0a65e (patch) | |
| tree | 6f48e819eaec926c894af6d6225ea6d8b36de657 /src | |
| parent | f1e5096b7827d82ab5b2df10080a2ad9223f2665 (diff) | |
Add getting profiles and add openvpn config support
Diffstat (limited to 'src')
| -rw-r--r-- | src/api.go | 56 | ||||
| -rw-r--r-- | src/oauth.go | 7 | ||||
| -rw-r--r-- | src/openvpn.go | 11 | ||||
| -rw-r--r-- | src/server.go | 63 | ||||
| -rw-r--r-- | src/state.go | 2 | ||||
| -rw-r--r-- | src/wireguard.go | 4 |
6 files changed, 125 insertions, 18 deletions
@@ -2,27 +2,28 @@ package eduvpn import ( "fmt" + "encoding/json" "net/http" "net/url" ) // Authenticated wrappers on top of HTTP -func (eduvpn *VPNState) apiAuthenticatedWithOpts(method string, endpoint string, opts *HTTPOptionalParams) (http.Header, []byte, error) { +func (server *Server) apiAuthenticatedWithOpts(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 := eduvpn.Server.Endpoints.API.V3.API + endpoint + url := server.Endpoints.API.V3.API + endpoint // Ensure we have non-expired tokens - oauthErr := eduvpn.EnsureTokensOAuth() + oauthErr := server.OAuth.EnsureTokens() if oauthErr != nil { return nil, nil, oauthErr } headerKey := "Authorization" - headerValue := fmt.Sprintf("Bearer %s", eduvpn.Server.OAuth.Token.Access) + headerValue := fmt.Sprintf("Bearer %s", server.OAuth.Token.Access) if opts.Headers != nil { opts.Headers.Add(headerKey, headerValue) } else { @@ -35,7 +36,26 @@ func (eduvpn *VPNState) apiAuthenticatedWithOpts(method string, endpoint string, return header, body, nil } -func (eduvpn *VPNState) APIConnectWireguard(pubkey string) (string, string, error) { +func (server *Server) APIInfo() error { + _, body, bodyErr := server.apiAuthenticatedWithOpts(http.MethodGet, "/info", nil) + if bodyErr != nil { + return bodyErr + } + structure := &ServerProfileInfo{} + jsonErr := json.Unmarshal(body, structure) + + if jsonErr != nil { + return jsonErr + } + + server.Profiles = structure + + // FIXME: Implement profile selection callback + server.Profiles.Current = 0 + 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"}, @@ -45,11 +65,29 @@ func (eduvpn *VPNState) APIConnectWireguard(pubkey string) (string, string, erro "profile_id": {"default"}, "public_key": {pubkey}, } - header, body, bodyErr := eduvpn.apiAuthenticatedWithOpts(http.MethodPost, "/connect", &HTTPOptionalParams{Headers: headers, Body: urlForm}) - if bodyErr != nil { - return "", "", bodyErr + header, connectBody, connectErr := server.apiAuthenticatedWithOpts(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": {"default"}, + } + header, connectBody, connectErr := server.apiAuthenticatedWithOpts(http.MethodPost, "/connect", &HTTPOptionalParams{Headers: headers, Body: urlForm}) + if connectErr != nil { + return "", "", connectErr } expires := header.Get("expires") - return string(body), expires, nil + return string(connectBody), expires, nil } diff --git a/src/oauth.go b/src/oauth.go index f0d5b4a..291a409 100644 --- a/src/oauth.go +++ b/src/oauth.go @@ -269,12 +269,7 @@ func (eduvpn *VPNState) FinishOAuth() error { return oauth.getTokensWithCallback() } -func (eduvpn *VPNState) EnsureTokensOAuth() error { - oauth := eduvpn.Server.OAuth - if oauth == nil { - panic("invalid oauth state") - } - +func (oauth *OAuth) EnsureTokens() error { if oauth.isTokensExpired() { return oauth.getTokensWithRefresh() } diff --git a/src/openvpn.go b/src/openvpn.go new file mode 100644 index 0000000..2cab2c4 --- /dev/null +++ b/src/openvpn.go @@ -0,0 +1,11 @@ +package eduvpn + +func (server *Server) OpenVPNGetConfig() (string, error) { + configOpenVPN, _, configErr := server.APIConnectOpenVPN("default") + + if configErr != nil { + return "", configErr + } + + return configOpenVPN, nil +} diff --git a/src/server.go b/src/server.go index 8f8706e..1dc0f88 100644 --- a/src/server.go +++ b/src/server.go @@ -1,6 +1,7 @@ package eduvpn import ( + "errors" "encoding/json" ) @@ -8,6 +9,21 @@ type Server struct { BaseURL string `json:"base_url"` Endpoints *ServerEndpoints `json:"endpoints"` OAuth *OAuth `json:"oauth"` + Profiles *ServerProfileInfo `json:"profiles"` +} + +type ServerProfile struct { + ID string `json:"profile_id"` + DisplayName string `json:"display_name"` + VPNProtoList []string `json:"vpn_proto_list"` + DefaultGateway bool `json:"default_gateway"` +} + +type ServerProfileInfo struct { + Current uint8 `json:"current_profile"` + Info struct { + ProfileList []ServerProfile `json:"profile_list"` + } `json:"info"` } type ServerEndpointList struct { @@ -58,3 +74,50 @@ func (server *Server) GetEndpoints() error { return nil } + +func (profiles *ServerProfileInfo) getCurrentProfile() (*ServerProfile, error) { + if profiles.Info.ProfileList == nil { + return nil, errors.New("No server profiles") + } + + if (int)(profiles.Current) >= len(profiles.Info.ProfileList) { + return nil, errors.New("Invalid profile") + } + return &profiles.Info.ProfileList[profiles.Current], nil +} + +func (profile *ServerProfile) supportsWireguard() bool { + for _, proto := range profile.VPNProtoList { + if proto == "wireguard" { + return true + } + } + return false +} + +func (server *Server) GetCurrentProfile() (*ServerProfile, error) { + if server.Profiles == nil { + return nil, errors.New("No server profiles found") + } + + return server.Profiles.getCurrentProfile() +} + +func (server *Server) GetConfig() (string, error) { + infoErr := server.APIInfo() + + if infoErr != nil { + return "", infoErr + } + + profile, profileErr := server.GetCurrentProfile() + + if profileErr != nil { + return "", profileErr + } + + if profile.supportsWireguard() { + return server.WireguardGetConfig() + } + return server.OpenVPNGetConfig() +} diff --git a/src/state.go b/src/state.go index cd8fa19..ab4f3fc 100644 --- a/src/state.go +++ b/src/state.go @@ -56,7 +56,7 @@ func (state *VPNState) Connect(url string) (string, error) { state.WriteConfig() } - return state.WireguardGetConfig() + return state.Server.GetConfig() } var VPNStateInstance *VPNState diff --git a/src/wireguard.go b/src/wireguard.go index 5491764..96e7547 100644 --- a/src/wireguard.go +++ b/src/wireguard.go @@ -25,7 +25,7 @@ func wireguardConfigAddKey(config string, key wgtypes.Key) string { return interface_re.ReplaceAllString(config, to_replace) } -func (eduvpn *VPNState) WireguardGetConfig() (string, error) { +func (server *Server) WireguardGetConfig() (string, error) { wireguardKey, wireguardErr := wireguardGenerateKey() if wireguardErr != nil { @@ -33,7 +33,7 @@ func (eduvpn *VPNState) WireguardGetConfig() (string, error) { } wireguardPublicKey := wireguardKey.PublicKey().String() - configWireguard, _, configErr := eduvpn.APIConnectWireguard(wireguardPublicKey) + configWireguard, _, configErr := server.APIConnectWireguard("default", wireguardPublicKey) if configErr != nil { return "", configErr |
